基于 Spring Framework v5.2.6.RELEASE
概述
上一篇,分析了 JdkDynamicAopProxy 的invoke
回调方法,根据被调用的目标方法查询拦截器链的流程,其中最重要的一部分,也就是如何从创建代理对象时配置的 Advisor 列表中找到与当前目标方法匹配的拦截器,单独放到本文中尽心分析。为了内容的完整性和连贯性,建议从之前的文章开始阅读。
获取拦截器链
我们接着分析之前,再看一下 DefaultAdvisorChainFactory 的getInterceptorsAndDynamicInterceptionAdvice
方法。
在上一篇中,已经分析过了方法开头的几个局部变量,接下来进入核心的步骤,也就是for
循环的部分,它的大致接口是这样的。
for (Advisoradvisor : advisors) { if (advisorinstanceofPointcutAdvisor) { // Add it conditionally.PointcutAdvisorpointcutAdvisor= (PointcutAdvisor) advisor; // 处理逻辑 } elseif (advisorinstanceofIntroductionAdvisor) { IntroductionAdvisoria= (IntroductionAdvisor) advisor; // 处理逻辑 } else { // 处理逻辑 } }
对于advisor
列表中的每一个 Advisor,都会先对其进行具体实现类型的判断,在根据不同的类型,执行不同的逻辑。其中, PointcutAdvisor 是我们最常见也是比较重要的类型。
先看 PointcutAdvisor 部分的逻辑。
if (advisorinstanceofPointcutAdvisor) { // Add it conditionally.PointcutAdvisorpointcutAdvisor= (PointcutAdvisor) advisor; if (config.isPreFiltered() ||pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) { MethodMatchermm=pointcutAdvisor.getPointcut().getMethodMatcher(); booleanmatch; if (mminstanceofIntroductionAwareMethodMatcher) { if (hasIntroductions==null) { hasIntroductions=hasMatchingIntroductions(advisors, actualClass); } match= ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions); } else { match=mm.matches(method, actualClass); } if (match) { MethodInterceptor[] interceptors=registry.getInterceptors(advisor); if (mm.isRuntime()) { // Creating a new object instance in the getInterceptors() method// isn't a problem as we normally cache created chains.for (MethodInterceptorinterceptor : interceptors) { interceptorList.add(newInterceptorAndDynamicMethodMatcher(interceptor, mm)); } } else { interceptorList.addAll(Arrays.asList(interceptors)); } } } }
其中,前半部分逻辑,是对 Advisor 进行筛选,如果与当前目标方法匹配, 那么,会将match
的值设置为true
,后半部分针对match
为true
的情况,也就是匹配成功的情况,根据 Advisor 获取拦截器列表并添加到最终的结果列表中。下面进行详细的分析。
为目标方法匹配增强逻辑
首先,将 Advisor 强转为 PointcutAdvisor 类型之后,有一个if判断,只有符合条件的 Advisor 才会进行处理。判断条件有两个,符合其一即可。第一个是config
的preFiltered
属性,这个属性是初始化 ProxyFactory 时设置的,值为true
(参考 Spring 源码阅读 58:配置 ProxyFactory 的 Advisor 列表 最后一节)。如果这个值为false
,第二个判断条件会判断当前的 PointcutAdvisor 的切入点是否和当前调用的目标方法的类型匹配。
匹配相关的逻辑,在之前的代理对象创建过程的分析中已经介绍过了,这里不再作为分析的重点。
符合上述条件之后,会创建一个用于匹配方法的 MethodMatcher,后续的核心逻辑就是通过它的matches
方法,判断当前调用的目标方法是否与 PointcutAdvisor 匹配。如果匹配的话,match
的值会被设置为true
。
对匹配的增强进行处理
匹配完之后,match
为true
的情况下,还需要对 Advisor 进行处理,处理的第一步就是调用registry的getInterceptors
方法,获取 Advisor 对应的拦截器列表。这里的registry
上一篇中介绍过了,它是一个全局单例的 DefaultAdvisorAdapterRegistry 对象。
获取到拦截器列表之后,会根据 MethodMatcher 是否是动态的,来决定是否将拦截器封装为 InterceptorAndDynamicMethodMatcher,最终添加到结果列表中。InterceptorAndDynamicMethodMatcher 会包含拦截器和 MethodMatcher。
MethodMatcher 是动态的,指的是即使此处match
方法返回true
,也需要在拦截器被执行时再次通过match
方法匹配,也就是这里的匹配条件是动态的。
IntroductionAdvisor 和其他情况的处理
上面我们分析的是 PointcutAdvisor 类型的增强的处理,之后还有两种情况的处理。
elseif (advisorinstanceofIntroductionAdvisor) { IntroductionAdvisoria= (IntroductionAdvisor) advisor; if (config.isPreFiltered() ||ia.getClassFilter().matches(actualClass)) { Interceptor[] interceptors=registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } else { Interceptor[] interceptors=registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); }
对这两者的执行逻辑,从 PointcutAdvisor 的处理过程中都能找到相同的步骤,在此就不进行详细的分析了。如果 Advisor 是 IntroductionAdvisor 类型,则判断其是否能与当前被调用的方法的类型匹配,通过匹配的 Advisor 获取到拦截器列表,并添加到最终的记过列表中。而对于除 PointcutAdvisor 和 IntroductionAdvisor 的其他情况,则直接获取拦截器列表,放入最终的结果列表中。
getInterceptors 方法
以上三种情况的处理逻辑中,除了想最终结果列表中添加拦截器之外,还有一个相同的步骤,就是通过registry
的getInterceptors
方法,根据 Advisor 获取拦截器列表。这也是一个值得深入分析的部分,对这个方法的分析,会放到下一篇中。
总结
本文分析了如何从代理对象的 Advisor 列表中,获取到与当前被调用的目标方法匹配的拦截器链,其中涉及到了 PointcutAdvisor 和 IntroductionAdvisor 类型的 Advisor 的处理,以及切点与类和方法的匹配。下一篇,将分析如何从 Advisor 中获取到拦截器链。