【Spring6源码・AOP】AOP源码解析

上一篇《【Spring6源码・AOP】代理对象的创建》,我们知道了代理是如何创建的,那么它又是如何工作的呢?

创建完代理对象之后,最终,会真正的执行我们的目标方法,但是步入该方法,会进入cglib代理类的拦截方法。

【Spring6源码・AOP】AOP源码解析_第1张图片

进入cglib代理类
【Spring6源码・AOP】AOP源码解析_第2张图片

进入拦截方法之后,首先获取拦截器链, 这里面就是我们切面类中定义的前置 后置 环绕的配置,还有一个是默认的。

【Spring6源码・AOP】AOP源码解析_第3张图片
看看是如何获取这些拦截器的,先从缓存里取,如果缓存没有调用getInterceptorsAndDynamicInterceptionAdvice() 方法去获取。
【Spring6源码・AOP】AOP源码解析_第4张图片

步入getInterceptorsAndDynamicInterceptionAdvice() 方法,首先获取切面相关的通知配置,初始化拦截器List集合。

【Spring6源码・AOP】AOP源码解析_第5张图片

紧接着在这个方法中,对advisors数组,进行循环遍历进行处理。

首先判断当前方法是否和我们切点中配置的方法相匹配。

【Spring6源码・AOP】AOP源码解析_第6张图片
如果匹配,则调用registry.getInterceptors方法将 advice 转化为 intercepter。

让我们看看是如何进行转换的,步入registry.getInterceptors方法,初始化拦截器集合,获取Advice【切面相关的配置】,对适配器进行循环,找到符合的拦截器,然后加入我们初始化好的拦截器List集合中,

private final List<AdvisorAdapter> adapters = new ArrayList<>(3);

如果适配器支持解析出来的advice,那么就会将advisor解析成拦截器,就 是86行的代码,adapter.getIntercepter();
【Spring6源码・AOP】AOP源码解析_第7张图片

步入adapter.getIntercepter()方法,每个适配器都会对应自己的拦截器。

【Spring6源码・AOP】AOP源码解析_第8张图片

得到拦截器之后,放到缓存中,以供下次使用。

【Spring6源码・AOP】AOP源码解析_第9张图片

就此,得到了想要的拦截器chain,最后创建CglibMethodInvocation对象,调用该对象的proceed()方法。
【Spring6源码・AOP】AOP源码解析_第10张图片
来看一下CglibMethodInvocation的proceed()方法。

【Spring6源码・AOP】AOP源码解析_第11张图片
最终来到如下方法,最后调用184行代码,去调用该拦截器:
【Spring6源码・AOP】AOP源码解析_第12张图片

步入proceed()方法:

【Spring6源码・AOP】AOP源码解析_第13张图片

调用其父类的proceed()方法:
【Spring6源码・AOP】AOP源码解析_第14张图片

调用invoke()方法:
【Spring6源码・AOP】AOP源码解析_第15张图片

继续…

【Spring6源码・AOP】AOP源码解析_第16张图片

go on…太深了
【Spring6源码・AOP】AOP源码解析_第17张图片

最后将我们所有的目标方法封住成一个Object数组作为参数:

【Spring6源码・AOP】AOP源码解析_第18张图片

这里首先通过反射机制,将方法设置为可以访问。
【Spring6源码・AOP】AOP源码解析_第19张图片

最后去调用invoke()方法:
【Spring6源码・AOP】AOP源码解析_第20张图片

invoke():
【Spring6源码・AOP】AOP源码解析_第21张图片
最终,根据我们的切面以及目标方法进行相关处理。

最后通过invoke0( )方法去调用本地方法,进而去调用切面中around()方法。

【Spring6源码・AOP】AOP源码解析_第22张图片

调用aroud方法
【Spring6源码・AOP】AOP源码解析_第23张图片

p.proceed() 方法前的操作都执行完之后,会调用该方法。
【Spring6源码・AOP】AOP源码解析_第24张图片

步入该proceed方法。。。省略若干调用。。。最终调用invoke()方法:
【Spring6源码・AOP】AOP源码解析_第25张图片
注意一下这里:this.interceptorsAndDymamicMethodMatchers这个缓存实际上存放了所有的和切面相关的拦截器,并且在初始化的时候是按排序存放的:环绕的前置、before、【目标方法】after、环绕的后置。

并且每次从缓存中取的时候,索引都会+1,这样就可以递归该方法,而且可以按顺序调用每一个拦截器。

【Spring6源码・AOP】AOP源码解析_第26张图片

不信你看看
【Spring6源码・AOP】AOP源码解析_第27张图片

所以,我们该执行before这个拦截器了,进入上图的invoke()方法。

【Spring6源码・AOP】AOP源码解析_第28张图片
步入before()方法,最终又到了这,设置方法的访问权限,再调用invoke。

【Spring6源码・AOP】AOP源码解析_第29张图片
最后还是调用了本地方法,去调用了切面的before方法。

【Spring6源码・AOP】AOP源码解析_第30张图片
【Spring6源码・AOP】AOP源码解析_第31张图片
完成了before的操作,才开始目标方法的调用:

【Spring6源码・AOP】AOP源码解析_第32张图片
其实到这里,我们就应该知道,下一步应该会调用after这个拦截器,在这个拦截器真正执行之前,会调用目标方法:

咱们来看看吧,截图真麻烦…

如果此时当前拦截器索引和缓存中的 size-1 相等,那么就会执行下面的方法:
【Spring6源码・AOP】AOP源码解析_第33张图片

步入该方法:

设置方法访问权限,然后invoke
【Spring6源码・AOP】AOP源码解析_第34张图片

通过反射去调用我们的目标方法:

【Spring6源码・AOP】AOP源码解析_第35张图片然后就调用了我们的目标方法:【Spring6源码・AOP】AOP源码解析_第36张图片

最后执行finally中的方法。
【Spring6源码・AOP】AOP源码解析_第37张图片
【Spring6源码・AOP】AOP源码解析_第38张图片
【Spring6源码・AOP】AOP源码解析_第39张图片

最后调用本地方法。
【Spring6源码・AOP】AOP源码解析_第40张图片
【Spring6源码・AOP】AOP源码解析_第41张图片

调用after方法。不行了,我得去吃饭了,妈妈叫我吃饭了,呜呜呜,你们自己看看,挺简单的。溜了。。。。
【Spring6源码・AOP】AOP源码解析_第42张图片

退出after的拦截器,before拦截器。。。。。。。。。

【Spring6源码・AOP】AOP源码解析_第43张图片
最后回到around方法中,继续执行后面的操作:

【Spring6源码・AOP】AOP源码解析_第44张图片

最后结束around拦截器:

【Spring6源码・AOP】AOP源码解析_第45张图片
至于这个返回值,返回的是目标方法的。

【Spring6源码・AOP】AOP源码解析_第46张图片

【Spring6源码・AOP】AOP源码解析_第47张图片
好了,好了,累死了,好像有个问题没有写,就是三级缓存相关的,明天吧,专门给三级缓存写一篇。

祝大家开心,爱你们。♥♥♥

你可能感兴趣的:(java,缓存)