概述
本期主要研究一下Spring底层是如何实现AOP的
EnableAspectJAutoProxy
都知道想要实现AOP必须先写一个@EnableAspectJAutoProxy
注解,那么我们就先来看这个注解做了什么事情
注解上直接@Import了另一个类
@Import注解在spring容器解析的时候会被ConfigurationClassPostProcessor
解析并且直接调用 registerBeanDefinitions
接口的方法,这个已经在第一章分析过了,所以Import的这个类其实就是调用了一个AopConfigUtils的方法并且把容器传进去了
最终其实就是向容器中注册了一个 AnnotationAwareAspectJAutoProxyCreator
对象
总结
我们添加的注解其实就是通过@Import的方式注入了一个其他的组件,我们在编码的过程中如果想实现什么功能也可以模仿spring的方式通过自定义注解在内部import组件来达到比较优雅的开启方式
AnnotationAwareAspectJAutoProxyCreator
我们来看这个bean在spring中都做了什么事情也就知道AOP的原理了。
初始化
因为这个Bean是一个后置处理器跟别的普通容器不一样,spring会优先创建后置处理器对象
然后就走正常的spring获取对象的流程,在实例化完spring对象之后,有一个执行生命周期函数的地方,因为AnnotationAwareAspectJAutoProxyCreator是一个BeanFactoryAware
所以执行生命周期方法
在生命周期方法内创建了一个builder和一个工厂
组件在spring容器中的作用
因为是一个后置处理器,所以在其他bean创建的时候会调用该后置处理器的方法,我们来看看。
postProcessBeforeInstantiation
在bean创建对象之前会先调用该方法,如果返回对象则spring容器不会再自己创建对象 我们可以看到在方法中进行了一个或的判断,所以只要是前面的为true则就会被加入到一个map中,前面的判断是判断正在创建的对象是不是一个切面类
inInfrastructureClass 如果类上有 @Aspect 注解就会被加入到advisedBeans这个map中,并且value是false
shouldSkip
shouldSkip的返回值并不重要,我们看方法内做了什么事情
我们来看看是如何获得增强器列表的
可以看到先调用父类的方法获取了一个list,其实是空的然后在调用自己的builder返回一个list.自然看builder的成声逻辑 通过代码可以看到,在第一次调用build的时候,aspectBeanNames是空的,所以会遍历整个spring容器中的所有对象然后找到切面类,在吧切面类中的增强方法找出来缓存住然后返回.我们来看看spring是如何判断切面类中的增强方法的. 可以看到,spring是把切面类的每一个方法都遍历过去,判断是不是切面类 上面的方法没什么好看的,就是方法传进来尝试生成一个对象,如果可以生成就返回,最后就是由 AbstractAspectJAdvisorFactory
判断能不能生成对象.
postProcessBeforeInstantiation总结
AOP在该方法中就是做了两个事情
把所有的切面类都保存在了一个 advisedBeans map里面,并且value是false
初始化了所有切面类和其增强方法的一个缓存
postProcessAfterInitallization
在spring创建完bean对象并且属性赋值结束后,调用postProcessAfterInitallization,AOP组件又做了一些事情.生命周期流程如图
方法中调用了一个 wrapIfNecessary,顾名思义如果满足条件就创建一个代理包装类,AOP的代理对象就是在这个时候创建的
我们先来看spring是如何判断一个bean有没有切面需要对其进行增强的 由于在之前的shouldSkip方法中,spring已经遍历过所有的切面类,并且缓存了他们和增强器的映射,所以拿到所有的增强器其实就是从缓存中获取 判断增强器是不是命中目标bean,则是通过 AopUtils
来实现 这个类里面就比较复杂,代码贴出来太麻烦 在返回了命中的增强器之后,如果有数据spring还会添加一个增强器到队列头部!!!
2. 知道了spring是如何判断一个类需不需要增强之后,我们来看如果有增强方法spring是如何生产代理对象的
在生成代理对象的时候还会判断是使用 JDK的动态代理还是cglib
返回了一个enhancer
我们看到在增强方法中把切面方法 advised包裹成DynamicAdvisedInterceptor
类
AOP方法调用过程
springboot2.x现在的动态代理是GCLIB的形式,所以调用的时候是走到DynamicAdvisedInterceptor
intercept方法
生成拦截器
我们先来看生成拦截器的逻辑,spring把容器中所有增强器遍历去生成拦截器 生成拦截器的逻辑是把增强器中的增强方法取出来,判断是不是MethodInterceptor
如果不是,也还有对应的Apater进行转换成拦截器 增强器获得增强方法的逻辑在ReflectiveAspectJAdvisorFactory
方法中,每个不同的切面都会生成不同的advise
Proceed
生成完拦截器之后就开始调用Proceed方法CglibMethodInvocation
是ReflectiveMethodInvocation
的子类重点逻辑都在 父类维护了一个index的索引和一个拦截器链,在之前创建切面类的时候,spring首先放入了一个写死的切面类
这个增强器在的advise是ExposeInvocationInterceptor
所以在执行proceed的时候第一个执行的就是spring提供的增强,方法中通过一个threadLocal把对象保存起来,然后继续调用proceed方法 这时候方法又回到了ReflectiveMethodInvocation类中,不同的是 index索引增加了,所以取出下一个拦截器链继续执行,AOP通过一个index和链条的方式把AOP的前置后置异常等切面串再了一起