Spring AOP实现原理
前言1.@EnableAspectJAutoProxy注解原理2.AnnotationAwareAspectJAutoProxyCreator 分析1.分析前工作,给相关方法打上断点2.源码调试分析1.创建过程2.作用(结合源码打断点调试理解)总结end...前言
前面我们对AOP进行了简单实现,那它是如何帮助我们实现相关通知方法的?它的底层是如何做到的?今天我们来探讨下。源码的学习一直是难啃的硬骨头,但是啃下了,对编程和面试都有很大的帮助。本篇文章只是个人的简单理解,想要真正深入的理解,建议:
阅读相关书籍,打断点进行源码调试。文章课程链接:尚硅谷spring注解驱动教程(雷神)
我们可以通过以下方式学习原理
往容器中注册了什么组件组件在什么时候工作组件能够帮我们做些什么
1.@EnableAspectJAutoProxy注解原理
我们实现AOP,只需在注解类加上@EnableAspectJAutoProxy就可生效,因此这个注解是我们研究源码的入口,首先看看这个注解,如图:
我们注意到,该注解又用@Import导入了一个组件(AspectJAutoProxyRegistrar),我们再点进去看看,如图:
AspectJAutoProxyRegistrar类实现了ImportBeanDefinitionRegistrar,我们在前面讲到,实现ImportBeanDefinitionRegistrar可以帮我们自定义的往容器中注册组件。那下面我们就打一个断点,看看这里往容器中注册了什么组件。进入registerAspectJAnnotationAutoProxyCreatorIfNecessary() 方法中,点进来如下:
可以看到该方法又掉用了下面这个方法,继续跟进,这里的 registerOrEscalateApcAsRequired() 方法第一个参数是传了AnnotationAwareAspectJAutoProxyCreator.class,点进来如下:
代码首先判断registry中是否已经包含了org.springframework.aop.config.internalAutoProxyCreator,我们第一次进入,当然是不存在,因此走下面的 else 逻辑
首先是创建一个bean定义信息:RootBeanDefinition beanDefinition = new RootBeanDefinition(cls); 注意传入的cls是 AnnotationAwareAspectJAutoProxyCreator 的class对象中间的代码设置了各种属性最后往 registry 中注册了一个bean定义信息,名称为 org.springframework.aop.config.internalAutoProxyCreator ,bean定义为创建AnnotationAwareAspectJAutoProxyCreator
整个过程最终就是往容器中注册一个AnnotationAwareAspectJAutoProxyCreator 组件(自动代理创建器),组件id为 org.springframework.aop.config.internalAutoProxyCreator
我们回到 AspectJAutoProxyRegistrar ,看下一句代码,如图:
这里是把 EnableAspectJAutoProxy 注解的内容信息拿到,并在后面做一些判断和操作。
前面的分析中,我们知道,@EnableAspectJAutoProxy 注解其实就是帮我们注册了一个 AnnotationAwareAspectJAutoProxyCreator 组件,下面我们继续研究。
2.AnnotationAwareAspectJAutoProxyCreator 分析
1.分析前工作,给相关方法打上断点
首先,我们还是先进入到源码,可以看到,继承了AspectJAwareAdvisorAutoProxyCreator。
这里,我们先理清该组件的继承关系。这里代码截图不一一展示,通过源码得出以下继承关系(idea工具快捷键 Ctrl+Alt+Shift+U):
梳理继承关系后,我们来分析研究下 AbstractAutoProxyCreator ,上图红框上方第二个,此类又继承了 ProxyProcessorSupport 并实现了 SmartInstantiationAwareBeanPostProcessor(bean的后置处理器)和BeanFactoryAware,下一步我们点到 BeanFactoryAware 中,如图:
此接口能将bean工厂给传进来,下面我们看下SmartInstantiationAwareBeanPostProcessor 这个后置处理器,所谓后置处理器,就是在bean初始化完成前后做事情。源码如图:
下一步,我们在 AbstractAutoProxyCreator 上把实现的方法打上相应的断点。其中有 BeanFactoryAware 的 setBeanFactory() 方法和所有与后置处理器有关的方法,如图(部分):
打上之后,我们回到此类(AbstractAutoProxyCreator)的子类(AbstractAdvisorAutoProxyCreator)看一下源码,发现其重写了setBeanFactory()方法,并调用了initBeanFactory(),如图:
我们在看看 AbstractAdvisorAutoProxyCreator 中是否有后置处理器相关的方法,有的话打上断点(此类没有)。然后在回到 AbstractAdvisorAutoProxyCreator 的子类(AspectJAwareAdvisorAutoProxyCreator)是否有相关的方法(后置处理器方法或setBeanFactory()),有的话继续打断点,就这样层层找回去,直到AnnotationAwareAspectJAutoProxyCreator,点进源码,我们发现有一个 initBeanFactory() 方法,似乎与前面的initBeanFactory() 方法有联系,先打上断点,如图:
最后,我们在自己的配置文件中加上注解(断点在组件注册的地方),此配置文件在文章《AOP实现中》创建,如图:
2.源码调试分析
1.创建过程
启动我们的测试类,首先来到 AbstractAdvisorAutoProxyCreator 的 setBeanFactory() 方法,如图:
那他是如何到达这一步的呐,我们从自己写的测试方法开始(在文章《AOP实现》中编写),先看看方法栈,如图:
分析过程请看视频,图片分析排版乱且不易编写,这里记录分析结果:
传入配置类,创建IOC容器,相应代码 AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AopConfig.class);注册配置类,刷新容器,调用方法 refresh();registerBeanPostProcessors(beanFactory); 注册bean的后置处理器来实现拦截bean的创建
1)先获取IOC容器中已经定义了的需要创建对象的所有BeanPostProcessor
2)给容器中添加其他 BeanPostProcessor
3)优先注册实现了priorityOrdered接口的 BeanPostProcessor
4)再注册实现了 Ordered 接口的 BeanPostProcessor
5)最后注册没有实现优先级接口的 BeanPostProcessor
6)注册 BeanPostProcessor 实际上就是创建 BeanPostProcessor 对象,保存在容器中
创建 internalAutoProxyCreator 的 BeanPostProcessor 【AnnotationAwareAspectJAutoProxyCreator】过程
–6.1)创建bean实例
–6.2)populateBean,给bean的各种属性赋值
–6.3)initializeBean:初始化bean
----6.3.1)invokeAwareMethods(),处理Aware接口的方法回调,这一步就调到了 setBeanFactory(),如图:
----6.3.2)applyBeanPostProcessorsBeforeInitialization(),应用后置处理器的 PostProcessorsBeforeInitialization()
----6.3.3)invokeInitMethods():执行自定义的初始化方法
----6.3.4)applyBeanPostProcessorsAfterInitialization(),执行后置处理器的 PostProcessorsAfterInitialization()
–6.4)BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator) 创建成功,并
7)把 BeanPostProcessor 注册到 BeanFactory 中( beanFactory.addBeanPostProcessor(postProcessor) )
以上为 AnnotationAwareAspectJAutoProxyCreator 的创建过程,且是InstantiationAwareBeanPostProcessor 类型的后置处理器,可以通过继承图看到finishBeanFactoryInitialization(beanFactory);完成BeanFactory的初始化工作,创建剩下的单实例bean
1)遍历获取容器中的所有bean,依次创建对象:getBean(beanName);方法依次调用
getBean -> doGetBean() -> getSingleton()
2)创建bean【AnnotationAwareAspectJAutoProxyCreator :所有bean创建之前会有一个拦截】
–2.1)先从缓存中获取当前bean,如果能获取到(bean是在之前创建过的),直接使用,否则再创建;只要创建好的Bean都会被缓存起来
–2.2)createBean(); 创建bean
【BeanPostProcessor是在Bean对象创建完成初始化前后调用的】
【InstantiationAwareBeanPostProcessor 是在创建Bean实例之前先尝试用后置处理器返回对象】
因此,AnnotationAwareAspectJAutoProxyCreator 会在任何bean创建之前先尝试返回bean实例
----2.2.1)resolveBeforeInstantiation(beanName,mbdToUse); 解析BeforeInstantiation,希望后置处理器在此能返回一个代理对象,如果能返回代理对象就使用,不能就继续
----2.2.2)doCreateBean(beanName, mbdToUse, args);真正的去创建一个bean实例,和前面的流程是一样的
2.作用(结合源码打断点调试理解)
每一个bean创建之前,调用 postProcessBeforeInstantiation(),以自己写的aop测试类为例
1)判断当前bean是否在advisedBeans中(保存了所有需要增强的bean)
2)判断当前bean是否是基础类型的Advice、Pointcut、Advisor、AopInfrastructureBean,或者是否是切面(@Aspect)
3)是否需要跳过
–3.1)获取候选的增强器(切面中的通知方法)List candidateAdvisors,每一个封装的通知方法的增强器类型为 InstantiationModelAwarePointcutAdvisor,
判断每一个增强器是否是AspectJpointcutAdvisor类型的,返回true
–3.2)其他返回false创建对象
postProcessAfterInstantiation
return wrapIfNecessary(bean, beanName, cacheKey);//如果需要的情况下,进行包装
1)获取当前bean的所有增强器(通知方法)Object[] specificInterceptors
1.1)找到候选的所有增强器(找哪些通知方法是需要切入当前bean方法的)
1.2)获取到能在bean中使用的增强器
1.3)给增强器排序
2)保存当前bean 在 advisedBeans 中
3)如果当前bean需要增强,创建当前bean的代理对象
3.1)获取所有增强器(通知方法)
3.2)保存到 proxyFactory 中
3.3)创建代理对象,spring自动决定,分别为 JKD动态代理和 cglib动态代理
4)给容器中返回当前组件使用cglib增强了的代理对象
5)以后容器中获取到的就是这个组件的代理对象,执行目标方法的时候,代理对象就会执行通知方法的流程。目标方法的执行
容器中保存了组建的代理对象(cglib增强后的对象),这个对象里面保存了详细信息(比如增强器,目标对象等)
1)CglibAopProxy.intercept();拦截目标方法的执行
2)根据ProxyFactory对象获取将要执行的目标方法拦截器链
List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
–3.1)List interceptorList保存所有拦截器链(一个默认的ExposeInvocationInterceptor和自己定义的增强器)
–3.2)遍历所有的增强器,将其转为Interceptor
–3.3)将增强器转为 List ,如果是 MethodInterceptor ,直接放到容器中,如果不是,使用AdvisorAdapter 将增强器转为 MethodInterceptor,转换后返回
3)如果没有拦截器链,直接执行目标方法
拦截器链(每一个通知方法又被包装为方法拦截器,利用MethodInterceptor机制)
4)如果有拦截器链,把需要执行的目标对象、目标方法、拦截器链等信息传入创建一个 CglibMethodInvocation 对象,并调用其proceed() 方法(触发过程)
5)拦截器链的触发过程(详细分析)
首先,我们将断点打到目标方法的执行上,如图,debug运行
运行后,来到断点处,直接进入方法(step into),来到这个方法,第一个红框为获取拦截器链,上面对其进行了分析,在下面的红框处打上断点,准备分析拦截器链的执行流程
首先看看当前的拦截器链,如图
我们进入到 xx.proceed() 方法,如图,我们来到了 CglibAopProxy的 proceed()方法,我们再点击进入
我们来到了 ReflectiveMethodInvocation 的 proceed() 方法,这里首先是一个判断,如果没有拦截器执行目标方法(size = 0),或者拦截器的索引(this.currentInterceptorIndex)和拦截器数组-1大小一样(执行到最后一个拦截器)执行目标方法(return this.invokeJoinpoint();)。此时,currentInterceptorIndex = -1,下一步 currentInterceptorIndex 会先自增,用于获取当前拦截器,我们给下面的 return ((Mxxx).invoke(this) 打上断点。我们进入这个 invoke(this) 方法。
我们来到了 ExposeInvocationInterceptor 的 invoke() 方法,如图,我们进入到红框的方法中(这里我点击下一步直接就跳过了,只有点击放行,就又到了ReflectiveMethodInvocation 的 proceed() 方法)
进入方法后,我们发现再次来到了 ReflectiveMethodInvocation 的 proceed() 方法,如图,此时 索引 = 1,拦截器为:前置通知,再次进入到 invoke() 方法。
我们进入到了 MethodBeforeAdviceInterceptor 的 invoke() 方法,它首先执行了前置通知方法,然后执行 mi.proceed() 方法,我们进入这个方法。
我们发现,我们再次来到了 CglibAopProxy的proceed() ,和前面的流程一样,我们点进去,自然而然我们再次来到了 ReflectiveMethodInvocation 的 proceed() 方法,如图,此时 索引 = 2,拦截器为:后置(返回)后置,再次进入到 invoke() 方法。
来到 AspectJAfterAdvice 的 invoke() 方法,这里注意,首先是执行 mi.proceed() ,等返回后再去执行后置通知方法(最后一个执行),且方法在 finally 语句块中,这也解释了为什么目标方法是否正常返回都会执行的原因,我们再次进入到 proceed() 方法
下面的步骤是一样的,不再赘述,这里只谈谈每个通知类型的 invoke() 方法:
再次进入到 ReflectiveMethodInvocation 的 proceed() 方法 ,索引 = 3,拦截器:正常返回通知,进入到 invoke() 方法
正常返回通知方法在 mi.proceed()下(下一个掉异常返回通知,然后返回),如果有异常,就直接抛给上一个方法了,因此,正常返回通知在发生异常时不会执行,我们再次进入 mi.proceed()
此时 索引 = 4,拦截器:异常返回通知,进入方法,如图
可以看到,异常返回通知会捕获异常,并抛出异常,再次进入 ReflectiveMethodInvocation 的 proceed() 方法,来到第一个判断,索引为 4 等于 拦截器链(size = 5)- 1,执行目标方法,如图
执行目标方法后,返回到异常返回通知,如果有异常就捕获执行,没有返回到正常返回通知,返回后置通知,至此,整个拦截器链的执行流程就分析完了。
总结
@EnableAspectJAutoProxy 开启AOP功能@EnableAspectJAutoProxy 会给容器中注册一个组件 AnnotationAwareAspectJAutoProxyCreatorAnnotationAwareAspectJAutoProxyCreator 是一个后置处理器 (InstantiationAwareBeanPostProcessor类型)容器的创建流程:1)this.registerBeanPostProcessors(beanFactory); 注册后置处理器,创建 AnnotationAwareAspectJAutoProxyCreator 对象
2)this.finishBeanFactoryInitialization(beanFactory);初始化剩下的单实例bean
2.1)创建业务逻辑组件和切面组件
2.2)AnnotationAwareAspectJAutoProxyCreator 拦截组件的创建过程
2.3)组件创建完成之后,判断组件是否需要增强,是:切面的通知方法,包装成增强器(Advisor)给业务逻辑组件创建一个代理对象(cglib)执行目标方法:
1)代理对象执行目标方法
2)CglibAopProxy.intercept();
2.1)得到目标方法的拦截器链(增强器包装成拦截器MethodInterceptor)
2.2)利用拦截器的链式机制,依次进入到每一个拦截器进行执行
2.3)效果(spring版本有区别):正常流程:前置通知 -> 目标方法 -> 正常返回通知 -> 后置通知
异常流程:前置通知 -> 目标方法 -> 异常返回通知 -> 后置通知
end…
如果总结的还行,就点个赞呗 @_@ 如有错误,欢迎指点,下一篇spring注解驱动开发-7 Spring声明式事务···