Spring 源码阅读 64:基于 JDK 的 AOP 代理如何获取拦截器链(2)- Advisor 与目标方法的匹配

简介: 本文分析了如何从代理对象的 Advisor 列表中,获取到与当前被调用的目标方法匹配的拦截器链,其中涉及到了 PointcutAdvisor 和 IntroductionAdvisor 类型的 Advisor 的处理,以及切点与类和方法的匹配。

基于 Spring Framework v5.2.6.RELEASE

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

接上一篇:Spring 源码阅读 63:基于 JDK 的 AOP 代理如何获取拦截器链(1)- 拦截器链的来源

概述

上一篇,分析了 JdkDynamicAopProxy 的invoke回调方法,根据被调用的目标方法查询拦截器链的流程,其中最重要的一部分,也就是如何从创建代理对象时配置的 Advisor 列表中找到与当前目标方法匹配的拦截器,单独放到本文中尽心分析。为了内容的完整性和连贯性,建议从之前的文章开始阅读。

获取拦截器链

我们接着分析之前,再看一下 DefaultAdvisorChainFactory 的getInterceptorsAndDynamicInterceptionAdvice方法。

在上一篇中,已经分析过了方法开头的几个局部变量,接下来进入核心的步骤,也就是for循环的部分,它的大致接口是这样的。

