文章目录
- 1 @EnableAspectJAutoProxy注解做了什么?
- 1.1 传入配置类,创建IOC容器`
- 1.2 注册配置文件,刷新容器
- 1.3 注册bean的后置处理器
- 2 AnnotationAwareAspectJAutoProxyCreator组件的执行时机
- 3 AnnotationAwareAspectJAutoProxyCreator组件的作用
- 3.1 postProcessBeforeInstantiation()
- 3.2 postProcessAfterInitialization()
- 3.3 目标方法执行
- 3.4 拦截器链的触发过程
- 4 总结
本博客demo源码地址
https://github.com/suchahaerkang/spring-annotation.git
上一篇博客,我们测试一下spring AOP功能,知道了如果要使用spring注解驱动开发aop的功能,必须要在配置类上加上@EnableAspectJAutoProxy注解开启切面动态代理功能,我们现在就以@EnableAspectJAutoProxy注解为入口,研究这个入口到底为我们向spring容器注册了什么组件?这组件在什么时候执行和这组件给我们实现了什么功能?
1 @EnableAspectJAutoProxy注解做了什么?
点进@EnableAspectJAutoProxy注解的源码可以看到是使用@Import注解给我们向容器中注册了一个AspectJAutoProxyRegistrar的组件。不知道@Import这个注解的的作用,可以看一下我这篇博客
那么AspectJAutoProxyRegistrar这个组件又是什么呢?我们再继续点进去看看,发现这个组件实现了ImportBeanDefinitionRegistrar接口,前面我们学习到ImportBeanDefinitionRegistrar这个接口提供的registerBeanDefinitions()方法可以让我们进行手动注册一些组件到容器中去。
然后我们看一下registerBeanDefinitions()这个方法里面做了一些什么操作
我们再进一下registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法,看一下给我们注册了什么组件。
从源码中我们可以看到,给我们注册了一个叫做AnnotationAwareAspectJAutoProxyCreator的组件,然后我们看一下registerOrEscalateApcAsRequired()这个方法是怎么注册AnnotationAwareAspectJAutoProxyCreator组件的。
我们回过来看一下AnnotationAwareAspectJAutoProxyCreator这个组件到底是一个什么样的组件,我们进行源码跟踪
AnnotationAwareAspectJAutoProxyCreator
extends AspectJAwareAdvisorAutoProxyCreator
extends AbstractAdvisorAutoProxyCreator
extends AbstractAutoProxyCreator
extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor
, BeanFactoryAware
,没有必要的源码图我就不截出来看了,我们发现AnnotationAwareAspectJAutoProxyCreator这个组件最后实现了SmartInstantiationAwareBeanPostProcessor
和BeanFactoryAware
组件。SmartInstantiationAwareBeanPostProcessor 组件是个后置处理器,在bean初始化前后处理事情;BeanFactoryAware组件可以动态向bean注入BeanFactory组件
好了,上面我们是通过@EnableAspectJAutoProxy作为入口来查看源码分析了@EnableAspectJAutoProxy注解给我们向容器中注入了一个AnnotationAwareAspectJAutoProxyCreator组件并且这个组件实现了SmartInstantiationAwareBeanPostProcessor
和BeanFactoryAware
组件。下面我们通过debug模式看源码,从容器的创建开始分析AnnotationAwareAspectJAutoProxyCreator的创建过程
1.1 传入配置类,创建IOC容器`
1.2 注册配置文件,刷新容器
1.3 注册bean的后置处理器
1.3.1 从容器中获取所有已经定义好了的BeanPostProcessor
1.3.2 注册其他BeanPostProcessor组件
1.3.3 分离BeanPostProcessor组件
1.3.4 注册BeanPostProcessor组件
1.3.5 注册BeanPostProcessor组件,实际上是创建BeanPostProcessor
1.3.5.1 创建bean
1.3.5.2 给bean的属性赋值
1.3.5.3 初始化bean
1.3.5.3.1 处理Aware接口的回调方法
1.3.5.3.2 执行后置处理的postProcessBeforeInitialization()方法
1.3.5.3.3 真正初始化bean操作
1.3.5.3.4 执行后置处理的postProcessAfterInitialization()方法
1.3.6 把BeanPostProcessor注册到BeanFactory中
2 AnnotationAwareAspectJAutoProxyCreator组件的执行时机
上面了解了AnnotationAwareAspectJAutoProxyCreator组件的创建过程,那么AnnotationAwareAspectJAutoProxyCreator组件什么时候执行呢?我们通过看源码知道AnnotationAwareAspectJAutoProxyCreator
最终继承了 InstantiationAwareBeanPostProcessor
, InstantiationAwareBeanPostProcessor
后置处理器有有两个方法postProcessBeforeInstantiation()和postProcessAfterInstantiation(),这两个方法和BeanPostProcessor
后置处理的两个方法postProcessBeforeInitialization()和postProcessAfterInitialization()有点类似,我们前面的博客知道BeanPostProcessor
后置处理时机是bean的初始化前后作的处理,那么InstantiationAwareBeanPostProcessor
后置处理器又是在什么时机进行处理的呢?下面我们debug看一下源码,上面创建和注册AnnotationAwareAspectJAutoProxyCreator组件走完之后即1.3 注册bean的后置处理器
这个步骤走完之后,下面来到了finishBeanFactoryInitialization(beanFactory)这个流程
2.1 分析finishBeanFactoryInitialization(beanFactory)
进到finishBeanFactoryInitialization(beanFactory)方法中发现,其实就是遍历获取容器中所有的Bean,依次创建对象getBean(beanName)。主要流程是getBean() -> doGetBean() -> getSingleton()
2.1.1 创建单实例bean
2.1.1.1 先从缓存中取单实例bean
2.1.1.2 createBean()
我们再点进这个方法看一下
继续点进resolveBeforeInstantiation() 方法
继续点进applyBeanPostProcessorsBeforeInstantiation() 方法,里面做了什么。点进去看后发现里面在遍历
容器中的InstantiationAwareBeanPostProcessor组件,然后调用他们的postProcessBeforeInstantiation()方法
到这里我们就知道了InstantiationAwareBeanPostProcessor组件即AnnotationAwareAspectJAutoProxyCreator组件的执行时机是在创建单实例之前
2.1.1.3 doCreateBean()
doCreateBean() 这个方法就是真正的开始创建bean了,整个流程和1.3.5
的流程一样。
3 AnnotationAwareAspectJAutoProxyCreator组件的作用
上一节我们分析了在spring中创建所有的bean之前都会被AnnotationAwareAspectJAutoProxyCreator(InstantiationAwareBeanPostProcessor)组件的postProcessBeforeInstantiation()和postProcessAfterInstantiation()方法拦截,那么这两个方法到底做了什么呢?我们现在就开始拦截MathCalculator(目标类)组件和LogAspects(切面类)组件的创建
3.1 postProcessBeforeInstantiation()
每一个bean的创建都会被postProcessBeforeInstantiation()拦截,我们看一下里面做了什么?
3.1.1 判断当前bean是否在advisedBeans中
3.1.2 判断当前bean是否是基础类型
判断当前bean是否是基础类型其实就是判断当前组件的父类是否是Advice,Pointcut,Advisor,AopInfrastructureBean或是否为切面类即标注了@AspectJ注解
3.1.3 是否需要跳过
进入shouldSkip()方法
MathCalculate组件在上面的判断都是false,所以创建MathCalculate组件之前没有对其进行什么处理。然后开始创建MathCalculate组件
创建MathCalculate之后,在初始化MathCalculate组件之后会被BeanPostProcessor组件的postProcessAfterInitialization()方法拦截,然后我们就分析一下postProcessAfterInitialization()方法里面操作
3.2 postProcessAfterInitialization()
点进wrapIfNecessary()方法看看源码
3.2.1 如果bean有增强器就为bean创建一个代理类
首先进入findEligibleAdvisors()方法
然后进入findAdvisorsThatCanApply() ->findAdvisorsThatCanApply()方法
3.2.1.1 获取bean的所有增强器
3.2.1.2 对增强器排序
3.2.1.3 将需要增强的bean保存在advisedBeans列表中
3.2.1.4 将需要增强的bean创建一个代理类
进入getProxy()方法
继续进入createAopProxy()方法
继续进入createAopProxy()方法,我们可以看到有两种方法动态的创建代理类:1)通过jdk提供的api,这种方式要求被代理的类必须要实现一个接口;2)Cglib的方式。
想了解代理模式可以参考我这篇博客
最后给容器中返回当前组件MathCalculate使用cglib增强了的代理对象。然后当从容器中获取这个组件的时候,其实获取的是一个MathCalculate的代理类,当我们调用MathCalculate组件的方法时,其实是通过代理类去操控组件的方法,所以可以为组件功能增强。
3.3 目标方法执行
上面我们知道AnnotationAwareAspectJAutoProxyCreator组件作为一个BeanPostProcessor在MathCalculate初始化之后,调用其postProcessAfterInitialization()方法判断MathCalculate组件需要增强吧,如果需要增强,那么就给MathCalculate组件创建了代理对象,下面我们从容器中获取MathCalculate组件,然后执行它的方法。
下面执行MathCalculate组件的div()方法,看看里面是怎么执行那些切面的通知方法的?首先是被CglibAopProxy的intercept()拦截
我们再看一下获取拦截器链的方法
判断拦截器链是否为空作出相应处理
3.4 拦截器链的触发过程
然后将拦截器链封装到CglibMethodInvocation中,调用proceed()方法触发拦截器链,我们点击去看看里面的执行过程
下面画个图来说明一下拦截器链的触发过程
4 总结
实现Spring AOP 注解驱动的原理
首先在配置类上标注@EnableAspectJAutoProxy注解,开启AOP功能
@EnableAspectJAutoProxy 会给容器中注册一个组件 AnnotationAwareAspectJAutoProxyCreator
AnnotationAwareAspectJAutoProxyCreator是一个后置处理器
容器的创建流程:
IOC容器创建过程:
registerBeanPostProcessors() 注册后置处理器;创建AnnotationAwareAspectJAutoProxyCreator对象
finishBeanFactoryInitialization() 初始化剩下的单实例bean
创建业务逻辑组件和切面组件
AnnotationAwareAspectJAutoProxyCreator拦截组件的创建过程
组件创建完之后,判断组件是否需要增强
组件创建完之后,判断组件是否需要增强 。是:切面的通知方法,包装成增强器(Advisor);给业务逻辑组件创建一个代理对象(cglib)
执行目标方法:
代理对象执行目标方法
CglibAopProxy.intercept()
得到目标方法的拦截器链(增强器包装成拦截器MethodInterceptor)
利用拦截器的链式机制,依次进入每一个拦截器进行执行
效果:正常执行:前置通知-》目标方法-》后置通知-》返回通知;出现异常:前置通知-》目标方法-》后置通知-》异常通知