Spring 源码阅读 58:配置 ProxyFactory 的 Advisor 列表

简介: 本文分析了 Spring 创建 AOP 代理对象之前,初始化 ProxyFactory 对象的最后一部分逻辑,主要包含 Advisor 列表的构建。

基于 Spring Framework v5.2.6.RELEASE

接上篇:Spring 源码阅读 57:配置 ProxyFactory 的 proxyTargetClass 属性

概述

本文接着上一篇分析 Spring 创建 AOP 代理对象的createProxy方法。之前分析了 ProxyFactory 的创建、基础的配置参数,以及如何通过后处理器的配置和 Bean 类型实现的接口信息,来配置 ProxyFactory 的proxyTargetClass属性,这个属性决定了创建代理对象时是通过 JDK 动态代理的方式创建还是 CGLIB 方式创建。

构建 Advisor 列表

先回到createProxy方法的代码中。

image.png

本文开始分析下面的这部分:

Advisor[] advisors=buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);

首先,会调用buildAdvisors方法,构建一个 Advisor 列表,方法中的参数specificInterceptors就是在调用createProxy方法时传入的参数,也就是之前从 Spring 容器中找到的与当前 Bean 对象匹配的增强逻辑的集合。这里为什么还要构建一次 Advisor 的列表呢,我们进入方法查看。

buildAdvisors 方法

// org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#buildAdvisorsprotectedAdvisor[] buildAdvisors(@NullableStringbeanName, @NullableObject[] specificInterceptors) {
// Handle prototypes correctly...Advisor[] commonInterceptors=resolveInterceptorNames();
List<Object>allInterceptors=newArrayList<>();
if (specificInterceptors!=null) {
allInterceptors.addAll(Arrays.asList(specificInterceptors));
if (commonInterceptors.length>0) {
if (this.applyCommonInterceptorsFirst) {
allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
         }
else {
allInterceptors.addAll(Arrays.asList(commonInterceptors));
         }
      }
   }
if (logger.isTraceEnabled()) {
intnrOfCommonInterceptors=commonInterceptors.length;
intnrOfSpecificInterceptors= (specificInterceptors!=null?specificInterceptors.length : 0);
logger.trace("Creating implicit proxy for bean '"+beanName+"' with "+nrOfCommonInterceptors+" common interceptors and "+nrOfSpecificInterceptors+" specific interceptors");
   }
Advisor[] advisors=newAdvisor[allInterceptors.size()];
for (inti=0; i<allInterceptors.size(); i++) {
advisors[i] =this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
   }
returnadvisors;
}

先整体看一下这个方法的流程。首先,通过resolveInterceptorNames方法得到一个 Advisor 列表commonInterceptors,名称翻译过来就是普通拦截器。然后,将commonInterceptorsspecificInterceptors都添加到实现声明的allInterceptors。最后,遍历allInterceptors中的元素,通过调用成员变量advisorAdapterRegistrywrap方法处理成 Advisor 对象后,得到方法最终的结果。

接下来详细分析,先进入resolveInterceptorNames方法查看。

// org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#resolveInterceptorNamesprivateAdvisor[] resolveInterceptorNames() {
BeanFactorybf=this.beanFactory;
ConfigurableBeanFactorycbf= (bfinstanceofConfigurableBeanFactory? (ConfigurableBeanFactory) bf : null);
List<Advisor>advisors=newArrayList<>();
for (StringbeanName : this.interceptorNames) {
if (cbf==null||!cbf.isCurrentlyInCreation(beanName)) {
Assert.state(bf!=null, "BeanFactory required for resolving interceptor names");
Objectnext=bf.getBean(beanName);
advisors.add(this.advisorAdapterRegistry.wrap(next));
      }
   }
returnadvisors.toArray(newAdvisor[0]);
}

这个方法中,会根据interceptorNames成员变量中保存的每一个拦截器名称,找到容器中对应的 Bean 实例,经过advisorAdapterRegistrywrap方法的处理,得到最终返回的 Advisor 列表。

