浅谈SpringAOP功能源码执行逻辑

Posted 默辨

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浅谈SpringAOP功能源码执行逻辑相关的知识,希望对你有一定的参考价值。

如题,该篇博文主要是对Spring初始化后AOP部分代码执行流程的分析,仅仅只是粗略的讲解整个执行流程,喜欢细的小伙伴请结合其他资料进行学习。

在看本文之前请一定要有动态代理的基础,否则后后半部分内容就像是坐牢,因为我写的比较简略。如果对动态代理不熟悉的小伙伴,可以参考我之前的博客:浅谈Cglib、Jdk以及ProxyFactory实现动态代理上的区别,两篇结合着看。


可以这么说,在明白了Cglib、Jdk动态代理以及使用ProxyFactory实现动态代理的基础上,Spring的AOP后半部分的代码,大致的执行骨架就明白了。

废话不多说,往下学吧,祝你好运!





一、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的数量以及构建好的执行链完成整个的代理逻辑,秒呀,值得好好研究学习!!!

以上是关于浅谈SpringAOP功能源码执行逻辑的主要内容,如果未能解决你的问题,请参考以下文章

Spring源码核心剖析

浅谈Spring中Bean的生命周期

一文搞懂Spring AOP源码底层原理

SpringAOP的切面执行顺序在Spring4和Spring5中有啥区别?

Spring事务源码:创建代理类

死磕Spring源码系列