Spring AOP使用整理:使用@AspectJ风格的切面声明

要启用基于@AspectJ风格的切面声明,需要进行以下的配置:

Xml代码
  1. <!-- 启用@AspectJ风格的切面声明 -->  
  2. <aop:aspectj-autoproxy proxy-target-class="true"/>  
  3.   
  4. <!-- 通过注解定义bean。默认同时也通过注解自动注入 -->  
  5. <context:component-scan base-package="com.cjm"/>  
<!-- 启用@AspectJ风格的切面声明 -->
<aop:aspectj-autoproxy proxy-target-class="true"/>

 

<!-- 通过注解定义bean。默认同时也通过注解自动注入 -->
<context:component-scan base-package="com.cjm"/>

 

基于@AspectJ风格的切面声明的源码:

Java代码
  1. /** 
  2.  * 声明本类为一个切面 
  3.  */  
  4. @Component  
  5. @Aspect  
  6. public class MyAspectJ {  
  7.     /** 
  8.      * 声明一个切入点(包括切入点表达式和切入点签名) 
  9.      */  
  10.     @Pointcut("execution(* com.cjm.model..*.*(..))")  
  11.     public void pointcut1(){}  
  12.       
  13.     /** 
  14.      * 声明一个前置通知 
  15.      */  
  16.     @Before("pointcut1()")  
  17.     public void beforeAdvide(JoinPoint point){  
  18.         System.out.println("触发了前置通知!");  
  19.     }  
  20.       
  21.     /** 
  22.      * 声明一个后置通知 
  23.      */  
  24.     @After("pointcut1()")  
  25.     public void afterAdvie(JoinPoint point){  
  26.         System.out.println("触发了后置通知,抛出异常也会被触发!");  
  27.     }  
  28.       
  29.     /** 
  30.      * 声明一个返回后通知 
  31.      */  
  32.     @AfterReturning(pointcut="pointcut1()", returning="ret")  
  33.     public void afterReturningAdvice(JoinPoint point, Object ret){  
  34.         System.out.println("触发了返回后通知,抛出异常时不被触发,返回值为:" + ret);  
  35.     }  
  36.       
  37.     /** 
  38.      * 声明一个异常通知 
  39.      */  
  40.     @AfterThrowing(pointcut="pointcut1()", throwing="throwing")  
  41.     public void afterThrowsAdvice(JoinPoint point, RuntimeException throwing){  
  42.         System.out.println("触发了异常通知,抛出了RuntimeException异常!");  
  43.     }  
  44.       
  45.     /** 
  46.      * 声明一个环绕通知 
  47.      */  
  48.     @Around("pointcut1()")  
  49.     public Object aroundAdvice(ProceedingJoinPoint point)throws Throwable{  
  50.         System.out.println("触发了环绕通知 开始");  
  51.         Object o = point.proceed();  
  52.         System.out.println("触发了环绕通知 结束");  
  53.         return o;  
  54.     }  
  55. }  
/**
* 声明本类为一个切面
*/
@Component
@Aspect
public class MyAspectJ {
/**
* 声明一个切入点(包括切入点表达式和切入点签名)
*/
@Pointcut("execution(* com.cjm.model..*.*(..))")
public void pointcut1(){}

 

/**
* 声明一个前置通知
*/
@Before("pointcut1()")
public void beforeAdvide(JoinPoint point){
System.out.println("触发了前置通知!");
}

/**
* 声明一个后置通知
*/
@After("pointcut1()")
public void afterAdvie(JoinPoint point){
System.out.println("触发了后置通知,抛出异常也会被触发!");
}

/**
* 声明一个返回后通知
*/
@AfterReturning(pointcut="pointcut1()", returning="ret")
public void afterReturningAdvice(JoinPoint point, Object ret){
System.out.println("触发了返回后通知,抛出异常时不被触发,返回值为:" + ret);
}

/**
* 声明一个异常通知
*/
@AfterThrowing(pointcut="pointcut1()", throwing="throwing")
public void afterThrowsAdvice(JoinPoint point, RuntimeException throwing){
System.out.println("触发了异常通知,抛出了RuntimeException异常!");
}

/**
* 声明一个环绕通知
*/
@Around("pointcut1()")
public Object aroundAdvice(ProceedingJoinPoint point)throws Throwable{
System.out.println("触发了环绕通知 开始");
Object o = point.proceed();
System.out.println("触发了环绕通知 结束");
return o;
}
}

 

