Spring 源码阅读 70:基于 JDK 的 AOP 代理拦截器链执行(4)- 容易被忽略的 ExposeInvocationInterceptor

简介: 【1月更文挑战第5天】本文分析了 Spring AOP 拦截器链中的一个特殊拦截器 ExposeInvocationInterceptor 的注册的时机以及它的作用。至此,基于 JDK 的 AOP 代理拦截器链执行的逻辑就分析完了。

本文分析了 Spring AOP 拦截器链中的一个特殊拦截器 ExposeInvocationInterceptor 的注册的时机以及它的作用。至此,基于 JDK 的 AOP 代理拦截器链执行的逻辑就分析完了。

基于 Spring Framework v5.2.6.RELEASE

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

接上一篇:Spring 源码阅读 69:基于 JDK 的 AOP 代理拦截器链执行(3)- MethodInterceptor 分析

概述

之前的三篇文章,分析了 JdkDynamicAopProxy 的invoke方法,如何获取到拦截器链,并通过 ReflectiveMethodInvocation 的proceed方法执行拦截器链的增强方法和目标方法的逻辑。在拦截器链的增强方法的执行逻辑中,分别分析了五种增强类型对应的拦截器中的invoke方法的逻辑。

但其实,在拦截器链中,还有一个不是这五种增强类型对应的拦截器,它就是 ExposeInvocationInterceptor,这个拦截器并不是与我们配置的增强方法对应的,所以很容易被忽略。

这个拦截器类型,其实我们之前的源码分析中是见过的,我们先回顾一下,它是什么时候被注册的。

ExposeInvocationInterceptor 的注册

Spring AOP 的特性,是通过在后处理器中创建目标 Bean 对象的代理对象来实现的。当 Bean 对象初始化完成之后,会在后处理器中查找与当前 Bean 对象的类型是配的增强逻辑,这个查找的逻辑是由 AbstractAdvisorAutoProxyCreator 的findEligibleAdvisors完成的。

// org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findEligibleAdvisorsprotectedList<Advisor>findEligibleAdvisors(Class<?>beanClass, StringbeanName) {
List<Advisor>candidateAdvisors=findCandidateAdvisors();
List<Advisor>eligibleAdvisors=findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors=sortAdvisors(eligibleAdvisors);
   }
returneligibleAdvisors;
}

在这个方法中,前两行代码的作用是找出 Spring 容器中所有的增强以及从这些增强中筛选出与当前 Bean 得类型匹配的增强。之后,通过extendAdvisors方法,对这个增强列表进行了扩展操作。

// org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#extendAdvisorsprotectedvoidextendAdvisors(List<Advisor>candidateAdvisors) {
}

这个方法在 AbstractAdvisorAutoProxyCreator 中是一个空方法,但是,无论是 XML 配置的切面配置,还是注解配置的切面配置,其对应的后处理器实现类,并不是 AbstractAdvisorAutoProxyCreator 本身,而是它的子类,在子类 AspectJAwareAdvisorAutoProxyCreator 中,重写了这个方法,逻辑如下。

// org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator#extendAdvisors@OverrideprotectedvoidextendAdvisors(List<Advisor>candidateAdvisors) {
AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
}

这里执行了一个方法,我们进入这个方法。

// org.springframework.aop.aspectj.AspectJProxyUtils#makeAdvisorChainAspectJCapableIfNecessarypublicstaticbooleanmakeAdvisorChainAspectJCapableIfNecessary(List<Advisor>advisors) {
// Don't add advisors to an empty list; may indicate that proxying is just not requiredif (!advisors.isEmpty()) {
booleanfoundAspectJAdvice=false;
for (Advisoradvisor : advisors) {
// Be careful not to get the Advice without a guard, as this might eagerly// instantiate a non-singleton AspectJ aspect...if (isAspectJAdvice(advisor)) {
foundAspectJAdvice=true;
break;
         }
      }
if (foundAspectJAdvice&&!advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
returntrue;
      }
   }
returnfalse;
}

可以看到这个方法的逻辑并不复杂,其主要作用是,如果之前获取到的 Advisor 列表包含符合isAspectJAdvice的判断逻辑(我们配置的增强逻辑都符合这个条件),则向列表的开头增加一个ExposeInvocationInterceptor.ADVISOR

下面我们看一下这里添加的ExposeInvocationInterceptor.ADVISOR

