zoukankan      html  css  js  c++  java
  • AOP实现(二)Spring框架中的AOP应用

    一:传统方式(Spring1.0)

    使用Spring中的AOP API中定义的接口来定义Adivce(通知,做什么事情),并设置代理对象(配置文件中使用org.springframework.aop.framework.ProxyFactoryBean)然后在程序中使用这个代理对象。

    还有基于XML配置方式和注解方式。

    1.方法前通知,实现接口MethodBeforeAdivce

     1 package proxy;
    2
    3 import java.lang.reflect.Method;
    4
    5 import org.springframework.aop.MethodBeforeAdvice;
    6
    7 public class BeforeLogin implements MethodBeforeAdvice{
    8
    9 public void before(Method method, Object[] args, Object target)
    10 throws Throwable {
    11 // TODO Auto-generated method stub
    12 System.out.println("执行前");

    13 }
    14 }

    2.被代理对象实现的接口

    1 package proxy;
    2
    3 public interface ILogin {
    4 public void login(String username,String password);
    5 }

    3.被代理对象

     1 package proxy;
    2
    3 public class Login implements ILogin{
    4 public void login(String username, String password) {
    5 // TODO Auto-generated method stub
    6 if("tazi".equals(username)&&"123".equals(password))

    7 System.out.println("login success!");
    8 else
    9 System.out.println("login fail!");
    10
    11 }
    12 }

    4.配置文件

     1 <bean id='beforeLogin' class="proxy.BeforeLogin">
    2 </bean>
    3 <bean id='login' class="proxy.Login"></bean>
    4 <bean id='my_proxy'
    5 class="org.springframework.aop.framework.ProxyFactoryBean">

    6 <property name="proxyInterfaces">
    7 <value>proxy.ILogin</value>
    8 </property>
    9 <property name="target" ref='login'></property>
    10 <property name="interceptorNames">
    11 <list>
    12 <value>beforeLogin</value>
    13 </list>
    14 </property>
    15 </bean>

    配置文件中<property name="interceptorNames">下的<list>子标签也可以用

    <idref local='interceptorLogin2'/>

    5.测试

    1 public class Test {
    2 public static void main(String[] args) {
    3 ApplicationContext apc=new ClassPathXmlApplicationContext("applicationContext.xml");
    4 ILogin login=(ILogin)apc.getBean("my_proxy");
    5 login.login("tazi", "123");
    6 }
    7 }

    运行结果:

    执行前
    login success!

    另外还有方法后通知,实现AfterReturingAdvice.它仅在方法正常返回后被调用,若方法执行中出现异常则不被调用。它可以看到方法的返回值,却不能改变它,由返回类型是void也可以知道。

     void    afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable

    环绕型通知,实现org.aopalliance.intercept.MethodInterceptor(aop联盟定义的,便于在实现规范的aop中迁移)

    Object invoke(MethodInvocation invocation) throws Throwable 

    注意返回值是Object类型,如果希望不影响返回值,应当返回原方法的返回值,即

    Object result=invocation.proceed();
    //...
    return result;

    invocation参数中封装了原方法的信息,有getMethod(),getArguments()等方法。

    异常通知ThrowsAdvice,此接口为标签接口,可以自定义方法名称,只要是如下形式

    aferThrowing([Method],[args],[target],Throwable的子类)

    二 XML文件的方式

    1.引入AOP命名空间

     1 <?xml version="1.0" encoding="UTF-8"?>
    2 <beans
    3 xmlns="http://www.springframework.org/schema/beans"
    4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    5 xmlns:p="http://www.springframework.org/schema/p"
    6 xmlns:aop="http://www.springframework.org/schema/aop"
    7 xmlns:tx="http://www.springframework.org/schema/tx"
    8 xmlns:context="http://www.springframework.org/schema/context"
    9 xsi:schemaLocation="http://www.springframework.org/schema/beans
    10 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    11 http://www.springframework.org/schema/tx
    12 http://www.springframework.org/schema/tx/spring-tx.xsd
    13 http://www.springframework.org/schema/aop
    14 http://www.springframework.org/schema/aop/spring-aop.xsd
    15 http://www.springframework.org/schema/context
    16 http://www.springframework.org/schema/context/spring-context-2.5.xsd
    17 ">

    18 <!-- 注解方式必须加上 <aop:aspectj-autoproxy/> -->
    19 <!-- 目标对象 -->
    20 <bean id="personService" class="com.tazi.service.impl.PersonServiceBean"></bean>
    21 <!-- 横切面 -->
    22 <bean id="myInterceptor" class="com.tazi.service.MyInterceptor"></bean>
    23 <!-- 所有aop配置 -->
    24 <aop:config>
    25 <!-- 定义一个切面 -->
    26 <aop:aspect id="asp" ref="myInterceptor">
    27 <!-- 定义一个切入点,也可以作为<aop:config>的子标签 -->
    28 <aop:pointcut id="mycut" expression="execution (* com.tazi.service.impl.PersonServiceBean.*(..))"/>
    29 <!-- 前置通知,注意方法没有参数或者有一个JoinPoint类型的参数 -->
    30 <aop:before pointcut-ref="mycut" method="doAccess"/>
    31 <aop:after pointcut-ref="mycut" method="afterRet"/>
    32
    33 </aop:aspect>
    34 </aop:config>
    35 </beans>

    2.建立目标对象,自定义的切面对象(不需要实现任何接口)

     1 package com.tazi.service;
    2
    3
    4 import org.aspectj.lang.JoinPoint;
    5 import org.aspectj.lang.ProceedingJoinPoint;
    6 /*
    7 * 切面,交给Spring容器管理
    8 */

    9
    10 public class MyInterceptor {
    11
    12 /*
    13 * 前置通知
    14 */

    15 public void doAccess(){
    16 System.out.println("前置通知");
    17 }
    18
    19 public void afterRet(JoinPoint jPoint){
    20 System.out.println(jPoint.getSignature().getDeclaringTypeName());
    21 System.out.println(jPoint.getSignature().getName());
    22 System.out.println("后置通知");
    23 }
    24 public void after(){
    25 System.out.println("最终通知");
    26 }
    27 public void expHandle(Exception e) {
    28 System.out.println("抛出异常"+e);
    29 }
    30
    31 public Object huan(ProceedingJoinPoint pjp)throws Throwable{
    32 System.out.println("进入方法");
    33 Object result=pjp.proceed();
    34 System.out.println("退出方法");
    35 return result;
    36
    37 }
    38 }

    3.定义切入点,使用切入点表达式语言

    4.配置xml文件

    5.测试

    三:使用注解的方式

    在Spring的配置文件中引入aop命名空间

    xmlns:aop="http://www.springframework.org/schema/aop"

    xsi:schemaLocation中加入

    http://www.springframework.org/schema/aop 
    http://www.springframework.org/schema/aop/spring-aop.xsd

    1.打开注解方式的配置项

    注解本身不能干活,需要处理器

    使用<aop:aspectj-autoproxy/> 提供对注解的解释功能。

    2.定义切面、切入点(对业务Bean里面的哪些方法进行拦截),定义通知(拦截到方法以后所要做的工作)。

    业务接口和业务方法如下:

    package com.tazi.service.impl;

    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;

    import com.tazi.service.PersonService;

    public class PersonServiceBean implements PersonService {

    public void save(String name) {
    // TODO Auto-generated method stub
    System.out.println("save");

    throw new RuntimeException("例外");
    }

    public void update() {
    // TODO Auto-generated method stub

    }
    public static void main(String[] args) {
    ApplicationContext apc=new ClassPathXmlApplicationContext("bean.xml");
    PersonService pService=(PersonService)apc.getBean("personService");
    pService.save("tazi");
    }

    public String getPersonName(Integer id) {
    // TODO Auto-generated method stub
    System.out.println("getName");

    return "tazi";
    }

    }
    • 定义切面,使用@Aspect注解,前提是把该切面交给Spring来管理,否则注解没有任何作用。
    • 定义切入点,使用切入点表达式,形如如下形式:

    execution表示运行时,后面是[返回值]+空格+包名.类名(包名..类名则表示连同子包)+点号+方法+(..)

    注意:方法(..)表示方法的参数任意,*可以表示任意

    切入点的名称定义是以一个方法的形式。名称连括号也带上。

    • 定义通知
      根据所作的工作是方法的前后位置,有不同的通知。
     1 package com.tazi.service;
    2
    3 import org.aspectj.lang.ProceedingJoinPoint;
    4 import org.aspectj.lang.annotation.After;
    5 import org.aspectj.lang.annotation.AfterReturning;
    6 import org.aspectj.lang.annotation.AfterThrowing;
    7 import org.aspectj.lang.annotation.Around;
    8 import org.aspectj.lang.annotation.Aspect;
    9 import org.aspectj.lang.annotation.Before;
    10 import org.aspectj.lang.annotation.Pointcut;
    11 /*
    12 * 切面,交给Spring容器管理
    13 */

    14 @Aspect
    15 public class MyInterceptor {
    16 /*
    17 * 定义一个切入点
    18 */

    19 @Pointcut ("execution (* com.tazi.service.impl.PersonServiceBean.*(..))")
    20 private void anyMethod(){}
    21
    22 /*
    23 * 前置通知
    24 */

    25 @Before("anyMethod() &&args(name)")//多个条件,与参数的名字相同,既然如此,也说明应用的方法必须有一个String类型的参数
    26 public void doAccess(String name){
    27 System.out.println("前置通知"+name);
    28 }
    29
    30 @AfterReturning(pointcut="anyMethod()",returning="result")//必须是方法正常执行,若抛出异常则不可能被调用,这里加了返回值,也暗示了所拦截的方法必须带有一个String类型的返回值
    31 public void afterRet(String result){
    32 System.out.println("后置通知"+result);
    33 }
    34 @After("anyMethod()") //无论方法是否抛出异常,都会执行它,相当于在try catch的finally中执行
    35 public void after(){
    36 System.out.println("最终通知");
    37 }
    38 @AfterThrowing(pointcut="anyMethod()",throwing="e")//当抛出异常时
    39 public void expHandle(Exception e) {
    40 System.out.println("抛出异常"+e);
    41 }
    42
    43 @Around("anyMethod()") //环绕方法前后,特别适合于权限管理,如果有权限,就调用pjp.proceed()否则不调用,环绕型的通知的方法签名必须是如下形式
    44 public Object huan(ProceedingJoinPoint pjp)throws Throwable{
    45 System.out.println("进入方法");
    46 Object result=pjp.proceed();
    47 System.out.println("退出方法");
    48 return result;
    49
    50 }
    51 }

    3.最后把切面和业务Bean都在xml配置文件中配置,交给Spring容器管理。

     






     











  • 相关阅读:
    Perl正则表达式
    Apache + Perl + FastCGI安装于配置
    FastCGI高级指南
    CentOs 设置静态IP 方法
    Xtrabackup安装及使用
    在Windows环境中使用版本管理工具Git
    DBI 数据库模块剖析:Perl DBI 数据库通讯模块规范,工作原理和实例
    CentOS5.2+apache2+mod_perl2 安装方法
    Premature end of script headers 的原因
    Mysql5.5.3 主从同步不支持masterhost问题的解决办法
  • 原文地址:https://www.cnblogs.com/tazi/p/2299782.html
Copyright © 2011-2022 走看看