首页 > 代码库 > Spring-AOP-学习笔记(2)-AspectJ

Spring-AOP-学习笔记(2)-AspectJ

1.启用@AspectJ,需要下载aspectjweaver.jar   

<!-- 默认启用动态代理 -->
<
aop:aspectj-autoproxy/>

<!-- 启用CGliB -->
<aop:aspectj-autoproxy proxy-target-class="true"/>

2.声明一个切面(Aspect)

/** 注解的方式声明 **/
package org.xyz;
import org.aspectj.lang.annotation.Aspect;

@Aspect
@Component
public class MyAspect{

}

添加@Component注解是为了让Spring自动搜索到并进行管理,当然还需要告诉Spring搜索路径:
<context:component-scan base-package="org.xyz"/>
<!-- XML方式声明,不需要@Aspect和@Component注解 -->
<bean id="masp" class="org.xyz.MyAspect">
    <!-- 配置切面属性 -->
</bean>
<aop:config>
    <aop:aspect id="myAspect" ref="masp">
        ... ...
    </aop:aspect>
</aop:config>

3.声明一个切点(Pointcut)

  Spring AOP只支持在方法上定义连接点,所以只需考虑如何让切点匹配到目标方法,声明一个切点需要2步:一个包含名称的签名及参数(方法返回值必须为void);一个切点表达式。切点表达式使用@Pointcut注解表示。

@Pointcut("execution(* com.xyz.myapp.service..(..))")
public void anyOldTransfer(){

}

/**
 *  anyOldTransfer即为切点签名
 *  execution为切点表达式,这里表示任意返回值,service包下(包括子包)任意形参的接口实现类方法 
 */
<!-- XML方式配置 -->
<aop:config>
    <aop:aspect id="myAspect" ref="masp">
       <aop:pointcut id="anyOldTransfer" expression="execution(* com.xyz.myapp.service..(..))"/>    

    </aop:aspect>
</aop:config>

4.声明一个通知(Advice)

@Aspect
public class AspectExample(){

   @Before("execution(* com.xyz.myapp.dao..(..)")
    public void beforeTest(){
  
    }
   
    @After("execution(* com.xyz.myapp.dao..(..)")
    public void afterTest(){
  
    }

    @AfterReturning("execution(* com.xyz.myapp.dao..(..)")
    public void afterReturnTest(){
  
    }

    /** 将返回值传递给切点 */
    @AfterReturning("execution(* com.xyz.myapp.dao..(..)",returning="retVal")
    public void afterReturningTest(Object retVal){
  
    }

    @AfterThrowing("execution(* com.xyz.myapp.dao..(..)")
    public void afterThrowingTest(){
  
    }

    /** 捕捉指定异常 */
    @AfterThrowing("execution(* com.xyz.myapp.dao..(..)",throwing="ex")
    public void afterThrowingTest(DataAccessException ex){
  
    }
    
    @Around("execution(* com.xyz.myapp.dao..(..)")
    public Object aroundTest(ProceedingJoinPoint pjp) throws Throwable{
        //前处理
        Object retVal = pjp.proceed();
        //后处理
      return retVal;  
    }
}

  访问当前JoinPoint

  任何Advice类型方法都可以声明第一个形参为org.aspectj.lang.JoinPoint(Around的为ProceedingJoinPoint,JoinPoint的子类)

  JoinPoint接口提供了:getArgs()获取方法形参,getThis()获取代理对象,getTarget()获取目标对象

  将调用方法参数传递到advice

  后置的上面已经给出实例,下面看看前置的

    @Before("execution(* com.xyz.myapp.dao..(..) && args(account,..)")
    public void beforeTest(Account account){
  
    }

  自定义注解使用

    //定义注解    
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface Auditable {
        AuditCode value();
    } 

     //获取注解
    @Before("com.xyz.lib.Pointcuts.anyPublicMethod() &&    @annotation(auditable)")
    public void audit(Auditable auditable) {
        AuditCode code = auditable.value();
    // ...
    }

  Advice参数和泛型

  Spring AOP还可以处理带泛型的类和方法参数

    public interface Sample<T> {
        void sampleGenericMethod(T param);
        void sampleGenericCollectionMethod(Collection<T> param);
    }

    @Before("execution(* ..Sample+.sampleGenericMethod(*)) && args(param)")
    public void beforeSampleMethod(MyType param) {
        // Advice implementation
    }  
 
    /** 对于集合的泛型形参要用?代替,真正类型由调用者自行转换 */ 
    @Before("execution(* ..Sample+.sampleGenericCollectionMethod(*)) && args(param)")
    public void beforeSampleMethod(Collection<?> param) {
        // Advice implementation
    }    

 

Spring-AOP-学习笔记(2)-AspectJ