Spring AOP的底层核心后置处理器
要研究这个原理,首先咱要从开启 AOP 的核心说起,那就是 **@EnableAspectJAutoProxy**
注解,
1. @EnableAspectJAutoProxy的作用
翻开 @EnableAspectJAutoProxy
注解的源码,可以发现它 @Import
了一个注册器:
1.1 AspectJAutoProxyRegistrar与后置处理器
这个注册器还挺有来头,咱点进去看一眼它的文档注释,会发现它已经把核心的后置处理器给说出来了:
Registers an AnnotationAwareAspectJAutoProxyCreator against the current BeanDefinitionRegistry as appropriate based on a given @EnableAspectJAutoProxy annotation.
根据给定的 @EnableAspectJAutoProxy
注解,根据当前 BeanDefinitionRegistry
在适当的位置注册 AnnotationAwareAspectJAutoProxyCreator
。
由此可知,AOP 的核心后置处理器是 **AnnotationAwareAspectJAutoProxyCreator**
。
先把它放在一边,咱先了解一下 AspectJAutoProxyRegistrar
是在什么时机下注册 AnnotationAwareAspectJAutoProxyCreator
的。
1.2 AspectJAutoProxyRegistrar注册后置处理器的时机
由于 AspectJAutoProxyRegistrar
实现了 ImportBeanDefinitionRegistrar
接口,所以我们可以直接找到 registerBeanDefinitions
方法,去寻找注册的逻辑。
合着第一句就明示了它要注册后置处理器,也就是代理的创建器了。而这个方法也指明了它要注册的 bean 的类型就是 AnnotationAwareAspectJAutoProxyCreator
:
再往下,就是根据这个类型,构造 BeanDefinition
,并注册进 BeanDefinitionRegistry
的动作了,逻辑相对简单,小伙伴们扫一眼就可以了:
逻辑还是简单吧,经过 IOC 部分的洗礼,这些底层看起来是不是也就轻松许多了呢?
下面我们来着重研究这个核心的后置处理器,也就是代理对象的创建器 **AnnotationAwareAspectJAutoProxyCreator**
。
2. AnnotationAwareAspectJAutoProxyCreator
这么重要的 API ,javadoc 中一定有对它的描述吧,咱先来看一眼:
AspectJAwareAdvisorAutoProxyCreator subclass that processes all AspectJ annotation aspects in the current application context, as well as Spring Advisors. Any AspectJ annotated classes will automatically be recognized, and their advice applied if Spring AOP's proxy-based model is capable of applying it. This covers method execution joinpoints. If the <aop:include>
element is used, only @AspectJ beans with names matched by an include pattern will be considered as defining aspects to use for Spring auto-proxying. Processing of Spring Advisors follows the rules established in org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.
它是 AspectJAwareAdvisorAutoProxyCreator
的子类,用于处理当前 ApplicationContext 中的所有基于 AspectJ 注解的切面,以及 Spring 原生的 Advisor
。
如果 Spring AOP 基于代理的模型能够应用任何被 @AspectJ
注解标注的类,那么它们的增强方法将被自动识别。这涵盖了方法执行的切入点表达式。
如果使用 <aop:include>
元素,则只有名称与包含模式匹配的被 @AspectJ
标注的 bean 将被视为定义要用于 Spring 自动代理的方面。
Spring 中内置的 Advisor
的处理遵循 AbstractAdvisorAutoProxyCreator
中建立的规则。
拆解看来,javadoc 中解释的核心内容是,AnnotationAwareAspectJAutoProxyCreator
它兼顾 AspectJ 风格的切面声明,以及 SpringFramework 原生的 AOP 编程。
2.1 AnnotationAwareAspectJAutoProxyCreator的继承结构
借助 IDEA ,可以很清楚的看到 AnnotationAwareAspectJAutoProxyCreator
的继承结构,以及它其中的重要核心:
注意看最顶层的接口,它实现了几个重要的接口:
BeanPostProcessor
:用于在postProcessAfterInitialization
方法中生成代理对象InstantiationAwareBeanPostProcessor
:拦截 bean 的正常doCreateBean
创建流程SmartInstantiationAwareBeanPostProcessor
:提前预测 bean 的类型、暴露 bean 的引用( AOP 、循环依赖等,太过于复杂,此处不作解释)AopInfrastructureBean
:实现了该接口的 bean 永远不会被代理(防止套娃)
除此之外,咱们一定要注意到它最开始的抽象实现类是 **AbstractAutoProxyCreator**
,它也是极度重要的!咱后面的不少源码分析中都会遇到它的。
2.2 AnnotationAwareAspectJAutoProxyCreator的初始化时机
既然在 AspectJAutoProxyRegistrar
中已经把 AnnotationAwareAspectJAutoProxyCreator
的 BeanDefinition
注册到 BeanDefinitionRegistry
中了,那么接下来的后置处理器初始化部分,它一定会被创建,而这个时机我们在前面 IOC 原理部分也讲过了,咱这里回顾一下:
这里面那个超级长的方法,还有印象吧!源码咱就不贴了,主要能让小伙伴们回忆起来就好。
注意一个小细节,AnnotationAwareAspectJAutoProxyCreator
实现了 Ordered
接口,它会提前于普通 BeanPostProcessor
创建,那是不是就代表着普通的 BeanPostProcessor
也会被 AOP 代理呢?答案是肯定的,小伙伴们可以自行测试一下。
2.3 AnnotationAwareAspectJAutoProxyCreator的作用时机
那既然 ApplicationContext
的 refresh
方法中,第 6 步 registerBeanPostProcessors
方法把 AnnotationAwareAspectJAutoProxyCreator
初始化好了,接下来的 bean 就应该都会被它干预了。
2.3.1 getBean → doCreateBean
bean 的创建流程咱前面 IOC 原理部分已经学过了,从 getBean
开始,依次是 doGetBean
、createBean
、doCreateBean
,在 doCreateBean
方法中会真正的创建对象、属性赋值、依赖注入,以及初始化流程的执行。等 bean 本身的初始化流程全部执行完毕后,就该 BeanPostProcessor
的 postProcessAfterIntialization
方法了,这些咱都很熟悉。
不过,在这之前有一个小插曲,是 createBean
到 doCreateBean
这个动作中还有一个 InstantiationAwareBeanPostProcessor
的拦截初始化动作,咱需要来看一下。
2.3.2 AnnotationAwareAspectJAutoProxyCreator#postProcessBeforeInstantiation
源码不是特别长,我们可以简单的来看一下这里面发生的核心动作:
纵读下来,这里面的逻辑其实并不复杂,甚至还蛮容易理解的,这里面涉及到几个小概念咱在这里解释一下。
2.3.2.1 InfrastructureClass
这个基础类型,可能小伙伴们不大理解这玩意是个啥,咱可以点进去看看:
得了,合着它说的这些基础类型,是切面、切入点、增强器等等的对象!那一切就解释的过去了,一个切入点的对象包装怎么会被 AOP 代理呢?它是作为 AOP 底层非常重要的组成成员,它不应该参与到具体的被增强对象中。
2.3.2.2 被跳过的bean?
这个被跳过的 bean ,似乎在之前我们学习 AOP 的过程中一直没有接触过,它是什么意思呢?咱可以先进到源码中看看:
简单的用注释一标,小伙伴们也不难理解这段逻辑吧,它要看看当前对象的名称是不是有跟增强器的名称撞车的,或者说它是不是一个还没有经过任何代理的原始对象。对于一般情况而言,我们构造的 bean 根本就不可能带有 .ORIGINAL
的后缀,所以这个地方相当于判断当前创建的 bean 是否名称与增强器撞车。
这里咱简单说下增强器的概念。一个 Advisor
可以视为一个切入点 + 一个通知方法的结合体,对于 Aspect 切面类中定义的通知方法,方法体 + 方法上的通知注解就可以看做一个 Advisor
增强器。更多相关的解释,咱放到下一章再研究。
至于上面的 findCandidateAdvisors
方法,里面的逻辑有点复杂,咱也放到下一章再研究。
不过在此 Debug 的时候,可以发现 findCandidateAdvisors
方法执行完成后,获取到了 5 个增强器,也都是在 Logger
类中定义的那 5 个通知方法:
(最后一个名太长了,实际上是 afterThrowing 的通知,引用的通用切入点表达式罢了。。。)
2.3.2.3 TargetSource?
这个概念咱之前在 IOC 部分没有见到过,当然它也不是 IOC 的东西。。。这个概念咱也是放到下一章再解释吧,这里咱可以先简单说一下,AOP 的代理其实不是代理的目标对象本身,而是目标对象包装后的 **TargetSource**
对象。至于为什么它会这么做,咱下一章也会展开解释的。
2.3.3 AnnotationAwareAspectJAutoProxyCreator#postProcessAfterInitialization
前面的拦截判断结束后,AnnotationAwareAspectJAutoProxyCreator
再发挥作用就要等到最后一步的 postProcessAfterInitialization
方法了,这里面就是真正的生成代理对象。方法的实现很简单,咱跳转进来看一下:
小小的前戏后,最关键的动作是中间的 wrapIfNecessary
方法。
这个动作从方法名上就可以很容易的理解了,如果有必要的话,给这个对象包装生成代理对象。下面进入到源码的部分:
所以由此可见,创建代理对象的核心动作其实就三个步骤:
判断决定是否是不会被增强的 bean
根据当前正在创建的 bean 去匹配增强器
如果有增强器,创建 bean 的代理对象
最后更新于