ExposeInvocationInterceptor 是什么

我们直接找到 ExposeInvocationInterceptor 类和ADVISOR常量的定义。

publicfinalclassExposeInvocationInterceptorimplementsMethodInterceptor, PriorityOrdered, Serializable {
/** Singleton instance of this class. */publicstaticfinalExposeInvocationInterceptorINSTANCE=newExposeInvocationInterceptor();
/*** Singleton advisor for this class. Use in preference to INSTANCE when using* Spring AOP, as it prevents the need to create a new Advisor to wrap the instance.*/publicstaticfinalAdvisorADVISOR=newDefaultPointcutAdvisor(INSTANCE) {
@OverridepublicStringtoString() {
returnExposeInvocationInterceptor.class.getName() +".ADVISOR";
      }
   };
// 省略其他代码 }

从以上的代码中可以看出:

  • ExposeInvocationInterceptor 是一个 MethodInterceptor 的实现类,也就是和我们之前分析过的五种增强类型对应的拦截器一样,通过invoke方法来实现其拦截器的逻辑。
  • ADVISOR常量,其实就是一个包含了一个 ExposeInvocationInterceptor 单例对象的 DefaultPointcutAdvisor 对象。

了解了这些,我们可以得出结论,这个拦截器其实和五种增强类型对应的拦截器很相似,因此,要分析它的作用,只要看它的invoke方法就行了。

ExposeInvocationInterceptor 的执行

下面看它的invoke方法源码。

// org.springframework.aop.interceptor.ExposeInvocationInterceptor#invoke@OverridepublicObjectinvoke(MethodInvocationmi) throwsThrowable {
MethodInvocationoldInvocation=invocation.get();
invocation.set(mi);
try {
returnmi.proceed();
   }
finally {
invocation.set(oldInvocation);
   }
}

方法中除了执行mi的proceed方法外,频繁操作了invocation成员变量,我们看一下这个它是什么。

privatestaticfinalThreadLocal<MethodInvocation>invocation=newNamedThreadLocal<>("Current AOP method invocation");

它是一个 ThreadLocal 变量。在invoke方法中,会先获取到invocation中的内容,暂存在oldInvocation变量,然后把mi放到invocation中。当miproceed方法执行完之后,再将invocation中最初保存的内容还原。

因为 ExposeInvocationInterceptor 是拦截器链中第一个拦截器,因此,它的作用是,在进入拦截器执行逻辑的时候,将 MethodInvocation 方法调用对象暴露到 ThreadLocal 中,在拦截器链执行完之后再还原。根据之前的分析,我们也能知道,这里参数传入的值,就是在 JdkDynamicAopProxy 的invoke方法中创建的 ReflectiveMethodInvocation 对象。

这也是 ExposeInvocationInterceptor 过滤器起到的作用。

总结

本文分析了 Spring AOP 拦截器链中的一个特殊拦截器 ExposeInvocationInterceptor 的注册的时机以及它的作用。至此,基于 JDK 的 AOP 代理拦截器链执行的逻辑就分析完了。

目录
相关文章
|
2月前
|
安全 前端开发 Java
JDK源码级别彻底剖析JVM类加载机制
JDK源码级别彻底剖析JVM类加载机制
|
3月前
|
Java Spring
Spring5源码(38)-SpringAop代理调用过程(二)
Spring5源码(38)-SpringAop代理调用过程(二)
29 0
|
3月前
|
Java Spring
Spring5源码(37)-SpringAop代理调用过程(一)
Spring5源码(37)-SpringAop代理调用过程(一)
23 0
|
3月前
|
缓存 Java Spring
Spring5源码(35)-SpringAop创建代理(一)
Spring5源码(35)-SpringAop创建代理(一)
22 0
|
3月前
|
Java 应用服务中间件 Spring
Spring5源码(50)-SpringMVC源码阅读环境搭建
Spring5源码(50)-SpringMVC源码阅读环境搭建
43 0
|
2月前
|
算法 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动态代理的完全指南
381 1
|
3月前
|
Java
Spring5源码(36)-SpringAop创建代理(二)
Spring5源码(36)-SpringAop创建代理(二)
45 0
|
4月前
|
设计模式 Java Spring
Spring AOP基础之代理模式.静态代理和动态代理
Spring AOP基础之代理模式.静态代理和动态代理
31 0
Spring AOP基础之代理模式.静态代理和动态代理