Spring AOP源码分析

1.什么是AOP
  与OOP对比,AOP是处理一些横切性问题,这些横切性问题不会影响到主逻辑实现的,但是会散落到代 码的各个部分,难以维护。
AOP就是把这些问题和主业务逻辑分开,达到与主业务逻辑解耦的目的。

2. AOP的应用场景

  • 日志记录
  • 权限验证
  • 效率检查
  • 事务管理

问题: Aspectj 和spring aop的区别?

 切面织入的方式:    

  •   编译期织入
  •      类装载期织入
  •      动态代理织入   spring采用  动态代理的方式,在运行时织入

 区别:

  织入的时期不同:Spring Aop采用的动态织入,而Aspectj是静态织入。静态织入:指在编译时期就织入,即:编译出来的class文件,字节码就已经被织入了。动态织入又分静动两种,静则指织入过程只在第一次调用时执行;动则指根据代码动态运行的中间状态来决定如何操作,每次调用Target的时候都执行。

   从使用对象不同:spring的通知 是基于该对象是spring bean才可以;aspectj 可以在任何java对象上使用通知;

      

3. Spring AOP原理及其应用 

3.1 AOP相关概念 

  Aspect(切面): 通常是一个类(交给Spring容器管理),里面可以定义切入点和通知

  JointPoint(连接点): 程序执行过程中的一个点,如方法的执行或异常的处理

  Advice(通知): AOP在特定的切入点上执行的增强处理

  通知类型:

    •   Before advice
    •   After returning advice
    •   After throwing advice
    •   After (finally) advice
    •   Around advice

  调用顺序: Around advice>Before advice>After (finally) advice>After returning advice/After throwing advice

  Pointcut(切入点): 连接点的集合

  Target object(目标对象):被通知对象 AOP proxy:AOP框架创建的对象,代理就是目标对象的增强。

    •    JDK dynamic proxy
    •   CGLIB proxy

    思考: 初始化时织入还是获取对象时织入?   spring是在初始化的时候织入的, ioc容器初始化bean的时候,在第8次调用 spring的后置处理器的时候执行的;

  Weaving(织入):把代理逻辑加入到目标对象上的过程叫做织入.

3.2  AOP的应用

  3.2.1 Spring AOP with AspectJ pointcuts

  Schema-based AOP Support   xml配置对AOP支持的 后置处理器

  

AspectJAwareAdvisorAutoProxyCreator 
AnnotationAwareAspectJAutoProxyCreator // 配置 <aop:aspectj-autoproxy/>

  spring-aop.xml

  

<!-- 自动为spring容器中那些配置@AspectJ切面的bean创建代理,织入切面    proxy-target-class默认为false,表示使用jdk动态代理织入增强,    当配为true时,表示使用Cglib动态代理技术织入增强--> 
<aop:aspectj-autoproxy proxy-target-class="true"/> <aop:config>     <!-- 配置切面-->     <aop:aspect id="myAspect" ref="xmlAspect">        
    <!-- 配置切入点-->        
    <aop:pointcut id="businessService"                      
      expression="execution(* bat.ke.qq.com.dao.*.*(..))"/>      
    <!-- 通知-->        
    <aop:before pointcut-ref="businessService" method="before"/>        
    <aop:after pointcut-ref="businessService" method="after"/>  
  </aop:aspect> </aop:config> <bean id="xmlAspect" class="bat.ke.qq.com.config.XmlAspect"/> <bean id="foxDao" class="bat.ke.qq.com.dao.FoxDao"/>

  

public class XmlAspect {
    public void before(JoinPoint point) {        
    System.out.println("before");
  } public void after() {
    System.out.println("after");
  }
}

  

  基于注解的方式@AspectJ support  

      注解配置对AOP支持的 后置处理器:   AnnotationAwareAspectJAutoProxyCreator

  @Aspect 