for (Advisoradvisor : advisors) {
if (advisorinstanceofPointcutAdvisor) {
// Add it conditionally.PointcutAdvisorpointcutAdvisor= (PointcutAdvisor) advisor;
// 处理逻辑   }
elseif (advisorinstanceofIntroductionAdvisor) {
IntroductionAdvisoria= (IntroductionAdvisor) advisor;
// 处理逻辑   }
else {
// 处理逻辑   }
}

对于advisor列表中的每一个 Advisor,都会先对其进行具体实现类型的判断,在根据不同的类型,执行不同的逻辑。其中, PointcutAdvisor 是我们最常见也是比较重要的类型。

先看 PointcutAdvisor 部分的逻辑。

if (advisorinstanceofPointcutAdvisor) {
// Add it conditionally.PointcutAdvisorpointcutAdvisor= (PointcutAdvisor) advisor;
if (config.isPreFiltered() ||pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodMatchermm=pointcutAdvisor.getPointcut().getMethodMatcher();
booleanmatch;
if (mminstanceofIntroductionAwareMethodMatcher) {
if (hasIntroductions==null) {
hasIntroductions=hasMatchingIntroductions(advisors, actualClass);
         }
match= ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
      }
else {
match=mm.matches(method, actualClass);
      }
if (match) {
MethodInterceptor[] interceptors=registry.getInterceptors(advisor);
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method// isn't a problem as we normally cache created chains.for (MethodInterceptorinterceptor : interceptors) {
interceptorList.add(newInterceptorAndDynamicMethodMatcher(interceptor, mm));
            }
         }
else {
interceptorList.addAll(Arrays.asList(interceptors));
         }
      }
   }
}

其中,前半部分逻辑,是对 Advisor 进行筛选,如果与当前目标方法匹配, 那么,会将match的值设置为true,后半部分针对matchtrue的情况,也就是匹配成功的情况,根据 Advisor 获取拦截器列表并添加到最终的结果列表中。下面进行详细的分析。

为目标方法匹配增强逻辑

首先,将 Advisor 强转为 PointcutAdvisor 类型之后,有一个if判断,只有符合条件的 Advisor 才会进行处理。判断条件有两个,符合其一即可。第一个是configpreFiltered属性,这个属性是初始化 ProxyFactory 时设置的,值为true(参考 Spring 源码阅读 58:配置 ProxyFactory 的 Advisor 列表 最后一节)。如果这个值为false,第二个判断条件会判断当前的 PointcutAdvisor 的切入点是否和当前调用的目标方法的类型匹配。

匹配相关的逻辑,在之前的代理对象创建过程的分析中已经介绍过了,这里不再作为分析的重点。

符合上述条件之后,会创建一个用于匹配方法的 MethodMatcher,后续的核心逻辑就是通过它的matches方法,判断当前调用的目标方法是否与 PointcutAdvisor 匹配。如果匹配的话,match的值会被设置为true

对匹配的增强进行处理

匹配完之后,matchtrue的情况下,还需要对 Advisor 进行处理,处理的第一步就是调用registry的getInterceptors方法,获取 Advisor 对应的拦截器列表。这里的registry上一篇中介绍过了,它是一个全局单例的 DefaultAdvisorAdapterRegistry 对象。

获取到拦截器列表之后,会根据 MethodMatcher 是否是动态的,来决定是否将拦截器封装为 InterceptorAndDynamicMethodMatcher,最终添加到结果列表中。InterceptorAndDynamicMethodMatcher 会包含拦截器和 MethodMatcher。

MethodMatcher 是动态的,指的是即使此处match方法返回true,也需要在拦截器被执行时再次通过match方法匹配,也就是这里的匹配条件是动态的。

IntroductionAdvisor 和其他情况的处理

上面我们分析的是 PointcutAdvisor 类型的增强的处理,之后还有两种情况的处理。

elseif (advisorinstanceofIntroductionAdvisor) {
IntroductionAdvisoria= (IntroductionAdvisor) advisor;
if (config.isPreFiltered() ||ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors=registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
   }
}
else {
Interceptor[] interceptors=registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}

对这两者的执行逻辑,从 PointcutAdvisor 的处理过程中都能找到相同的步骤,在此就不进行详细的分析了。如果 Advisor 是 IntroductionAdvisor 类型,则判断其是否能与当前被调用的方法的类型匹配,通过匹配的 Advisor 获取到拦截器列表,并添加到最终的记过列表中。而对于除 PointcutAdvisor 和 IntroductionAdvisor 的其他情况,则直接获取拦截器列表,放入最终的结果列表中。

getInterceptors 方法

以上三种情况的处理逻辑中,除了想最终结果列表中添加拦截器之外,还有一个相同的步骤,就是通过registrygetInterceptors方法,根据 Advisor 获取拦截器列表。这也是一个值得深入分析的部分,对这个方法的分析,会放到下一篇中。

总结

本文分析了如何从代理对象的 Advisor 列表中,获取到与当前被调用的目标方法匹配的拦截器链,其中涉及到了 PointcutAdvisor 和 IntroductionAdvisor 类型的 Advisor 的处理,以及切点与类和方法的匹配。下一篇,将分析如何从 Advisor 中获取到拦截器链。

目录
相关文章
|
4月前
|
Java Spring
Spring 源码阅读 72:基于 CGLIB 的 AOP 代理的原理(2)- 拦截器的查找与执行
【1月更文挑战第7天】本文分析了基于 CGLIB 的 AOP 代理如何查找和执行拦截器链,其主要的逻辑在 DynamicAdvisedInterceptor 的intercept方法执行。
35 1
|
3月前
|
Java 应用服务中间件 Spring
Spring5源码(50)-SpringMVC源码阅读环境搭建
Spring5源码(50)-SpringMVC源码阅读环境搭建
43 0
|
4月前
|
Java Spring
Spring 源码阅读 71:基于 CGLIB 的 AOP 代理的原理(1)- DynamicAdvisedInterceptor 分析
【1月更文挑战第6天】本文分析了基于 CGLIB 的 AOP 代理对象,是通过一个 DynamicAdvisedInterceptor 类型的 Callback 来完成 AOP 增强逻辑处理的,DynamicAdvisedInterceptor 通过实现 MethodInterceptor 接口的intercept方法来处理 AOP 增强逻辑。下一篇,将重点分析这个方法的原理。
56 7
|
2月前
|
NoSQL 关系型数据库 MySQL
Docker安装详细步骤及相关环境安装配置(mysql、jdk、redis、自己的私有仓库Gitlab 、C和C++环境以及Nginx服务代理)
Docker安装详细步骤及相关环境安装配置(mysql、jdk、redis、自己的私有仓库Gitlab 、C和C++环境以及Nginx服务代理)
251 0
|
3月前
|
设计模式 安全 Java
深入理解Spring Boot AOP:CGLIB代理与JDK动态代理的完全指南
深入理解Spring Boot AOP:CGLIB代理与JDK动态代理的完全指南
381 1
|
4月前
|
设计模式 Java
java中的jdk代理和cglib代理
在Java中,代理是一种设计模式,它允许一个对象(代理)控制对另一个对象(真实对象)的访问。Java中的代理主要分为两种类型:JDK(Java Dynamic Proxy)代理和CGLIB(Code Generation Library)代理。
|
4月前
|
Java Linux iOS开发
Spring5源码(27)-静态代理模式和JDK、CGLIB动态代理
Spring5源码(27)-静态代理模式和JDK、CGLIB动态代理
23 0
|
4月前
|
XML Java 开发者
Spring 源码的阅读心得
【1月更文挑战第12天】最近花了很多时间去阅读Spring框架核心部分的源码,本文将分享一些阅读的思路和心得,分享给想阅读源码但是不知道如何下手或者读不下来的小伙伴。
64 1
|
4月前
|
缓存 Java Spring
Spring 源码阅读 75:@EnableAsync 分析
【1月更文挑战第10天】本文以 @EnableAsync 作为切入点,分析了 Spring 开启基于注解的异步任务特性的原理。
37 0
|
4月前
|
缓存 Java 数据库连接
Spring 源码阅读 74:BeanFactoryTransactionAttributeSourceAdvisor 分析
【1月更文挑战第9天】本文通过对 BeanFactoryTransactionAttributeSourceAdvisor 类的分析,了解了 Spring 是如何通过 AOP 来完成事务的管理的,本文的内容需要你对 Spring 的 AOP 的实现原理有一定的了解。
51 0