再看一下interceptorNames里有什么:

/** Default is no common interceptors. */privateString[] interceptorNames=newString[0];

可以看到,默认情况下这个数组是空的,并且advisorAdapterRegistrywrap方法我们后面还会分析到,所以resolveInterceptorNames方法就分析到这里。

回到buildAdvisors方法中,接着往下看。

接下来,会将commonInterceptorsspecificInterceptors合并为一个allInterceptors列表,合并时会进行判断,如果成员变量applyCommonInterceptorsFirst的值时true,则将commonInterceptors添加到allInterceptors头部,否则添加到尾部。这个属性的默认值是true

方法的最后,会通过成员变量advisorAdapterRegistrywrap方法来处理allInterceptors里的每一个拦截器。

advisorAdapterRegistry.wrap 方法

我们进入wrap方法。

@OverridepublicAdvisorwrap(ObjectadviceObject) throwsUnknownAdviceTypeException {
if (adviceObjectinstanceofAdvisor) {
return (Advisor) adviceObject;
   }
if (!(adviceObjectinstanceofAdvice)) {
thrownewUnknownAdviceTypeException(adviceObject);
   }
Adviceadvice= (Advice) adviceObject;
if (adviceinstanceofMethodInterceptor) {
// So well-known it doesn't even need an adapter.returnnewDefaultPointcutAdvisor(advice);
   }
for (AdvisorAdapteradapter : this.adapters) {
// Check that it is supported.if (adapter.supportsAdvice(advice)) {
returnnewDefaultPointcutAdvisor(advice);
      }
   }
thrownewUnknownAdviceTypeException(advice);
}

这个方法的逻辑比较简单,作用是将参数传入的拦截器对象(也就是上一步allInterceptors集合中的每一个元素)封装成 Advisor 对象。

如果当前操作的拦截器类型本身就是 Advisor 的实现类,那么,将其原样返回即可。如果它不是 Advisor 的实现类,那么在判断它是否是 Advice 的实现类,如果不是,则抛出异常,也就是说,它只能是 Advisor 或者 Advice 的实现类。

之后就是 Advice 的情况。先判断它是不是 MethodInterceptor 的实现类,MethodInterceptor 是 Advice 的子接口,如果是 MethodInterceptor 的实现类的话,则将其封装为 DefaultPointcutAdvisor 返回。

最后,对于是 Advice 实现类,但不是 MethodInterceptor 实现类的情况,在进行下面的逻辑处理。

遍历adapters成员变量中的每一个元素adapteradapters中的内容可以从以下代码中看到:

privatefinalList<AdvisorAdapter>adapters=newArrayList<>(3);
/*** Create a new DefaultAdvisorAdapterRegistry, registering well-known adapters.*/publicDefaultAdvisorAdapterRegistry() {
registerAdvisorAdapter(newMethodBeforeAdviceAdapter());
registerAdvisorAdapter(newAfterReturningAdviceAdapter());
registerAdvisorAdapter(newThrowsAdviceAdapter());
}
@OverridepublicvoidregisterAdvisorAdapter(AdvisorAdapteradapter) {
this.adapters.add(adapter);
}

初始状态下,这里有三个 Advice 适配器。在遍历过程中对正在处理的 Advice 类型的拦截器,调用adaptersupportsAdvice方法,判断遍历到的适配器是不是与当前的拦截器适配,如果得到结果true,则将拦截器封装为 DefaultPointcutAdvisor 返回。如果adapters中没有能够预知适配的适配器,则表示无法将当前的拦截器包装成 Advisor,会在wrap方法的最后抛出异常。

其实适配器的supportsAdvice方法就是判断拦截器的类型。

介绍完wrap方法,buildAdvisors方法的全部流程也就介绍完了。在createProxy方法中,buildAdvisors的结果会被添加到proxyFactoryadvisors结合中。

接下来,还将目标类型targetSource赋值给了proxyFactory的相应属性。

customizeProxyFactory 方法

