本文分析了 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#extendAdvisorsprotectedvoidextendAdvisors(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) { publicStringtoString() { returnExposeInvocationInterceptor.class.getName() +".ADVISOR"; } }; // 省略其他代码 }
从以上的代码中可以看出:
- ExposeInvocationInterceptor 是一个 MethodInterceptor 的实现类,也就是和我们之前分析过的五种增强类型对应的拦截器一样,通过
invoke
方法来实现其拦截器的逻辑。 ADVISOR
常量,其实就是一个包含了一个 ExposeInvocationInterceptor 单例对象的 DefaultPointcutAdvisor 对象。
了解了这些,我们可以得出结论,这个拦截器其实和五种增强类型对应的拦截器很相似,因此,要分析它的作用,只要看它的invoke
方法就行了。
ExposeInvocationInterceptor 的执行
下面看它的invoke
方法源码。
// org.springframework.aop.interceptor.ExposeInvocationInterceptor#invokepublicObjectinvoke(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
中。当mi
的proceed
方法执行完之后,再将invocation
中最初保存的内容还原。
因为 ExposeInvocationInterceptor 是拦截器链中第一个拦截器,因此,它的作用是,在进入拦截器执行逻辑的时候,将 MethodInvocation 方法调用对象暴露到 ThreadLocal 中,在拦截器链执行完之后再还原。根据之前的分析,我们也能知道,这里参数传入的值,就是在 JdkDynamicAopProxy 的invoke
方法中创建的 ReflectiveMethodInvocation 对象。
这也是 ExposeInvocationInterceptor 过滤器起到的作用。
总结
本文分析了 Spring AOP 拦截器链中的一个特殊拦截器 ExposeInvocationInterceptor 的注册的时机以及它的作用。至此,基于 JDK 的 AOP 代理拦截器链执行的逻辑就分析完了。