Spring 源码阅读 66:AOP 代理获取拦截器链时拦截器的封装

324 阅读2分钟

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

基于 Spring Framework v5.2.6.RELEASE

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

接上一篇:Spring 源码阅读 65:AOP 代理获取拦截器链时 Advice 的获取

概述

上一篇分析了从 Advisor 中获取 Advice 的过程,在得到 Advice 对象之后,还需要将它封装成拦截器,才能最终交给 JdkDynamicAopProxy 的invoke回调方法来执行其中的增强逻辑。本文的主要内容就是分析如何将 Advice 封装成拦截器,为了内容连贯性,建议从之前的文章开始阅读。

封装拦截器

先从 DefaultAdvisorAdapterRegistry 的getInterceptors方法开始入手。

通过advisorgetAdvice方法获取 Advice 对象的过程,是上一篇文章分析的主要内容,我们接着看后面的内容。

MethodInterceptor 的处理

if (advice instanceof MethodInterceptor) {
   interceptors.add((MethodInterceptor) advice);
}

得到 Advice 之后,首先判断了它是不是 MethodInterceptor 接口的对象。我们看一下 MethodInterceptor 接口的定义。

@FunctionalInterface
public interface MethodInterceptor extends Interceptor {
Object invoke(MethodInvocation invocation) throws Throwable;
}

它是一个函数式接口,包含了一个invoke方法,方法的参数对象是当前的目标方法调用。再上一步获取 Advice 的过程分析中可以知道,我们的到的 Advice 一共就 5 中,分别对应了切面配置中的五种增强类型,所以,这里可以看一下这五种类型的 Advice 哪些是实现了 MethodInterceptor 接口的。

从上面的类关系图中可以看到,AspectJAroundAdvice / AspectJAfterAdvice / AspectJAfterThrowingAdvice 三个类型的 Advice 是实现了 MethodInterceptor 接口的,因此,三个类型中也包含了invoke方法的实现,而其他两个没有。

结合getInterceptors方法的返回值类型是MethodInterceptor[],可以知道,实现了 MethodInterceptor 接口的 Advice 可以直接作为返回值数组中的元素,添加到结果数组中,因此,代码中也是这样做的,在if语句块中将其添加到了方法开头声明好的列表interceptors中。

非 MethodInterceptor 的处理

再看下一段逻辑。

for (AdvisorAdapter adapter : this.adapters) {
   if (adapter.supportsAdvice(advice)) {
      interceptors.add(adapter.getInterceptor(advisor));
   }
}

先看一下for循环条件语句中的this.adapters是什么。

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

public DefaultAdvisorAdapterRegistry() {
   registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
   registerAdvisorAdapter(new AfterReturningAdviceAdapter());
   registerAdvisorAdapter(new ThrowsAdviceAdapter());
}

结合成员变量的初始化,和构造方法中的逻辑可以看到,adapters中包含了 3 个对象,从名字可以看出他们是 Advice 相关的适配器。

从类关系图中可以看到,它们都是 AdvicorAdapter 的实现类,接口中声明了两个方法,通过接口源码中的注释,可以大概了解这两个方法的作用。

  • supportsAdvice 方法用来判断,当前的 AdvisorAdapter 类型,是否适配参数中给定的 Advice。
  • getInterceptor 的作用是通过给定的 Advisor 对象,获取一个包含 Advisor 中增强逻辑的 MethodInterceptor。

这是一个很典型的适配器模式的逻辑。通过它们的supportsAdvice方法可以知道它们适配的 Advice 类型分别是什么。

  • MethodBeforeAdviceAdapter 适配 MethodBeforeAdvice
  • AfterReturningAdviceAdapter 适配 AfterReturningAdvice
  • ThrowsAdviceAdapter 适配 ThrowsAdvice

在五个增强类型对应的 Advice 类型中,只有两个属于上述被适配的类型,分别是:

  • AspectJMethodBeforeAdvice 实现了 MethodBeforeAdvice 接口
  • AspectJAfterReturningAdvice 实现了 AfterReturningAdvice 接口

而这两个正好是没有实现 MethodInterceptor 接口的两个,也就是说,通过这一步操作,所有类型的 Advice 就都处理完了。

再回到刚刚的代码中,如果adapters中的一个元素能够适配当前的 Advice 对象,那么通过getInterceptor方法得到的 MethodInterceptor 对象,会被添加到最终结果列表interceptors中。

AdviceAdapter 适配器的原理

因为适配器的工作原理都相似,因此,下面以其中之一 MethodBeforeAdviceAdapter 来分析其工作原理。

// org.springframework.aop.framework.adapter.MethodBeforeAdviceAdapter#supportsAdvice
@Override
public boolean supportsAdvice(Advice advice) {
   return (advice instanceof MethodBeforeAdvice);
}

supportsAdvice方法的原理比较简单,就是判断当前要处理的 Advice 类型,是不是特定的 Advice 类型,如果是的话,表示当前的适配器能够适配这个类型的 Advice 对象。它主要的工作还是在getInterceptor方法中完成的。

// org.springframework.aop.framework.adapter.MethodBeforeAdviceAdapter#getInterceptor
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
   MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
   return new MethodBeforeAdviceInterceptor(advice);
}

在getInterceptor方法中,先获取到 Advisor 的getAdvice方法。在上一篇分析中,我们知道了,这里的getAdvice方法是有缓存机制的,因此不会再将封装 Advice 的过程又执行一遍,而是从缓存中读取。得到的advice是 MethodBeforeAdvice 类型,也就是通过supportsAdvice判断过适配的类型。然后再将其封装成一个 MethodBeforeAdviceInterceptor 返回。

我们看一下 MethodBeforeAdviceInterceptor 的定义。

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {
   private final MethodBeforeAdvice advice;
public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
      Assert.notNull(advice, "Advice must not be null");
      this.advice = advice;
   }
   @Override
   public Object invoke(MethodInvocation mi) throws Throwable {
      this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
      return mi.proceed();
   }

}

可以看到 MethodBeforeAdviceInterceptor 是实现了 MethodInterceptor 接口的。其实它的作用就是对 MethodBeforeAdvice 进行封装,得到一个 MethodInterceptor。

分析完了 MethodBeforeAdviceInterceptor 之后,AfterReturningAdviceAdapter 的逻辑是相似的,就不重复分析了,唯一的区别就是invoke方法中的实现不同,分别对应的不同类型的增强逻辑的执行时机不同。

返回结果

以上,就走完了getInterceptors方法的所有流程,得到一个 MethodInterceptor 的数组,结合前几篇文章分析的获取拦截器链的过程,这些 MethodInterceptor 会最终返回到 JdkDynamicAopProxy 的invoke方法中,作为以下这样代码的结果。

// Get the interception chain for this method.
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

也就是这行代码所调用的获取拦截器链的逻辑,一共写了四篇分析,欢迎阅读。

总结

本文分析了 Advice 被封装成 MethodInterceptor 的过程,Spring AOP 用到的五种 Advice 中,有些本身就是 MethodInterceptor 的实现类,而有些需要通过适配器的封装。至此,查找拦截器链的过程分析完了,接下来会分析 JdkDynamicAopProxy 的invoke方法的下一个重要逻辑,就是增强逻辑的执行。