zoukankan      html  css  js  c++  java
  • Spring aop(1)--- 寻找切面和代理对象执行流程源码分析

    1.基于注解,首先我们是通过@EnableAspectJAutoProxy()这个注解开起AOP功能,这个注解会导入AspectJAutoProxyRegistrar组件从而将AnnotationAwareAspectJAutoProxyCreator注册到bean定义中。

    2.如果容器有对应名字的bean定义,判断下是不是这个class,如果不是就改成AnnotationAwareAspectJAutoProxyCreator,如果没有就直接注册进去,注册bean定义名字叫org.springframework.aop.config.internalAutoProxyCreator。

     

     3.AnnotationAwareAspectJAutoProxyCreator看来这个类是比较重要的了,我们看一下它的继承关系图,可以看到这个类扩展了那些接口,可以看到他是BeanPostProcessor的实现类

     

     4.现在就直接来看之前在bean的实例化过程中第五点提到的org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation这个方法中是寻找切面的过程。这个方法中其实就是去调用我们相应处理器的before和after方法

     applyBeanPostProcessorsBeforeInstantiation方法中我们看到其实会去调用InstantiationAwareBeanPostProcessor这个接口的postProcessBeforeInstantiation这个方法。从我们上面类图中可以看到。我们通过@EnableAspectJAutoProxy注解注册进去的AnnotationAwareAspectJAutoProxyCreator这个正是InstantiationAwareBeanPostProcessor这个的实现类,所以在这里必然会去调用AnnotationAwareAspectJAutoProxyCreator这个实现,但是这里使用了模板方法的设计模式,实际上的方法实现在其父类AbstractAutoProxyCreator这个中的方法。

     5.AbstractAutoProxyCreator类的postProcessBeforeInstantiation方法中会去判断当前创建的类是否是基础类,是否跳过设置,正是shouldSkip这个方法将切面找出来。

    6.shouldSkip中会先调用父类的findCandidateAdvisors找事务切面,再调用自己的builder找其他的切面。

     7.BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans中会获取到所的bean,循环判断是否是切面类,也就是是否标注了@Aspect注解的,再获取切面类中的增强器,也就是@After,@Before,@AfterReturning,@AfterThrowing,@Around这几个。找到了之后再加入到缓存中。

     

     8.后面的类再进来就直接缓存里面拿出来就行了,不需要再去寻找切面了

    9.接下来就是在在bean创建好之后会通过bean的后置处理器创建代理对象返回,并且在代理对象中织入我们的增强器。

    10.现在来看AbstractAutoProxyCreator#postProcessAfterInitialization这个方法中的一些逻辑,从缓存中拿到我们之前的找到的增强器信息,并且找到匹配当前类的增强器。

     

     11.找到之后又有一步排序的操作,这个就决定了我们增强器的执行顺序。找到了增强器说明需要生成代理,没有增强器就不需要代理。

    12.如果需要创代理对象,则判断我们代理分方式@EnableAspectJAutoProxy(exposeProxy = true, proxyTargetClass = true),第一个参数是是否暴露我们代理对象,如果暴露了可以当前原型类中通过AopContext.currentProxy(),获取到代理对象。如下图两种调用方式:一种会被切,一种不会

     第二个参数是是否强制只用cglib代理。

     

     判断是何种代理

     13.可以看到返回的代理对象里面是有我们的增强器信息的。

     至此切面寻找,代理对象创建,增强器织入都完成了,接下来就是我们执行目标方法的时候,这些增强器是如何执行的。

    14.代理对象调用方法的时候会将增强器转换成拦截器链,就是根据上说到的排序顺序。

    如下图:

    15.然后创建一个反射方法的执行器执行proceed()方法 进行一个递归的调用,这里的调用有点绕,初始下标-1,然后通过前++的方式从拦截器链中获取出来执行,当最后都取完了的时候才执行目标方法,通过断点调试会发现调用顺序如下图:

     

     因为是递归的调用所以最先执行结束却是54321的顺序,这就是为什么@Before是在方法执行之前执行,可以看到@AfterThrowing是在try-catch中执行的增强器方法。@After是在一个try-finally中执行的,所以这个始终会被执行。

     

     

     这就是整个Spirng整个AOP的流程。

  • 相关阅读:
    MyBatis(六)、事务控制
    MyBatis(五)、CRUD操作与重要参数及标签
    Java学习笔记-2020学习目录
    Java学习笔记(十四) 字符串
    Java学习笔记(十三) 面向对象基础
    Java学习笔记(十二) 基础知识练习
    Java学习笔记(十一) Debug
    Java学习笔记(十) 方法
    Java学习笔记(九) 数组
    Java学习笔记(八) IDEA
  • 原文地址:https://www.cnblogs.com/nijunyang/p/12382993.html
Copyright © 2011-2022 走看看