如题,该篇博文主要是对Spring初始化后AOP部分代码执行流程的分析,仅仅只是粗略的讲解整个执行流程,喜欢细的小伙伴请结合其他资料进行学习。
在看本文之前请一定要有动态代理的基础,否则后后半部分内容就像是坐牢,因为我写的比较简略。如果对动态代理不熟悉的小伙伴,可以参考我之前的博客:浅谈Cglib、Jdk以及ProxyFactory实现动态代理上的区别,两篇结合着看。
可以这么说,在明白了Cglib、Jdk动态代理以及使用ProxyFactory实现动态代理的基础上,Spring的AOP后半部分的代码,大致的执行骨架就明白了。
废话不多说,往下学吧,祝你好运!
文章目录
- 一、AOP代码结构大纲
- 二、核心类AnnotationAwareAspectJAutoProxyCreator
- 1、AbstractAutoProxyCreator抽象类
- 2、@EnableAspectJAutoProxy
- 三、找到当前Bean的所有切入点
- 1、调用findCandidateAdvisors方法
- 2、调用父类的findCandidateAdvisors方法
- 3、调用buildAspectJAdvisors方法
- 四、找到当前Bean的符合要求的切入点
- 1、方法一直跳转,最终调用的就是canApply方法
- 2、获取匹配的切入点match
- 3、最终将符合要求的Advisor添加到集合返回
- 五、对切入点进行排序
- 六、构建所有的Advisor
- 1、创建ProxyFactory对象
- 2、添加符合Bean的所有切入点
- 3、调用具体的动态代理实现方式
- 七、Cglib动态代理执行逻辑
- 八、Jdk动态代理执行逻辑
- 1、调用getProxy方法
- 2、执行this指向类的invoke方法
- 3、构建Advisor执行链
- 4、proceed执行代理逻辑
一、AOP代码结构大纲
由于该部分代码涉及的细节过多,这里就不一一讲解,更多的是讲明白每一部分是干嘛的,以及大致是如何干的,最主要的是理清楚该部分代码的逻辑。
该部分代码的大致执行逻辑整理为了对应的执行流程图:
我将代码逻辑分为六部分:
1、方法入口
2、找到当前Bean的所有切入点
3、在当前Bean的所有切入点中找到符合要求的切入点
4、对切入点进行排序
5、将我们前面找到的所有切入点封装为Advisor数组
6、根据Advisor数组执行Cglib动态代理逻辑
7、根据Advisor数组执行Jdk动态代理逻辑
二、核心类AnnotationAwareAspectJAutoProxyCreator
1、AbstractAutoProxyCreator抽象类
正常情况下AOP功能的代码实现,是在Bean的生命周期初始化后进行调用。
初始化后会进行所有的初始化后的postProcess,此时就会调用到AbstractAutoProxyCreator类(实现了BeanPostProcessor接口)的postProcessAfterInitialization方法,即开始我们的AOP之旅。
一定一定要明白,这是Bean的生命周期,即每一个Bean都会执行这一步,所以这里的概念都是站在Bean的基础上进行讲解的!!!
即AOP的入口为AbstractAutoProxyCreator类的postProcessAfterInitialization方法
2、@EnableAspectJAutoProxy
如果你足够细心,你就会发现,Spring中的AOP是一个可插拔的功能。Spring天然是不具备AOP功能的,如果使用注解的方式进行配置,我们需要在配置类上添加一个@EnableAspectJAutoProxy注解,也就是这个注解让我们的Spring拥有了AOP的功能。
接下来让我们简单看看这个注解干了什么。
1)Import一个类(第一张图)
了解Spring容器启动流程的小伙伴就应该知道,该功能就是向Spring容器中添加一个Bean。
Import注解解析的位置在我们解析Configuration配置类的时候就会进行解析。
想了解具体解析位置的小伙伴可以参考该篇博客的第四步,即第二张图的位置:Spring解析@ComponentScan注解的执行流程
2)在解析Import注解的时候,会调用对应的registerBeanDefinitions方法,即又注册了一个Bean,这个Bean就是AnnotationAwareAspectJAutoProxyCreator.class这个类
3)为什么注入的是AnnotationAwareAspectJAutoProxyCreator这个类,但是调用AOP的方法确实AbstractAutoProxyCreator这个类呢?
因为它们是继承关系。
三、找到当前Bean的所有切入点
简单的代码直接略过,最终会进入到wrapIfNecessary方法内部。
然后执行getAdvicesAndAdvisorsForBean方法,内部分成三步,即三、四、五
再执行createProxy方法,内部也分为三步,即六、七、八
1、调用findCandidateAdvisors方法
getAdvicesAndAdvisorsForBean该方法在当前类是一个接口,然后由子类实现,然后又会调用findEligibleAdvisors方法,最终执行我们该节的目标方法findCandidateAdvisors。
2、调用父类的findCandidateAdvisors方法
最终调用findAdvisorBeans方法
该方法功能为解析我们自己新建类,然后自定义的advisor的切入点
1)根据Bean的类型去Spring容器中找我们的Bean,即如果我们编写一个类实现了这个接口Advisor接口,就会被认为是一个切入点
2)过滤掉一些和循环依赖创建有关的Advisor的Beaen
3)至此,我们自定义的Advisor就被找到了
这种就是实现了Advisor接口的Bean
3、调用buildAspectJAdvisors方法
然后执行aspectJAdvisorsBuilder.buildAspectJAdvisors()方法。这个方法很暴力,也很深
1)同样的还是根据类型,此时的类型是Object,即拿到所有的Bean。然后解析类上是否有@Aspect注解
2)将注解包装成一个AspectMetadata类,然后解析类上的一些信息
3)关键就是这个getAdvisors方法
该步为获取所有使用@Aspect类中的所有切入点
4)最终会将所有的切入点实例化为InstantiationModelAwarePointcutAdvisorImpl对象,该对象内部就含有对不同@After、@Before注解的解析
5)理解InstantiationModelAwarePointcutAdvisorImpl类对于后面的解析有帮助
这里调用的是AspectJAdvisorFactory接口的getAdvice方法,ReflectiveAspectJAdvisorFactory类又是该接口的实现,所以就调用到了ReflectiveAspectJAdvisorFactory类的getAdvice方法
四、找到当前Bean的符合要求的切入点
前面已经到了所有的切入点,现在就是要找到符合当前Bean的切入点
方法的入口是findAdvisorsThatCanApply
1、方法一直跳转,最终调用的就是canApply方法
2、获取匹配的切入点match
前面文章开头有说过,请务必了解三种动态代理的不同实现方式,这里调用match方法(后面有图),就可以理解为进行方法参数和方法名称的匹配
就在刚刚过去的第三节,第三点的,第五步,每一个切入点最终都会封装为一个InstantiationModelAwarePointcutAdvisorImpl类的对象,最终调用getAdvice方法,就会进行方法的解析。这个是不是就和使用Proxyfactory实现动态代理的长相一模一样,我们在使用Proxyfactory实现动态代理的时候,也是调用getAdvice方法获取对应的代理逻辑
3、最终将符合要求的Advisor添加到集合返回
五、对切入点进行排序
调用sortAdvisors方法,对符合当前Bean要求的Advisor进行排序,我们所熟知的Order就是在这个位置进行解析
该方法会对每一个Advisor创建一个比较器,然后排序,再依次放入集合中
六、构建所有的Advisor
如果还不明白我文章开头所说的三种实现动态代理的方式的,一定要看,不然你就看不懂后面的代码了,我在讲解该部分的时候就默认你是懂的动态代理的。
浅谈Cglib、Jdk以及ProxyFactory实现动态代理上的区别
1、创建ProxyFactory对象
2、添加符合Bean的所有切入点
其实该方法不用细看,结合ProxyFactory,你就明白它是在添加前面是已经排好序了的切入点
3、调用具体的动态代理实现方式
这里就分为Cglib和Jdk两种形式
Spring会根据我们当前Bean的基本情况进行选择,到底使用那种动态代理的实现方式。这里就出现了我们所说的使用Jdk动态代理的类必须要实现接口
七、Cglib动态代理执行逻辑
会使用Cglib动态代理是基础
1、创建Enhancer对象
2、添加对应的superClass属性
3、添加callbackFilter属性
4、添加其他属性
3、添加callbacks属性
4、调用create方法,执行代理流程
八、Jdk动态代理执行逻辑
会使用Jdk动态代理是基础
1、调用getProxy方法
2、执行this指向类的invoke方法
正常我们使用Jdk动态代理的时候,第三个位置都是传入一个InvocationHandler,此处的InvocationHandler指向的是this,即执行当前类的invoke方法
3、构建Advisor执行链
该步骤不像Cglib一样,直接添加对应的属性就能够使用,而是需要自己构建对应的Advisor执行链,可以理解为最终的执行逻辑使用了责任链设计模式
此步骤仅完成Advisor的链条构建,没有真正的去执行对应的代理逻辑
4、proceed执行代理逻辑
根据Advisor执行链条执行代理逻辑,然后调用invokeJoinpoint方法执行对应的被代理的逻辑。
个人认为该类设计的十分巧妙,利用递归和Advisor的数量以及构建好的执行链完成整个的代理逻辑,秒呀,值得好好研究学习!!!