本文分析了 JdkDynamicAopProxy 在执行代理的回调逻辑时,如何根据目标方法找到其对应的拦截器链。
基于 Spring Framework v5.2.6.RELEASE
概述
上一篇分析了 JdkDynamicAopProxy 的invoke
回调方法对特殊目标方法调用的处理,本文开始,会接着分析invoke
方法的下一个关键步骤,即拦截器链的获取。为保证内容的连续性,推荐先阅读文章开头列出的两篇文章。
获取拦截器链
拦截器链的获取,对应invoke
方法的下面这段代码。
// Get as late as possible to minimize the time we "own" the target,// in case it comes from a pool.target=targetSource.getTarget(); Class<?>targetClass= (target!=null?target.getClass() : null); // Get the interception chain for this method.List<Object>chain=this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
获取拦截器链的步骤,通过advised
的getInterceptorsAndDynamicInterceptionAdvice
方法来完成,调用方法是需要目标类型和被调用的目标方法作为参数。这个方法声明在 AdvisedSupport 中。我们找到方法的实现。
拦截器链的缓存
// org.springframework.aop.framework.AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvicepublicList<Object>getInterceptorsAndDynamicInterceptionAdvice(Methodmethod, Class<?>targetClass) { MethodCacheKeycacheKey=newMethodCacheKey(method); List<Object>cached=this.methodCache.get(cacheKey); if (cached==null) { cached=this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice( this, method, targetClass); this.methodCache.put(cacheKey, cached); } returncached; }
虽然方法声明的返回值是 Object 列表,但注释是这样描述的:
Determine a list of
org.aopalliance.intercept.MethodInterceptor
objects for the given method, based on this configuration.
也就是说,返回的是一个 MethodInterceptor
列表。
在方法体中,先通过method
获取了一个cacheKey
,然后到methodCache
中去查找已经缓存的拦截器列表,如果有,则直接返回,如果没有,则通过advisorChainFactory
的getInterceptorsAndDynamicInterceptionAdvice
方法获取,然后放入缓存中再返回。
MethodCacheKey 是 AdvisedSupport 的内部类,初始化cacheKey
的方法如下。
// org.springframework.aop.framework.AdvisedSupport.MethodCacheKey#MethodCacheKeypublicMethodCacheKey(Methodmethod) { this.method=method; this.hashCode=method.hashCode(); }
可以看出,这个方法核心逻辑是由getInterceptorsAndDynamicInterceptionAdvice
完成的,增加缓存机制是为了确保针对每个方法查找拦截器链的逻辑只会执行一次。
这里还需要看一下调用上述方法的成员变量advisorChainFactory
。
/** The AdvisorChainFactory to use. */AdvisorChainFactoryadvisorChainFactory=newDefaultAdvisorChainFactory();
其实就是一个 DefaultAdvisorChainFactory 类型的对象,并且没有在类中定义构造方法。因此,下面我们直接看它的getInterceptorsAndDynamicInterceptionAdvice
方法。
拦截器链的获取
方法的代码量比较大,我们先做整体结构的分析。
首先,在for循环之前的部分,定义了一些变量,这些都是后面具体的处理逻辑中需要用到的。其中,interceptorList
是方法最终的返回结果。
接下来,方法的处理逻辑都在for
循环中,for
循环遍历了创建代理对象时配置的 Advisor 列表,在循环体中,针对 Advisor 的具体类型(PointcutAdvisor 或 IntroductionAdvisor 以及其他)执行不同的处理逻辑,每一种处理逻辑的最后,都是向方法返回值interceptorList
列表中添加内容。
最终,interceptorList
作为返回值返回。
下面进入详细分析,先看方法体的第一部分。
// This is somewhat tricky... We have to process introductions first,// but we need to preserve order in the ultimate list.AdvisorAdapterRegistryregistry=GlobalAdvisorAdapterRegistry.getInstance(); Advisor[] advisors=config.getAdvisors(); List<Object>interceptorList=newArrayList<>(advisors.length); Class<?>actualClass= (targetClass!=null?targetClass : method.getDeclaringClass()); BooleanhasIntroductions=null;
我们逐个分析这几个变量。首先是 AdvisorAdapterRegistry 类型的registry
,找到 GlobalAdvisorAdapterRegistry 的getInstance
方法。
/*** Keep track of a single instance so we can return it to classes that request it.*/privatestaticAdvisorAdapterRegistryinstance=newDefaultAdvisorAdapterRegistry(); /*** Return the singleton {@link DefaultAdvisorAdapterRegistry} instance.*/publicstaticAdvisorAdapterRegistrygetInstance() { returninstance; }
可以看出,它是一个全局单例的 DefaultAdvisorAdapterRegistry 类型的对象个。这个单例的 DefaultAdvisorAdapterRegistry 对象其实在以前的代码分析中见过,在 AbstractAutoProxyCreator 类的buildAdvisors
方法中,就曾经通过它的wrap
方法来封装 Advisor。根据这里获取它的方式,可以知道这两个地方用到的是同一个对象。
言归正传,再看方法中的advisors
变量,它是之前创建代理对象的时候,配置的 Advisor 列表,也是后续for
循环遍历的列表。
第三个变量interceptorList
是方法最终返回的结果列表,初始状态为空,在后面的for
循环中会不断向这个列表中添加元素。
第四个变量actualClass
是当前被调用目标方法所在的类型。
分析到这里,也可以大概猜出后续的主要逻辑,就是根据advisors
中的每一个 Advisor,来得到所有的拦截器,并放入列表中返回。这一部分,是这个方法的核心逻辑,也是一块相对完整且复杂的逻辑,我会放到下一篇中单独分析。
总结
本文分析了 JdkDynamicAopProxy 在执行代理的回调逻辑时,如何根据目标方法找到其对应的拦截器链。对于 Advisor 是如何转换成 Intercepter 拦截器的,下一篇会详细分析。