- Spring 5企业级开发实战
- 周冠亚 黄文毅
- 1727字
- 2025-02-17 15:01:12
3.6 Spring AOP的实现原理
Spring AOP的实现是通过创建目标对象的代理类,并对目标对象进行拦截来实现的。分析Spring AOP的底层实现,需要重点分析几个常用类,相关类图如3-15所示。
ProxyConfig类是一个基类——数据类,主要为各种AOP代理工厂提供属性配置。
AdvisedSupport类是ProxyConfig类的子类,其封装了AOP中对通知(Advice)和通知器(Advisor)的相关操作,这些操作对于不同的创建代理对象的类都是相同的,但是对于具体的AOP代理对象的生成需要AdvisedSupport各个子类去实现。
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P114_33185.jpg?sign=1739936457-4Z5aDEllkGmVMV0otfQIC4iIRMvd45LN-0-28495ca89b6c294c1ce673252f674442)
图3-15 Spring AOP核心类图
ProxyCreatorSupport类是AdvisedSupport的子类——辅助类,不同子类的一些通用的操作都封装在ProxyCreatorSupport中。
ProxyFactoryBean,ProxyFactory和AspectJProxyFactory是用于创建AOP代理对象的,这三个类的作用分别如下:
• ProxyFactoryBean类:功能是创建声明式的代理对象。
• ProxyFactory类:功能是创建编程式的代理对象。
• AspectJProxyFactory类:功能是创建基于AspectJ的代理对象。
3.6.1 设计原理
下面以ProxyFactoryBean为例,分析Spring AOP的实现原理。
首先定义一个接口Log,其中包含一个printLog()方法,Log接口的代码如下:
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P114_94759.jpg?sign=1739936457-a0LQxcDDatTvO2rRqRUfovQo6dtB52Ga-0-94ad7d468be59fce83fa4a84948056ba)
再创建一个Target类,实现Log接口,重写printLog方法,Target类的代码如下:
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P115_94764.jpg?sign=1739936457-8iz9czy5tVvfEbYeOwoBV5Id1I2oUsmz-0-72743c2c6d0b1143cbe3fe016a7e5c0c)
然后创建一个通知类LogAroundAdvice并实现MethodInterceptor接口,重写invoke()方法,在方法执行前后分别打印实现,LogAroundAdvice的实现如下:
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P115_94765.jpg?sign=1739936457-6LNQHVc4FBi1xJNHbH8tTzliLd81SyV7-0-30a56f1f376bca18df15f37ff0943a51)
创建一个测试类,用于观察测试结果,测试代码如下:
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P116_94766.jpg?sign=1739936457-RnDzyJbT2aWNvRXahCta78HerbC0PgIR-0-e2f45157144785a9cbcf9b7556eec2f0)
文件spring-chapter3-sourcecodelearning.xml的配置如下:
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P116_94767.jpg?sign=1739936457-LCkSgAt8qbwR6MXyU4iB4zVMDMTiTC6U-0-ba8319bf1fd4f3dec3096b2fd9de0398)
运行测试代码,测试结果如下:
方法执行开始时间:2018-10-03 08:18:51 167 执行一些操作 方法执行结束时间:2018-10-03 08:18:52 172
从测试结果可以看出,在正常的调用printLog()方法前后分别打印了日志,说明AOP已经实现了。下面将通过这个案例分析ProxyFactoryBean的实现逻辑。
打开ProxyFactoryBean的代码,其生成代理对象的核心方法是getObject()方法,部分代码如下:
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P117_94769.jpg?sign=1739936457-QQsZqulVjjjsfMobz8SH5UybIeBdRYpT-0-8f3371ed2fa92e88a67d6055c9ac79f8)
下面分析getObject()方法中的initializeAdvisorChain()方法,initializeAdvisorChain()方法是初始化通知器链(或者叫拦截器链)的,其代码如下:
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P117_94770.jpg?sign=1739936457-tgjU0JA5KD30JhxAvOXzs3NrgtYUcutd-0-adf071fe54c116599079e37db0b3dac0)
执行initializeAdvisorChain()方法后,如果是单例模式,将会调用getSingletonInstance()方法获取一个单例模式的代理对象,getSingletonInstance()方法代码如下:
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P118_94772.jpg?sign=1739936457-2ACPvq76aCJri3XmrgjUaHGMYhu8mpkL-0-871a7f38133b655db4dc34e743052c58)
执行initializeAdvisorChain()方法后,如果是非单例模式即原型模式,将会调用newPrototypeInstance()方法获取一个新的原型模式的代理对象,newPrototypeInstance()方法代码如下:
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P119_94774.jpg?sign=1739936457-14LPTUAMYK5t1WlpV7Ki5tZIRw3DHyDu-0-38517d667c753c7135eb7805d17bf84b)
可以发现,无论是单例模式还是原型模式,最终都是通过调用getProxy()方法获取代理对象的,getProxy()的实现如下:
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P120_94776.jpg?sign=1739936457-m0Chx4UihjufkfkHH3zvg68I7gZ2iDj7-0-8340eacc0e58cf21db959ad3133ae470)
通过以上对getSingletonInstance()方法和newPrototypeInstance()方法的代码注释可以发现,这两个方法都会调用ProxyCreatorSupport.createAopProxy()方法,ProxyCreatorSupport类的核心代码如下:
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P120_94777.jpg?sign=1739936457-SEqHsAoCeraAERbFjWTnZLgfAqO8irhb-0-f7f0b63edf4a272b89041f97b4516acf)
从createAopProxy()方法的代码可以看出,AopProxy对象是在DefaultAopProxyFactory类的createAopProxy()方法中生成的,DefaultAopProxyFactory.createAopProxy()方法的代码如下:
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P121_94778.jpg?sign=1739936457-wJ3rY7OHcdyJiUZshMK5mAE0xwQ7ecsW-0-2788a82838b9256158ebea93d63790fc)
从DefaultAopProxyFactory.createAopProxy()使用的类的名称可以发现,如果是继承了接口的类,会使用JDK动态代理,即用JdkDynamicAopProxy类创建代理对象,否则将会使用CGLIB动态代理即用ObjenesisCglibAopProxy类创建代理对象,关于这两种动态代理的具体使用,请参考本章3.1节。
3.6.2 JdkDynamicAopProxy
JDK动态代理只能针对接口起作用,Spring中通过JdkDynamicAopProxy类使用JDK动态代理创建AOPProxy对象,JdkDynamicAopProxy类的定义如下:
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P121_94779.jpg?sign=1739936457-GpfzE5B9wO3q573ZRh8pcdTcfj87BIuh-0-7c6033c85908189ae5bcf67aeb3f4f2a)
JdkDynamicAopProxy类实现了InvocationHandler接口,因而可以使用JDK动态代理产生代理对象。
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P121_94780.jpg?sign=1739936457-7MJUMTeXZ6ht4JaRN3LpWpYCQ6ycJlOg-0-0d003f31dfdae82af2f5b642c1fbe862)
此处的getProxy()方法是获取代理对象的入口,其是通过调用以下方法实现的:
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P121_94781.jpg?sign=1739936457-sIZrMdegt0qO1dQpl0ARC5UWrDBupXM8-0-35c0667b8dd6bb7a3fff725ec7a80503)
findDefinedEqualsAndHashCodeMethods()方法的功能是查找代理的接口是否有定义equals()或hashCode()方法。
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P122_94783.jpg?sign=1739936457-9uadYePfF4NAxal9piqDDWYdRDuS9RgB-0-509f980e30048a877f496e080571822c)
通过在3.1节中的介绍可以得知,InvocationHandler接口的invoke()方法是代理对象执行方法调用和增强的地方,下面分析JdkDynamicAopProxy实现InvocationHandler接口重写invoke()方法的代码:
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P123_94785.jpg?sign=1739936457-BQmoaMZWl36QwFEtFZPEOa17GgCi9z9Z-0-63733236a96b681c392b2b6e841584a1)
通过以上代码分析可知,最核心的功能都是在invocation.proceed()方法中实现的,下面分析ReflectiveMethodInvocation,代码如下:
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P124_94787.jpg?sign=1739936457-vc1UOWsZG5aE1PtqhotxTBIUF6XH3QHJ-0-f416a50dfd4ee5cb7c21fcf3e72aa79c)
invokeJoinpoint()方法是调用目标对象方法的地方,其实现如下:
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P125_94788.jpg?sign=1739936457-TqJxLoqKTd507ESpGbNcoGyOgexUJwPt-0-9fa41d4f309acdedaca796e985bfe256)
invokeJoinpoint()方法会调用AopUtils.invokeJoinpointUsingReflection()方法,代码如下:
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P125_94789.jpg?sign=1739936457-Bg3UX1MAh5ZRLS65jvkWjKUR5o1QVPH5-0-0b875bfc6272e5a02990890d34412ada)
可以看到invokeJoinpointUsingReflection()方法最终是通过反射调用目标对象的方法。
通过对JdkDynamicAopProxy类的代码进行分析可以知道,JdkDynamicAopProxy类实现了InvocationHandler接口,重写了invoke()方法,当进行调用时,其实并不是调用目标对象,而是为目标对象创建一个代理对象,触发代理对象的invoke()方法,在invoke()方法中会通过反射调用目标对象的方法,Spring AOP相关通知的调用也是在invoke()方法中完成的。
3.6.3 CglibAopProxy
由于JDK动态代理只能针对接口生成代理对象,对于没有实现接口的目标对象,需要使用CGLIB产生代理对象,下面分析CglibAopProxy的代码。
回到DefaultAopProxyFactory.createAopProxy()方法,如果目标对象没有实现接口,将会返回一个ObjenesisCglibAopProxy对象。ObjenesisCglibAopProxy类的代码如下:
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P126_94790.jpg?sign=1739936457-HssXLZDhQ4XSTUU8nTAhVYFBbcmIJ6BK-0-0afd895ed9382360400a5f619a9cadfc)
从代码可以看出,ObjenesisCglibAopProxy继承了CglibAopProxy,Objenesis是一个轻量级的Java库,作用是绕过构造器创建一个实例。因此分析的重点还是CglibAopProxy类。
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P127_94791.jpg?sign=1739936457-ukQ2YsCUQ4OMWKTBZQPOrV9vkvbfe9rG-0-63be6a8caf9f8162f38fd6d8c3b82b8a)
由本章3.1节可知,CGLIB的运行需要配合回调方法,实现MethodInterceptor接口,在CglibAopProxy中也是一样,下面分析获取回调方法getCallbacks()的代码:
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P128_94793.jpg?sign=1739936457-JXCfvHIQF2dAXY8NwGUPMi61kLn74YAb-0-7a8ae20e7c68512eb46066d824eece32)
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P129_94794.jpg?sign=1739936457-9vCqS4fCquzajuRagiuRzRfDIypPiOaV-0-c633ff99cf047a8961274b281fd6d13c)
通过上面对CGLIB创建代理和获取回调通知的代码分析,可以了解到CGLIB在获取代理通知时,会创建DynamicAdvisedInterceptor类;当调用目标对象的方法时,不是直接调用目标对象,而是通过CGLIB创建的代理对象来调用目标对象;并且在调用目标对象的方法时,会触发DynamicAdvisedInterceptor的intercept回调方法对目标对象进行处理,CGLIB回调拦截器链的代码如下:
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P129_94795.jpg?sign=1739936457-8zZc7j5ZL12d9KCJSDWpmREuuU6L9LsV-0-2e69500d3ed266563308bf6c78b75ecc)
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P130_94796.jpg?sign=1739936457-WQPhFenGYhFXgoyaiNRTffJ2BmPdU0L9-0-14ffccbf1741dfd6aefc727498191b1f)
这里的CglibMethodInvocation类继承了ReflectiveMethodInvocation类,CglibMethodInvocation.procceed()调用了父类的ReflectiveMethodInvocation.proceed()方法,和3.6.2节中调用的方法是相同的,此处不再赘述。