@Component 
@Aspect
@Order(1) //如果有多个切面,可以通过该注解 指定加载顺序,值越小越先加载
public class AspectConfig {   @Pointcut("execution(* bat.ke.qq.com.dao.*.*(..))")   常用的是execution
  //@Pointcut("within(bat.ke.qq.com.dao.*)")  
  //@Pointcut("args(String)")  
  //@Pointcut("this(bat.ke.qq.com.dao.FoxDao)")   // jdk动态代理 extend Proxy implements IFoxDao  
  //@Pointcut("target(bat.ke.qq.com.dao.FoxDao)")  
  //@Pointcut("args(String ...) || args()")  
  //@Pointcut("execution(* bat.ke.qq.com.dao.*.*(String))")  
  //@Pointcut("@annotation(bat.ke.qq.com.anno.Yuanma)")  
  //@Pointcut("@target(bat.ke.qq.com.anno.Dao)") // 目标是注解配置  
  //@Pointcut("@within(bat.ke.qq.com.anno.Dao)")  
  //@Pointcut("@args(bat.ke.qq.com.anno.Dao)") //传参类型配置@Dao的类型  

   @Pointcut("bean(foxDao)")  
   private void pointcut() {}  


  //前置通知   @Before("pointcut()")  
  public void before(JoinPoint point) {      
    point.getThis();      
    System.out.println("before");  
  }
  
  //后置通知   @After("pointcut()")  
  public void after() {      
    System.out.println("after");  
  }
  
  @AfterReturning("pointcut()")  
  public void afterReturning() {      
    System.out.println("afterReturning");  
  }
  @AfterThrowing("pointcut()")  
  public void afterThrwoing() {      
    System.out.println("afterThrwoing");  
  }
  
  //环绕通知   @Around("pointcut()")  
  public Object around(ProceedingJoinPoint point) throws Throwable {      
    System.out.println("around");      
    Object[] args = point.getArgs();      
    for(int i=0;i<args.length;i++){
         if(args[i].getClass().equals(String.class)){           
            args[i] += "xxxx";         
          } 
    }
   return point.proceed(args);
}
        

  3.2.2  pointcut的配置分析

    execution  : 属于方法级别的配置

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?namepattern(param-pattern) throws-pattern?)
modifiers-pattern:方法的可见性,如public,protected
ret-type-pattern:方法的返回值类型,如int,void等,必须配置;
declaring-type-pattern:方法所在类的全路径名,如bat.ke.qq.com.dao.FoxDao;
name-pattern:方法名类型,如userService(),必须配置;
param-pattern:方法的参数类型,如java.lang.String,必须配置;
throws-pattern:方法抛出的异常类型,如java.lang.Exception;

  @Pointcut("execution(* bat.ke.qq.com.dao.*.*(..))")

  within  表达式的最小粒度 为 类;

@Pointcut("within(bat.ke.qq.com.dao.*)")

  this  代理对象  :使用jdk动态代理时 表达式中配置的为 接口;使用cglib动态代理时,表达式中配置的是类

// jdk动态代理 基于接口 extend Proxy implements IFoxDao 只支持接口和Proxy 
// cglib   基于继承,支持接口和目标类
@Pointcut("this(bat.ke.qq.com.dao.FoxDao)")

  target  目标对象

@Pointcut("target(bat.ke.qq.com.dao.FoxDao)")

  args :args表达式的作用是匹配指定参数类型和指定参数数量的方法,与包名和类名无关

@Pointcut("args(String)") 
@Pointcut("args(String ...) || args()")

  @target   目标对象有配置@Dao注解

@Pointcut("@target(bat.ke.qq.com.anno.Dao)")

  @args  传参类型配置@Dao的类型

@Pointcut("@args(bat.ke.qq.com.anno.Dao)") 

  @within 

  @annotation   作用方法级别,配置@Yuanma  自定义注解;只用对使用该注解的方法生效; @Transactional注解就是基于该方式

@Pointcut("@annotation(bat.ke.qq.com.anno.Yuanma)")

  bean  指定的bean

@Pointcut("bean(foxDao)") 
@Pointcut("bean(*Service)")

  注意: 上述所有的表达式可以混合使用,|| && !

 

原文地址:https://www.cnblogs.com/wl20200316/p/12792057.html