Spring 源码阅读 63:AOP 代理获取拦截器链的来源

229 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第30天,点击查看活动详情

基于 Spring Framework v5.2.6.RELEASE

相关阅读:Spring 源码阅读 61:基于 JDK 动态代理的 AOP 代理回调方法 invoke 分析

接上一篇:Spring 源码阅读 62:基于 JDK 的 AOP 代理对特殊方法调用的处理

概述

上一篇分析了 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);

获取拦截器链的步骤,通过advisedgetInterceptorsAndDynamicInterceptionAdvice方法来完成,调用方法是需要目标类型和被调用的目标方法作为参数。这个方法声明在 AdvisedSupport 中。我们找到方法的实现。

拦截器链的缓存

// org.springframework.aop.framework.AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
   MethodCacheKey cacheKey = new MethodCacheKey(method);
   List<Object> cached = this.methodCache.get(cacheKey);
   if (cached == null) {
      cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
            this, method, targetClass);
      this.methodCache.put(cacheKey, cached);
   }
   return cached;
}

虽然方法声明的返回值是 Object 列表,但注释是这样描述的:

Determine a list of org.aopalliance.intercept.MethodInterceptor objects for the given method, based on this configuration.

也就是说,返回的是一个 MethodInterceptor 列表。

在方法体中,先通过method获取了一个cacheKey,然后到methodCache中去查找已经缓存的拦截器列表,如果有,则直接返回,如果没有,则通过advisorChainFactorygetInterceptorsAndDynamicInterceptionAdvice方法获取,然后放入缓存中再返回。

MethodCacheKey 是 AdvisedSupport 的内部类,初始化cacheKey的方法如下。

// org.springframework.aop.framework.AdvisedSupport.MethodCacheKey#MethodCacheKey
public MethodCacheKey(Method method) {
   this.method = method;
   this.hashCode = method.hashCode();
}

可以看出,这个方法核心逻辑是由getInterceptorsAndDynamicInterceptionAdvice完成的,增加缓存机制是为了确保针对每个方法查找拦截器链的逻辑只会执行一次。

这里还需要看一下调用上述方法的成员变量advisorChainFactory

 /** The AdvisorChainFactory to use. */
AdvisorChainFactory advisorChainFactory = new DefaultAdvisorChainFactory();

其实就是一个 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.
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
Advisor[] advisors = config.getAdvisors();
List<Object> interceptorList = new ArrayList<>(advisors.length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
Boolean hasIntroductions = null;

我们逐个分析这几个变量。首先是 AdvisorAdapterRegistry 类型的registry,找到 GlobalAdvisorAdapterRegistry 的getInstance方法。

 /**
* Keep track of a single instance so we can return it to classes that request it.
*/
private static AdvisorAdapterRegistry instance = new DefaultAdvisorAdapterRegistry();

/**
* Return the singleton {  @link  DefaultAdvisorAdapterRegistry} instance.
*/
public static AdvisorAdapterRegistry getInstance() {
   return instance;
}

可以看出,它是一个全局单例的 DefaultAdvisorAdapterRegistry 类型的对象个。这个单例的 DefaultAdvisorAdapterRegistry 对象其实在以前的代码分析中见过,在 AbstractAutoProxyCreator 类的buildAdvisors方法中,就曾经通过它的wrap方法来封装 Advisor。根据这里获取它的方式,可以知道这两个地方用到的是同一个对象。

言归正传,再看方法中的advisors变量,它是之前创建代理对象的时候,配置的 Advisor 列表,也是后续for循环遍历的列表。

第三个变量interceptorList是方法最终返回的结果列表,初始状态为空,在后面的for循环中会不断向这个列表中添加元素。

第四个变量actualClass是当前被调用目标方法所在的类型。

分析到这里,也可以大概猜出后续的主要逻辑,就是根据advisors中的每一个 Advisor,来得到所有的拦截器,并放入列表中返回。这一部分,是这个方法的核心逻辑,也是一块相对完整且复杂的逻辑,我会放到下一篇中单独分析。

总结

本文分析了 JdkDynamicAopProxy 在执行代理的回调逻辑时,如何根据目标方法找到其对应的拦截器链。对于 Advisor 是如何转换成 Intercepter 拦截器的,下一篇会详细分析。