设置完advisorstargetSource属性之后,执行了customizeProxyFactory方法。但这个方法是一个空方法。

protectedvoidcustomizeProxyFactory(ProxyFactoryproxyFactory) {
}

可以看出来,这是一个扩展点,通过在子类中重写这个方法,可以在 ProxyFactory 工厂对象的重要属性都配置完之后,在对其进行自定义的处理。

后续的步骤

接下来再看下一个代码片段。

proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}

这里又给proxyFactory配置了两个属性,其中if语句的判断条件中advisorsPreFiltered需要留意。

// org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#advisorsPreFilteredprotectedbooleanadvisorsPreFiltered() {
returnfalse;
}

在 AbstractAutoProxyCreator 中,这个方法返回了false。但是,我们这里用到的创建 AOP 代理的后处理器,并不是 AbstractAutoProxyCreator 类型,而是它的子类,所以需要找到子类中与具体实现类关系最近的类中的方法实现。可以找到 AbstractAdvisorAutoProxyCreator 找到重写的方法实现,返回的是true

// org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#advisorsPreFiltered@OverrideprotectedbooleanadvisorsPreFiltered() {
returntrue;
}

createProxy方法的最后,返回了通过调用proxyFactory的getProxy方法创建的代理对象。

returnproxyFactory.getProxy(getProxyClassLoader());

具体的创建代理对象的原理,放到下篇文章中分析。

总结

本文分析了 Spring 创建 AOP 代理对象之前,初始化 ProxyFactory 对象的最后一部分逻辑,主要包含 Advisor 列表的构建。至此,可以看出,ProxyFactory 创建代理对象之前,最重要的配置内容就是创建代理对象的方式(JDK 动态代理或 CGLIB)以及增强逻辑的集合,接下来就进入了最后创建代理对象的过程。


目录
相关文章
|
11天前
|
存储 Java 数据安全/隐私保护
|
5天前
|
Java 微服务 Spring
Spring Boot中获取配置参数的几种方法
Spring Boot中获取配置参数的几种方法
17 2
|
7天前
|
消息中间件 安全 Java
在Spring Bean中,如何通过Java配置类定义Bean?
【4月更文挑战第30天】在Spring Bean中,如何通过Java配置类定义Bean?
16 1
|
8天前
|
Java 开发者 Spring
Spring Boot中的资源文件属性配置
【4月更文挑战第28天】在Spring Boot应用程序中,配置文件是管理应用程序行为的重要组成部分。资源文件属性配置允许开发者在不重新编译代码的情况下,对应用程序进行灵活地配置和调整。本篇博客将介绍Spring Boot中资源文件属性配置的基本概念,并通过实际示例展示如何利用这一功能。
20 1
|
12天前
|
Java Spring 容器
如何用基于 Java 配置的方式配置 Spring?
如何用基于 Java 配置的方式配置 Spring?
|
12天前
|
存储 前端开发 Java
第十一章 Spring Cloud Alibaba nacos配置中心
第十一章 Spring Cloud Alibaba nacos配置中心
19 0
|
17天前
|
存储 安全 Java
第2章 Spring Security 的环境设置与基础配置(2024 最新版)(下)
第2章 Spring Security 的环境设置与基础配置(2024 最新版)(下)
22 0
|
5月前
|
XML Java uml
spring 源码解析——第一篇(ioc xml方式)
spring 源码解析——第一篇(ioc xml方式)
33 0
|
4月前
|
安全 Java 应用服务中间件
阿里技术官架构使用总结:Spring+MyBatis源码+Tomcat架构解析等
分享Java技术文以及学习经验也有一段时间了,实际上作为程序员,我们都清楚学习的重要性,毕竟时代在发展,互联网之下,稍有一些落后可能就会被淘汰掉,因此我们需要不断去审视自己,通过学习来让自己得到相应的提升。
|
7月前
|
Java 应用服务中间件 Spring
66Spring - 源码解析Spring的启动机制(contextConfigLocation)
66Spring - 源码解析Spring的启动机制(contextConfigLocation)
38 0