Spring AOP原理分析

AOP是Spring Core中几大重要能力之一,我们可以使用AOP实现很多功能,比如我们常用的日志处理与Spring中的声明式事务。

AOP的几个重要概念

Aspect:切面,在Spring中意为所有通知方法所在的类

Join point:连接点,程序执行中的一点,在Spring中只表示方法执行(Spring只支持方法级别的拦截)

Advice:通知,在特定连接点上采取的操作,Spring将通知抽象为拦截器,并围绕连接点维护拦截器链。共有5种类型,before(切点之前执行),around(环绕执行,即切点前后执行),After returning(切点正常执行完返回后执行),After throwing(切点抛出异常后执行),after(切点之后执行,不管是异常或正常结束),AOP拦截器链则为以上五种通知组成。我们可以在通知方法中获得我们需要的参数(返回值,异常信息,代理对象等)

Pointcut:切点,与通知一起出现,使用专门的切点表达式决定在何处执行通知方法。

Introduction:引入,为类添加新的方法或字段。

Target object:被代理的对象

AOP proxy:AOP代理对象,由JDK动态代理或CGLIB代理生成

Weaving:织入,将通知等织入代理类。Spring AOP是动态织入(运行时织入),AspectJ则是静态织入(编译时织入)

几个注意点

关于Spring AOP的具体使用这里不做介绍,具体见文档,这里说几个在使用代理时需要注意的地方。

由于Spring AOP框架基于代理的特性,目标对象内的调用根据定义不会被拦截。自调用即类似this.bar()或this.foo()这样的调用,即使在bar方法上有通知方法通知也不会执行。对于JDK代理,只能拦截代理上的公共接口方法调用。使用CGLIB,可以拦截代理上的公共和受保护方法调用(Cglib基于子父类实现代理,而私有方法不会被子类继承)。当多个通知都想在同一个连接点上运行时,他们将按照优先级顺序执行,优先级顺序可以使用Order接口来定义。

总结一句:自调用通知方法不执行,私有方法通知不执行。

原理

接下来从源码角度分析下Spring AOP的实现原理。

在Spring中我们使用@EnableAspectJautoProxy开启AOP功能,我们以此为入口。(其他的Enable注解分析原理都是一样的,比如EnableAsync等)。

@EnableAspectJautoProxy

它使用@Import注解导入了AspectJAutoProxyRegistrar类,该类实现了ImportBeanDefinitionRegistrar接口,用于向Spring中注册类。

AspectJAutoProxyRegistrar

在registerBeanDefinitions方法的第一行注册了AOP需要的相关bean,方法中的下面部分是取EnableAspectJAutoProxy注解的信息,根据参数值做相应的处理,这里主要关注方法的首行代码,进入registerAspectJAnnotationAutoProxyCreatorIfNecessary方法。

发现最终注册了AnnotationAwareAspectJAutoProxyCreator。该类是实现AOP的基础,我们对该类进行分析,首先来看继承结构

BeanFactoryAware接口主要用于设置BeanFactory,这里我们主要关注InstantiationAwareBeanPostProcessor与BeanPostProcessor接口,实现这两个接口意味着AnnotationAwareAspectJAutoProxyCreator是一个Spring的后置处理器,后置处理器会在bean的创建过程中起作用,关于后置处理器不熟悉的同学可以去看这篇文章Spring之IOC容器初始化。

InstantiationAwareBeanPostProcessor

InstantiationAwareBeanPostProcessor有一个before与after接口,由接口名可知两个方法分别在bean实例化前后调用,关于Spring中bean的实例化过程不清楚的可以看Spring Bean的实例化分析。我们在子类中找到他们的实现(after方法由于没有特别的处理这里就省略了)

before的实现

首先从缓存中获取,然后调用this.isInfrastructureClass(beanClass)判断创建的类是否为Advice、Pointcut等相关类,若是则放入adviseBean集合并返回null,正常的bean经过该方法会返回null,这里主要是用来处理我们的切面类。

isInfrastructureClass

bean创建完成后接下来就是另一个接口BeanPostprocess(实例化,调用构造函数)开始起作用了。

BeanPostprocess

他会在InstantiationAwareBeanPostProcessor(初始化,即BeanDefination的初始化)接口方法执行完之后调用,查看其实现(before方法由于没有特别的处理这里就省略了)

最终会调用wrapIfNecessary方法判断该bean是否需要增强。进入方法

正常bean的创建会进入到isInfrastructureClass这个分支,isInfrastructureClass这个方法就是之前分析的判断是否是Aspect等注解的类,如果不是则调用getAdvicesAndAdvisorsForBean方法获取到符合该bean的通知方法(即相应的Advisor)。

最终调用createProxy创建代理对象。

createProxy

接上图右侧

最终进入代理工厂创建代理对象的方法,根据是否实现接口自动选择创建JDK动态代理(基于接口)或者是Cglib代理(基于子父类)。到这里切面以及要被代理的类就都创建完成了,接下来就是如何运行通知方法了。

执行流程

我们这里假设上一步创建的对象为Cglib对象,了解过Cglib代理的同学都知道实现代理要实现MethodInterceptor接口,在里面的intercept方法中进行方法的拦截。我们找到代理类的intercept方法

首先调用getInterceptorsAndDynamicInterceptionAdvice方法获取所有通知方法的Advisor拦截器链,chain不为空会依次调用对应的Advisor拦截器的proceed方法进行代理调用,在此会按照通知的顺序执行原方法与通知方法。

大体的执行流程就分析完了,有时间的同学最好简单写个demo然后跟着一步步debug,这样能够更清晰的了解流程。

最后总结一下,容器初始化时将切面等信息放入通知集合中,正常bean在创建时会判断该bean是否需要被增强,若需要增强,创建相应的代理对象。在执行时,代理对象执行相应的invoke方法,在方法中获取到通知集合并抽象成拦截器链,使用拦截器模式按照顺序执行相应的方法。

附两张流程图:

文章来源于互联网:Spring AOP原理分析

阅读全文
下载说明:
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.shuli.cc/?p=16989,转载请注明出处。
0

评论0

显示验证码
没有账号?注册  忘记密码?