1、切入点表达式的格式:execution([可见性] 返回类型 [声明类型].方法名(参数) [异常])

 

2、切入点表达式通配符:
      *:匹配所有字符
      ..:一般用于匹配多个包,多个参数
      +:表示类及其子类

 

3、切入点表达式支持逻辑运算符:&&、||、!

 

4、切入点表达式关键词:
      1)execution:用于匹配子表达式。

            //匹配com.cjm.model包及其子包中所有类中的所有方法,返回类型任意,方法参数任意
            @Pointcut("execution(* com.cjm.model..*.*(..))")
            public void before(){}

 

      2)within:用于匹配连接点所在的Java类或者包。

            //匹配Person类中的所有方法
            @Pointcut("within(com.cjm.model.Person)")
            public void before(){}

 

            //匹配com.cjm包及其子包中所有类中的所有方法

            @Pointcut("within(com.cjm..*)")
            public void before(){}

 

     3) this:用于向通知方法中传入代理对象的引用。
            @Before("before() && this(proxy)")
            public void beforeAdvide(JoinPoint point, Object proxy){
                  //处理逻辑
            }

 

      4)target:用于向通知方法中传入目标对象的引用。
            @Before("before() && target(target)
            public void beforeAdvide(JoinPoint point, Object proxy){
                  //处理逻辑
            }

 

      5)args:用于将参数传入到通知方法中。
            @Before("before() && args(age,username)")
            public void beforeAdvide(JoinPoint point, int age, String username){
                  //处理逻辑
            }
 
      6)@within:用于匹配在类一级使用了参数确定的注解的类,其所有方法都将被匹配。 

            @Pointcut("@within(com.cjm.annotation.AdviceAnnotation)") - 所有被@AdviceAnnotation标注的类都将匹配
            public void before(){}

 

Java代码
  1. @Retention(RetentionPolicy.RUNTIME)  
  2. @Target({ElementType.TYPE, ElementType.METHOD})  
  3. @Documented  
  4. @Inherited  
  5. public @interface AdviceAnnotation {  
  6.   
  7. }  
  @Retention(RetentionPolicy.RUNTIME)
  @Target({ElementType.TYPE, ElementType.METHOD})
  @Documented
  @Inherited
  public @interface AdviceAnnotation {

 

  }

 

      7)@target:和@within的功能类似,但必须要指定注解接口的保留策略为RUNTIME。
            @Pointcut("@target(com.cjm.annotation.AdviceAnnotation)")
            public void before(){}

 

      8)@args:传入连接点的对象对应的Java类必须被@args指定的Annotation注解标注。
            @Before("@args(com.cjm.annotation.AdviceAnnotation)")
            public void beforeAdvide(JoinPoint point){
                  //处理逻辑
            }

 

Java代码
  1. public class Person {  
  2.     public void say(Address address){  
  3.           //处理逻辑  
  4.    }  
  5. }  
  6.   
  7.  @AdviceAnnotation  
  8.  public class Address {  
  9.      
  10.  }  
public class Person {
    public void say(Address address){
          //处理逻辑
   }
}

 

@AdviceAnnotation
public class Address {
  
}

 

  如果需要在Person类的say方法被调用时触发beforeAdvide通知,那么say方法的参数对应的Java类型Address类必须要被@AdviceAnnotation标注。

 

      9)@annotation:匹配连接点被它参数指定的Annotation注解的方法。也就是说,所有被指定注解标注的方法都将匹配。
            @Pointcut("@annotation(com.cjm.annotation.AdviceAnnotation)")
            public void before(){}

 

Java代码
  1. public class Person {  
  2.       @AdviceAnnotation  
  3.       public void say(Address address){  
  4.               //处理逻辑  
  5.     }  
  6. }  
public class Person {
      @AdviceAnnotation
      public void say(Address address){
              //处理逻辑
    }
}

 

  Person类的say方法被@AdviceAnnotation标注,所以它匹配。

 

      10)bean:通过受管Bean的名字来限定连接点所在的Bean。该关键词是Spring2.5新增的。
            @Pointcut("bean(person)")
            public void before(){}

 

            id为person的受管Bean中的所有方法都将匹配。

posted on 2010-11-24 21:07  aurawing  阅读(1639)  评论(0编辑  收藏  举报