Spring注解 AOP
AOP原理分析就是看给容器中注入了什么组件,这个组件什么时候工作,这个组件工作时候的功能
AOP的使用
实现AOP的详细步骤
-
导入aop模块
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.2.5.RELEASE</version> </dependency>
-
定义一个业务逻辑类(MathCalculator)
-
定义一个日志切面类
- 加@Aspect 注解 表明这是一个切面类
- 在对应的方法上加对应的通知注解
- 配置类
- 将切面类和业务逻辑类加入到容器中
- 开启基于注解的aop模式 @EnableAspectJAutoProxy
测试:
结果:
@EnableAspectJAutoProxy
@EnableAspectJAutoProxy注解利用AspectJAutoProxyRegistrar给容器中创建了AnnotationAwareAspectJAutoProxyCreator的beandefinition信息,IOC容器在注册后置处理器的时候就会根据这个beandefinition信息创建AnnotationAwareAspectJAutoProxyCreator的bean 实例
- @EnableAspectJAutoProxy
EnableAspectJAutoProxy上导入了AspectJAutoProxyRegistrar
AnnotationAwareAspectJAutoProxyCreator的定义信息beandefinition的注册
-
AspectJAutoProxyRegistrar
AspectJAutoProxyRegistrar实现了ImportBeanDefinitionRegistrar, 也就是自定义方式给容器中注册组件
AspectJAutoProxyRegistrar 给容器中加入的是beanDefinition ,也就是告诉容器要创建的类型是AnnotationAwareAspectJAutoProxyCreator,名字是
internalAutoProxyCreator
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); //通过这个方法注册的bean
这个函数里具体注册bean的 是registerOrEscalateApcAsRequired方法
registry.registerBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator", beanDefinition);
通过上面这一句给容器中注入了AnnotationAwareAspectJAutoProxyCreator的定义信息beanDefinition
AnnotationAwareAspectJAutoProxyCreator 的注册
AnnotationAwareAspectJAutoProxyCreator是 注解模式的AspectJ切面自动代理创建器
父类
通过追溯AnnotationAwareAspectJAutoProxyCreator 的父类 我们可以看到
它其实 实现了两个接口
- SmartInstantiationAwareBeanPostProcessor 后置处理器
- BeanFactoryAware Aware接口的实现类
AnnotationAwareAspectJAutoProxyCreator
-> AspectJAwareAdvisorAutoProxyCreator
-> AbstractAdvisorAutoProxyCreator
->AbstractAutoProxyCreator
->ProxyProcessorSupport
实现SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware
其中SmartInstantiationAwareBeanPostProcessor的父类
SmartInstantiationAwareBeanPostProcessor
->InstantiationAwareBeanPostProcessor
->BeanPostProcessor
可以看到就是后置处理器
创建ioc容器
AnnotationConfigApplicationContext:
做了三步
- 调用无参构造器
- 注册配置类
- 调用refresh() 刷新容器
refresh() :
中注册bean的后置处理器 用来拦截bean的创建
registerBeanPostProcessors 注册BeanPostProcessor
registerBeanPostProcessors 方法:
-
先获取ioc容器中已经定义了的需要创建对象的所有BeanPostProcessor
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
现在这些 BeanPostProcessor 都是BeanDefinetion 还没有创建对象
-
给容器中加入别的BeanPostProcessor
beanFactory.addBeanPostProcessor(new PostProcessorRegistrationDelegate.BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
-
将BeanPostProcessor分类 , 并注册
-
实现了PriorityOrdered接口的 priorityOrderedPostProcessors[实现这个接口的有优先级排序]
-
实现了Ordered接口的orderedPostProcessors
-
没有实现Oredered接口的nonOrderedPostProcessors
-
是MergedBeanDefinitionPostProcessor的 internalPostProcessors
这个internalPostProcessors 遍历前面的时候都往这里加,我还没搞懂为这个处理器是个什么东西上面的顺序就是注册顺序,即优先注册实现了PriorityOrdered接口的 BeanPostProcessor,再给容器中注册实现了Ordered接口的BeanPostProcessor,再注册实现Oredered接口的,最后实现是MergedBeanDefinitionPostProcessor的
上面这些注册调用的registerBeanPostProcessors如下:
拿到所有的后置处理器,调用beanFactory.addBeanPostProcessor ,即把BeanPostProcessor注册到BeanFactory中
-
-
注册一个ApplicationListenerDetector
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
ApplicationListenerDetector是在Bean创建完成后检查是不是ApplicationListener
创建BeanPostProcessor对象
注册BeanPostProcessor,实际上就是创建BeanPostProcessor对象,保存在容器中
从registerBeanPostProcessors方法中
会调用beanFactory.getBean 来获取对象(名字为internalAutoProxyCreator,类型为后置处理器),那我们第一次是没有这个对象的 ,所以就会创建一个对象
-
beanFactory.getBean()
会调用doGetBeanpublic <T> T getBean(String name, Class<T> requiredType) throws BeansException { return this.doGetBean(name, requiredType, (Object[])null, false); }
-
doGetBean
首先通过getSingleton 获取 这个单实例对象, 获取不到,就用 createBean() 创建bean
-
getSingleton 先去获取bean
首先通过getSingleton 用singletonFactory.getObject()获取beansingletonObject = singletonFactory.getObject();
我们第一次访问 肯定是没有的, 所以肯定是要去创建
-
createBean() 创建bean
通过这一句调用return this.createBean(beanName, mbd, args);
参数:
调用doCreateBean
-
-
doCreateBean
-
创建bean的实例
-
属性赋值
this.populateBean(beanName, mbd, instanceWrapper);
-
初始化bean initializeBean
-
invokeAwareMethods
处理Aware接口的方法回调(利用这些Aware接口对应的方法进行处理) -
applyBeanPostProcessorsBeforeInitialization
应用后置处理器的postProcessBeforeInitialization方法
-
invokeInitMethods
执行自定义的初始化方法 -
applyBeanPostProcessorsAfterInitialization
执行后置处理器的postProcessAfterInitialization方法
-
-
BeanFactoryAware
通过分析AnnotationAwareAspectJAutoProxyCreator的父类,我们知道它实现了 BeanFactoryAware,所以我们分析它作为Aware做了哪些工作
实现了BeanFactoryAware的setBeanFactory方法的父类
首先找到所有实现了BeanFactoryAware的setBeanFactory方法的父类:
AbstractAdvisorAutoProxyCreator
AbstractAutoProxyCreator
所以上面创建IOC容器走到了doCreateBean 创建AnnotationAwareAspectJAutoProxyCreator类型的名为internalAutoProxyCreator 的 bean 时
初始化initializeBean 中 先调用了invokeAwareMethods方法
invokeAwareMethods
由于 实现了BeanFactoryAware,所以这里时true 就去调用setBeanFactory方法
setBeanFactory
调用的AnnotationAwareAspectJAutoProxyCreator的父类AbstractAdvisorAutoProxyCreator的setBeanFactory方法
- 父类的setBeanFactory方法
AbstractAdvisorAutoProxyCreator的父类AbstractAutoProxyCreator也实现了BeanFactoryAware,所以会调用 AbstractAutoProxyCreator的setBeanFactory方法 - AnnotationAwareAspectJAutoProxyCreator重写的initBeanFactory方法
这个方法中调用了initBeanFactory方法,这个方法被AnnotationAwareAspectJAutoProxyCreator重写了,所以调用的是AnnotationAwareAspectJAutoProxyCreator重写的initBeanFactory方法
AnnotationAwareAspectJAutoProxyCreator 作为后置处理器所做的工作
AnnotationAwareAspectJAutoProxyCreator 是一个后置处理器, 上面我们已经把它放在容器中了,之后任何组件在创建对象的时候 它就可以发挥作用,主要是两个作用:
-
在bean创建前尝试返回对象
通过AbstractAutoProxyCreator 实现的postProcessBeforeInstantiation 方法(这个方法是InstantiationAwareBeanPostProcessor )AnnotationAwareAspectJAutoProxyCreator 的父类AbstractAutoProxyCreator实现的是SmartInstantiationAwareBeanPostProcessor:
public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor {
InstantiationAwareBeanPostProcessor 的方法是BeforeInstantiation
-
在创建对象后 , 通过postProcessAfterInitialization 对对象进行增强
通过AbstractAutoProxyCreator 实现的postProcessAfterInitialization方法(这个方法是BeanPostProcessor )SmartInstantiationAwareBeanPostProcessor继承了BeanPostProcessor
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor
因为两种后置处理器类型不一样
- BeanPostProcessor
方法是BeforInitialization
是在Bean对象创建完成初始化前后调用的 - InstantiationAwareBeanPostProcessor (继承了BeanPostProcessor)
方法是BeforeInstantiation
是在创建Bean实例之前尝试用后置处理器返回对象的
finishBeanFactoryInitialization
首先还是创建ioc容器, 在refresh() 方法中调的是finishBeanFactoryInitialization
finishBeanFactoryInitialization 方法是用来完成beanFactory初始化的,也就是来创建剩下的单实例bean.(因为之前已经创建了后置处理器之类的bean)
finishBeanFactoryInitialization 方法如下:
调用preInstantiateSingletons 创建剩余的单实例
- preInstantiateSingletons
获取容器中所有的bean 放到beanNames里
然后遍历beanNames, 通过getBean(beanName)来获取对象
创建bean
- getBean
getBean会调用doGetBeanpublic Object getBean(String name) throws BeansException { return this.doGetBean(name, (Class)null, (Object[])null, false); }
- doGetBean
-
先从缓存中获取当前bean
-
缓存中获取不到再创建
-
- createBean
我们创建calculator的时候,第一步即resolveBeforeInstantiation返回的是null,因此会执行doCreate 来创建对象-
resolveBeforeInstantiation 解析BeforeInstantiation
给后置处理器一个机会来返回代理对象,而不是target bean instance.也就是希望后置处理器能在此返回一个代理对象. 如果能返回代理对象就使用,如果不能就调用doCreateBean
applyBeanPostProcessorsBeforeInstantiation
resolveBeforeInstantiation 中通过applyBeanPostProcessorsBeforeInstantiation方法尝试返回代理对象
拿到所有的后置处理器,如果这个后置处理器是InstantiationAwareBeanPostProcessor,就调用postProcessBeforeInstantiation方法
postProcessBeforeInstantiation
postProcessBeforeInstantiation 是用来对 那些循环依赖的对象 提前创建代理对象,所以这个方法里 主要是判断那些不需要生成代理对象的就直接返回,需要的才生成代理对象.
下面的是MathCalculator
- 不需要生成代理对象的 直接返回null
- 判断当前bean是否在advisedBeans中
advisedBeans中保存了所有需要增强的bean, - 判断当前bean是否是基础类型isInfrastructureClass或切面
- 判断是否是基础类型 super.isInfrastructureClass(beanClass)
基础类型也就是是否实现了Advice\ PointCut\Advisor\AopInfrastructureBean
- 判断是否是切面 this.aspectJAdvisorFactory.isAspect(beanClass)
判断是不是标了@Aspect
- 判断是否是基础类型 super.isInfrastructureClass(beanClass)
- 判断是否需要跳过shouldSkip
增强器:
就是切面里的通知方法标了@Befor @After @AfterReturning @AfterThrowing @Around注解的
我们给MathCalculator增强的方法如下:
所以这里的candidateAdvisors有四个
每个通知方法的类型是InstantiationModelAwarePointcutAdvisor
所以它判断每个通知方法是不是AspectJPointcutAdvisor类型的,我们这里的方法都是InstantiationModelAwarePointcutAdvisor类型的,所以都返回false - targetSource == null
这种也是返回null
- 判断当前bean是否在advisedBeans中
- 需要生成代理对象的 返回proxy
MathCalculator 的postProcessBeforeInstantiation 完 返回null
- 不需要生成代理对象的 直接返回null
-
doCreateBean
由于上面的返回null,所以调用doCreateBean创建对象
-
创建MathCalculator对象
是跳到这里创建的MathCalculator的对象 -
创建AOP代理
在doCreateBean的initializeBean 中,会通过applyBeanPostProcessorsAfterInitialization 来找到所有后置处理器
initializeBean 方法:
,我们目前关注的是我们这个AnnotationAwareAspectJAutoProxyCreator 后置处理器,所以下面的postProcessAfterInitialization 也是AnnotationAwareAspectJAutoProxyCreator 实现的方法,所以applyBeanPostProcessorsAfterInitialization 目前停在的是这个
-
-
postProcessAfterInitialization
下面具体看AnnotationAwareAspectJAutoProxyCreator 的postProcessAfterInitialization方法具体做了什么
postProcessAfterInitialization 主要调了wrapIfNecessary方法
wrapIfNecessary方法中:
最终wrapIfNecessary给容器中返回当前组件使用cglib增强了的代理对象
以后容器中获取到的就是这个组件的代理对象,执行目标方法的时候代理对象就会执行通知方法的流程
-
判断是否在targetSourcedBeans
-
判断是不是在advisedBeans
-
判断是不是切面
-
getAdvicesAndAdvisorsForBean
获取当前bean的可用的增强器(通知方法),用的是findEligibleAdvisors方法
-
findEligibleAdvisors
找当能在当前bean使用的增强器(也就是找哪些通知方法是需要切入当前bean方法的)
-
findCandidateAdvisors() 找到所有的候选增强器
-
findAdvisorsThatCanApply 找到当前bean能使用的增强器
找哪些通知方法是要切入到当前bean方法的
-
AopUtils.findAdvisorsThatCanApply
遍历所有的Advisors, 看是IntroductionAdvisor 还是不是 IntroductionAdvisor -
canApply
通过算切入点表达式看能不能匹配
-
-
对增强器进行排序
-
-
-
advisedBeans.put 保存当前bean在advisedBeans
存在advisedBeans 中表示这个bean已经被增强处理了 -
创建代理对象
如果我们的bean是需要增强的就会来到这一步,创建当前bean的代理对象
主要用到的是createProxy方法
-
获取所有增强器,保存到proxyFactory中
在这里插入代码片
Advisor[] advisors = this.buildAdvisors(beanName, specificInterceptors);//获取所有增强器 proxyFactory.addAdvisors(advisors); //保存到proxyFactory中
-
用代理工厂proxyFactory 创建对象
- getAopProxyFactory() 得到AOP代理的创建工厂
- createAopProxy 创建AOP代理
- 创建Jdk动态代理
类是有实现接口的 - 还是cglib动态代理
没有实现接口
- 创建Jdk动态代理
-
目标方法的执行流程
首先来看一下 容器中保存的cglib增强后的代理对象mathCalculator 包含的内容:
-
通知方法的信息
-
要切入的目标对象
在 mathCalculator.div(1,1)处打一个断点,看这个方法具体是怎么执行的
进入的是CglibAopProxy.intercept 方法:
- 获取拦截器链
连接器链就是 每个advisor 包装成MethodInterceptor//根据ProxyFactory对象获取将要执行的目标方法的拦截器链 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
- 没有拦截器链 直接执行目标方法
- 有拦截器链
把需要执行的目标对象,目标方法,拦截器链等信息传入创建CglibMethodInvocation对象,并调用proceed方法retVal = (new CglibAopProxy.CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy)).proceed();
获取拦截器链
最后得到的拦截器链
根据ProxyFactory对象获取将要执行的目标方法的拦截器链,拦截器链中就是 每个通知方法包装成MethodInterceptor
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
这一句会调 getInterceptorsAndDynamicInterceptionAdvice方法:
用advisor链的工厂获取
getInterceptorsAndDynamicInterceptionAdvice:
遍历所有的增强器,根据增强器是PointcutAdvisor IntroductionAdvisor 还是其它 ,将器转为对应的interceptors,放到interceptorList中
-
List interceptorList = new ArrayList(advisors.length);
保存所有拦截器:一个默认的ExposeInvocationInterceptor和我们定义的4个增强器
-
PointcutAdvisor
-
IntroductionAdvisor
-
其它
registry.getInterceptors:
将增强器转为MethodInterceptor
- advisor是MethodInterceptor
直接返回 - advisor不是MethodInterceptor
用对应的适配器 将其转成MethodInterceptor
所有的适配器
执行拦截器链
执行拦截器链 就是目标方法通知方法的执行过程
通过拦截器链的机制,保证通知方法和目标方法的执行顺序
retVal = (new CglibAopProxy.CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy)).proceed();
是先创建CglibMethodInvocation对象,然后调用它的proceed()
proceed()的过程:
- 判断当前索引和和拦截器-1大小是否相等
currentInterceptorIndex 默认是-1if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return this.invokeJoinpoint(); //执行目标方法
因此 如果没有拦截器,就会执行目标方法;或者到了最后一个拦截器 也会执行目标方法 - 通过索引获取到拦截器,每一个拦截器执行自己的invoke方法
自己的invoke方法又会调用CglibMethodInvocation的proceed方法,因为索引加1 了,也就是执行了下一个拦截器
所以等下一个拦截器执行完成返回以后再来执行
通过索引得到获取拦截器:Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
-
ExposeInvocationInterceptor
索引是0获取到的拦截器是ExposeInvocationInterceptor,直接执行自己的invoke方法:
其中,this就是之前创建的CglibMethodInvocation对象return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);
ExposeInvocationInterceptor的invoke()方法:
就是把CglibMethodInvocation作为共享数据放进去,然后执行CglibMethodInvocation的proceed方法(相当于调用了下一个拦截器)
invocation:private static fin al ThreadLocal<MethodInvocation> invocation;
ThreadLocal就是同一条线程共享数据的, 共享的数据是MethodInvocation ,即CglibMethodInvocation对象
-
AspectJAfterThrowingAdviceInterceptor
上面的拦截器调用CglibMethodInvocation.proceed 由于索引加1 索引是1得到AspectJAfterThrowingAdvice,拦截器,AspectJAfterThrowingAdvice调用自己的invoke方法如下:
- 调用下一个拦截器
也是通过调用 CglibMethodInvocation的invoke 调用下一个拦截器 - 如果有异常
会通过try catch 捕获到异常,然后执行标了@AfterThrowing注解的方法
- 调用下一个拦截器
-
AfterRetruningAdviceInterceptor
- 调用下一个拦截器
- 执行自己的afterReturning方法有异常的话这一句就不会执行
等到之前的都return了之后,就会执行标了@afterRetruning方法. 如果之前执行的有异常,那这一句就不会执行.
-
AspectJAfterAdviceInterceptor
- 调用下一个拦截器
下一个拦截器是标了@Before的方法,调完这个会执行被增强的方法 - 调用invokeAdviceMethod
这里就是调用@After标的方法,这个是用finally包的,所以不管有无异常这一句都会执行
- 调用下一个拦截器
-
MethodBeforeAdviceInterceptor
- 先执行@Before方法
- 再执行mi.proceed
因为是最后一个拦截器了所以满足这个条件们就会调用被增强的方法if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return this.invokeJoinpoint();//调用被增强的方法
-
AOP原理总结
- @EnableAspectJAutoProxy 开启AOP功能
- @EnableAspectJAutoProxy会给容器中注册一个组件AnnotationAwareAspectJAutoProxyCreator
- AnnotationAwareAspectJAutoProxyCreator是一个后置处理器
- 容器创建流程:
- refresh()的registerBeanPostProcessors() 是注册后置处理器的,这里会创建 AnnotationAwareAspectJAutoProxyCreator对象
- refresh()的finishBeanFactoryInitialization() 会初始化剩下的单实例bean
- 这里会创建业务逻辑组件和切面组件
- AnnotationAwareAspectJAutoProxyCreator 就会拦截组件的创建过程
- 组件创建完后, 初始化后还会判断组件是否需要增强
需要增强,就会把切面的通知方法包装成增强器,然后给业务逻辑组件创建一个代理对象
- 执行目标方法
也就是代理对象执行目标方法
使用CglibAopProxy.intercept()进行拦截:
* 得到目标方法的拦截器链(增强器包装成拦截器MethodInterceptor)
* 利用拦截器的链式机制,依次进入每一个拦截器进行执行
* 效果:
正常执行:前置通知->目标方法->后置通知->返回通知
正常执行:前置通知->目标方法->后置通知->异常通知