上一篇《【Spring6源码・AOP】代理对象的创建》,我们知道了代理是如何创建的,那么它又是如何工作的呢?
创建完代理对象之后,最终,会真正的执行我们的目标方法,但是步入该方法,会进入cglib代理类的拦截方法。
进入cglib代理类
进入拦截方法之后,首先获取拦截器链, 这里面就是我们切面类中定义的前置 后置 环绕的配置,还有一个是默认的。
看看是如何获取这些拦截器的,先从缓存里取,如果缓存没有调用getInterceptorsAndDynamicInterceptionAdvice() 方法去获取。
步入getInterceptorsAndDynamicInterceptionAdvice() 方法,首先获取切面相关的通知配置,初始化拦截器List集合。
紧接着在这个方法中,对advisors数组,进行循环遍历进行处理。
首先判断当前方法是否和我们切点中配置的方法相匹配。
如果匹配,则调用registry.getInterceptors方法将 advice 转化为 intercepter。
让我们看看是如何进行转换的,步入registry.getInterceptors方法,初始化拦截器集合,获取Advice【切面相关的配置】,对适配器进行循环,找到符合的拦截器,然后加入我们初始化好的拦截器List集合中,
private final List<AdvisorAdapter> adapters = new ArrayList<>(3);
如果适配器支持解析出来的advice,那么就会将advisor解析成拦截器,就 是86行的代码,adapter.getIntercepter();
步入adapter.getIntercepter()方法,每个适配器都会对应自己的拦截器。
得到拦截器之后,放到缓存中,以供下次使用。
就此,得到了想要的拦截器chain,最后创建CglibMethodInvocation对象,调用该对象的proceed()方法。
来看一下CglibMethodInvocation的proceed()方法。
最终来到如下方法,最后调用184行代码,去调用该拦截器:
步入proceed()方法:
调用其父类的proceed()方法:
调用invoke()方法:
继续…
go on…太深了
最后将我们所有的目标方法封住成一个Object数组作为参数:
这里首先通过反射机制,将方法设置为可以访问。
最后去调用invoke()方法:
invoke():
最终,根据我们的切面以及目标方法进行相关处理。
最后通过invoke0( )方法去调用本地方法,进而去调用切面中around()方法。
调用aroud方法
在 p.proceed() 方法前的操作都执行完之后,会调用该方法。
步入该proceed方法。。。省略若干调用。。。最终调用invoke()方法:
注意一下这里:this.interceptorsAndDymamicMethodMatchers这个缓存实际上存放了所有的和切面相关的拦截器,并且在初始化的时候是按排序存放的:环绕的前置、before、【目标方法】after、环绕的后置。
并且每次从缓存中取的时候,索引都会+1,这样就可以递归该方法,而且可以按顺序调用每一个拦截器。
不信你看看
所以,我们该执行before这个拦截器了,进入上图的invoke()方法。
步入before()方法,最终又到了这,设置方法的访问权限,再调用invoke。
最后还是调用了本地方法,去调用了切面的before方法。
完成了before的操作,才开始目标方法的调用:
其实到这里,我们就应该知道,下一步应该会调用after这个拦截器,在这个拦截器真正执行之前,会调用目标方法:
咱们来看看吧,截图真麻烦…
如果此时当前拦截器索引和缓存中的 size-1 相等,那么就会执行下面的方法:
步入该方法:
设置方法访问权限,然后invoke
通过反射去调用我们的目标方法:
然后就调用了我们的目标方法:
最后执行finally中的方法。
最后调用本地方法。
调用after方法。不行了,我得去吃饭了,妈妈叫我吃饭了,呜呜呜,你们自己看看,挺简单的。🆒溜了。。。。
退出after的拦截器,before拦截器。。。。。。。。。
最后回到around方法中,继续执行后面的操作:
最后结束around拦截器:
至于这个返回值,返回的是目标方法的。
好了,好了,累死了,好像有个问题没有写,就是三级缓存相关的,明天吧,专门给三级缓存写一篇。
祝大家开心,爱你们。♥♥♥