Spring AOP 创建动态代理源码分析

576 阅读4分钟

从我学Spring AOP开始,我就一直有一个问题,Spring到底是如何使实现动态代理的?它到底是如何创建动态代理对象的?于是便有了这篇文章。

想了解AOP简单执行流程的jym,可以参考我的这篇文章:Spring Aop 到底做了什么? 后续我也会补上AOP执行流程详细源码分析。

前置知识

Spring中创建代理的三种场景:

1.最标准的就是bean初始化以后创建动态代理对象。

也就是在AbstractAutoProxyCreator类中 postProcessAfterInitialization方法。

after.png

2.三级缓存中创建代理对象,也可以说是循环依赖需要依赖代理对象。

我的这篇文章中也有提及Spring 循环依赖解析

也就是在SmartInstantiationAwareBeanPostProcessor接口中getEarlyBeanReference方法。 而AbstractAutoProxyCreator类继承了SmartInstantiationAwareBeanPostProcessor接口。

三级after.png

3.实例化之前创建代理对象,注意是实例化而不是初始化

如果不清楚什么是实例化还是初始化可以参考我的这篇文章Spring bean 的生命周期问题

也就是在AbstractAutowireCapableBeanFactory类中的createBean方法中的resolveBeforeInstantiation方法。 before.png

源码分析

本文中就以最常见的bean初始化以后做动态代理来做源码分析。由于涉及到的类方法对象等实在太多, 所以下面的解析尽可能的都在图片之中,这样效果可能会好些。

注:我的springboot版本2.4.3,若根据图片跟踪源码请注意。版本不同可能有所差异,但是大致思路不会有错。

入口方法wrapIfNecessary

wrap.png

下面就来分析最为重要的两个方法:

1.准备代理bean对应的切面getAdvicesAndAdvisorsForBean方法。

2.创建代理对象createProxy方法。

getAdvicesAndAdvisorsForBean 为增强bean找出它的切面

由于为代理bean准备切面的方法里面内容依旧很多,所以我也只会挑最重要的地方讲,尽量把大致的框架列出来让jym有个整体的了解,知道重要方法中做了什么。重要的细节也会补上。

找到合适的切面.png

找出切面主要方法.png

根据上图我们来逐一分析各个方法

findCandidateAdvisors 找出所有的切面

主要的方法在 AnnotationAwareAspectJAutoProxyCreator子类中

找出所有切面.png

找出所有切面2.png

找出所有切面4.png

这个方法中为每个@AspectJ切面的每个方法都创造了一个Spring的通知对象,具体的创建过程就在这个方法的 synchronized代码块中,由于不是本文讨论重点,这里就不做分析了,有兴趣的jy可以自行去阅读。

findAdvisorsThatCanApply 在所有切面中找出自己的切面

找出符合条件的切面.png

pointcut.png

至于canApply方法本文就不做详细分析了,里面大致就是通过pointcut,判断你的表达式(比如execution表达式等)是否和你的bean匹配,从而判断这个切面是不是符合bean的切面。

extendAdvisors 在通知链最前面加上一个暴露调用的通知

ext.png

ext1.png

sortAdvisors 切面排序

order.png

order2.png

总结和问题

通过上述一系列操作,找出了符合条件的增强bean的切面,且对切面都做了order层面的排序。

但是切面本来就是有自己的顺序的,比如before在最前面,after在最后面,那这些切面的排序到底是在哪里 就已经排好了呢?spring中是否有他们的默认排序?

答案当然是有的,其实在创建切面的时候spring就对切面做好了排序,还记得上面提到在 buildAspectJAdvisors方法中的synchroized关键词中创建切面对应的spring通知么?

sort.png

sort2.png

sort3.png

sort4.png

createProxy 创建代理对象

create.png

buildAdvisors 创建通知链条

create2.png

getProxy 获取代理

create3.png

createAopProxy 创建AOP代理

create4.png

getPorxy 真正的获取代理的实际对象

如果是jdk代理,直接定位到JdkDynamicAopProxy类的getProxy方法 非常好理解,就是用ProxynewProxyInstance方法来创建动态代理对象。

create7.png

如果是cglib动态代理,直接定位到ObjenesisCglibAopProxy类的getProxy方法,也就是CglibAopProxygetProxy方法。 在这个方法中会去调用cglib真正的创建cglib动态代理对象。

由于笔者水平有限,对于cglib不是很了解,这部分代码真的无力详细解读,但是还是要讲一下自己的思路和几个关键点。

create5.png

首先看到入参是enhancercallbacks

call.png

上图是我在百度上随意找的一张图,但是它很好的解释了enhancer就是创建代理的核心类,而callback就是回调接口。也就是说cglib代理对象执行增强方法时会使用到callback。

直接定位到getCallbacks方法

intercept.png

intercept2.png

总结

创建动态代理这一块大致思路非常简单,但是细节依然很多,如果要深入了解还需自行阅读源码。

非常感谢能看到这里的jym。本文其实并不难理解,顺着思路应该可以明白个大概,细节部分自己也可以去阅读源码。如果有错误的地方还望各位不吝指教。

c3ff758e76ba42399f5473607ebe535b_tplv-k3u1fbpfcp-zoom-in-crop-mark_3024_0_0_0.webp