Spring 源码阅读 66:基于 JDK 的 AOP 代理如何获取拦截器链(4)- 将 Advice 封装为拦截器

简介: 【1月更文挑战第1天】本文分析了 Advice 被封装成 MethodInterceptor 的过程,Spring AOP 用到的五种 Advice 中,有些本身就是 MethodInterceptor 的实现类,而有些需要通过适配器的封装。


基于 Spring Framework v5.2.6.RELEASE

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

接上一篇:Spring 源码阅读 65:基于 JDK 的 AOP 代理如何获取拦截器链(3)- 从 Advisor 获取 Advice

概述

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

封装拦截器

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

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

MethodInterceptor 的处理

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

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

@FunctionalInterfacepublicinterfaceMethodInterceptorextendsInterceptor {
Objectinvoke(MethodInvocationinvocation) throwsThrowable;
}

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

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

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

非 MethodInterceptor 的处理

再看下一段逻辑。

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

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

privatefinalList<AdvisorAdapter>adapters=newArrayList<>(3);
publicDefaultAdvisorAdapterRegistry() {
registerAdvisorAdapter(newMethodBeforeAdviceAdapter());
registerAdvisorAdapter(newAfterReturningAdviceAdapter());
registerAdvisorAdapter(newThrowsAdviceAdapter());
}

结合成员变量的初始化,和构造方法中的逻辑可以看到,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@OverridepublicbooleansupportsAdvice(Adviceadvice) {
return (adviceinstanceofMethodBeforeAdvice);
}

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

// org.springframework.aop.framework.adapter.MethodBeforeAdviceAdapter#getInterceptor@OverridepublicMethodInterceptorgetInterceptor(Advisoradvisor) {
MethodBeforeAdviceadvice= (MethodBeforeAdvice) advisor.getAdvice();
returnnewMethodBeforeAdviceInterceptor(advice);
}

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

我们看一下 MethodBeforeAdviceInterceptor 的定义。

publicclassMethodBeforeAdviceInterceptorimplementsMethodInterceptor, BeforeAdvice, Serializable {
privatefinalMethodBeforeAdviceadvice;
publicMethodBeforeAdviceInterceptor(MethodBeforeAdviceadvice) {
Assert.notNull(advice, "Advice must not be null");
this.advice=advice;
   }
@OverridepublicObjectinvoke(MethodInvocationmi) throwsThrowable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
returnmi.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方法的下一个重要逻辑,就是增强逻辑的执行。

目录
相关文章
|
3天前
|
安全 前端开发 Java
JDK源码级别彻底剖析JVM类加载机制
JDK源码级别彻底剖析JVM类加载机制
|
3天前
|
Java Spring
Spring 源码阅读 72:基于 CGLIB 的 AOP 代理的原理(2)- 拦截器的查找与执行
【1月更文挑战第7天】本文分析了基于 CGLIB 的 AOP 代理如何查找和执行拦截器链,其主要的逻辑在 DynamicAdvisedInterceptor 的intercept方法执行。
35 1
|
1天前
|
前端开发 Java 编译器
详解Spring与JDK注入
依赖注入是Spring框架的核心概念之一,它通过将对象之间的依赖关系外部化,实现了松耦合和可测试性。面向切面编程则允许开发人员将横切关注点(如日志、事务管理)从应用程序的主要业务逻辑中分离出来,以提高代码的模块化和可维护性。
9 4
|
3天前
|
Java Spring
Spring 源码阅读 71:基于 CGLIB 的 AOP 代理的原理(1)- DynamicAdvisedInterceptor 分析
【1月更文挑战第6天】本文分析了基于 CGLIB 的 AOP 代理对象,是通过一个 DynamicAdvisedInterceptor 类型的 Callback 来完成 AOP 增强逻辑处理的,DynamicAdvisedInterceptor 通过实现 MethodInterceptor 接口的intercept方法来处理 AOP 增强逻辑。下一篇,将重点分析这个方法的原理。
58 7
|
3天前
|
算法 Java 索引
【数据结构与算法】4、双向链表(学习 jdk 的 LinkedList 部分源码)
【数据结构与算法】4、双向链表(学习 jdk 的 LinkedList 部分源码)
35 0
|
3天前
|
设计模式 Java
根据JDK源码Calendar来看工厂模式和建造者模式
根据JDK源码Calendar来看工厂模式和建造者模式
|
3天前
|
设计模式 安全 Java
深入理解Spring Boot AOP:CGLIB代理与JDK动态代理的完全指南
深入理解Spring Boot AOP:CGLIB代理与JDK动态代理的完全指南
403 1
|
3天前
|
设计模式 Java Spring
Spring AOP基础之代理模式.静态代理和动态代理
Spring AOP基础之代理模式.静态代理和动态代理
31 0
Spring AOP基础之代理模式.静态代理和动态代理
|
3天前
|
Java Linux iOS开发
Spring5源码(27)-静态代理模式和JDK、CGLIB动态代理
Spring5源码(27)-静态代理模式和JDK、CGLIB动态代理
24 0
|
3天前
|
XML Java 数据格式
Spring 源码阅读 70:基于 JDK 的 AOP 代理拦截器链执行(4)- 容易被忽略的 ExposeInvocationInterceptor
【1月更文挑战第5天】本文分析了 Spring AOP 拦截器链中的一个特殊拦截器 ExposeInvocationInterceptor 的注册的时机以及它的作用。至此,基于 JDK 的 AOP 代理拦截器链执行的逻辑就分析完了。
445 0