《Spring源码深度分析》第6章 容器的功能扩展

前言

经过前面几章的分析,相信大家已经对 Spring 中的容器功能有了简单的了解,在前面的章节中我们一直以 BeanFacotry 接口以及它的默认实现类 XmlBeanFactory 为例进行分析,但是,Spring 中还提供了另一个接口
ApplicationContext,用于扩展 BeanFacotry 中现有的功能。

ApplicationContext 和 BeanFacotry 两者都是用于加载 Bean 的,但是相比之下,ApplicationContext 提供了更多的扩展功能,简单一点说:ApplicationContext 包含 BeanFactory 的所有功能。通常建议比 BeanFactory 优先,除非在一些限制的场合,比如字节长度对内存有很大的影响时(Applet )。绝大多数“典型的”企业应用和系统,ApplicationContext 就是你需要使用的。

一、ApplicationContext代码切入点

加载配置文件的方式

那么究竟 ApplicationContext 比 BeanFactory 多出了哪些功能呢?还需要我们进一步的探索。首先我们来看看使用两个不同的类去加载配置文件在写法上的不同。

使用 BeanFactory 方式加载 XML.

BeanFactory bf = new XmlBeanFactory (new ClassPathResource ("beanFactoryTest. xml”))

使用 ApplicationContext 方式加载 XML.

ApplicationContext bf = new ClassPathXmlApplicationcontext ("beanFactoryTest. xml")

代码切入点

同样,我们还是以 ClassPathXmlApplicationContext 作为切入点,开始对整体功能进行分析:

	public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
    
    
		this(new String[] {
    
    configLocation}, true, null);
	}

	public ClassPathXmlApplicationContext(
			String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
			throws BeansException {
    
    

		super(parent);
		// 设置配置路径
		setConfigLocations(configLocations);
		if (refresh) {
    
    
		// 核心功能处理
			refresh();
		}
	}

设置路径是必不可少的步骤,ClassPathXmlApplicationContext 中可以将配置文件路径以数组的方式传入,ClassPathXmlApplicationContext 可以对数组进行解析并进行加载。而对于解析及功能实现都在 refresh()中实现

二、设置配置路径

在 ClassPathXmlApplicationContext 中支持多个配置文件以数组方式同时传入:

	public void setConfigLocations(@Nullable String... locations) {
    
    
		if (locations != null) {
    
    
			Assert.noNullElements(locations, "Config locations must not be null");
			this.configLocations = new String[locations.length];
			for (int i = 0; i < locations.length; i++) {
    
    
				// 解析指定路径
				this.configLocations[i] = resolvePath(locations[i]).trim();
			}
		}
		else {
    
    
			this.configLocations = null;
		}
	}

三、扩展功能

设置了路径之后,便可以根据路径做配置文件的解析以及各种功能的实现了。可以说 refresh 函数中包合了几乎 ApplicationContext 中提供的全部功能 ,而且此函数中逻辑非常清晰明了,使我们很容易分析对应的层次及逻辑。

public void refresh() throws BeansException, IllegalStateException {
    
    
		synchronized (this.startupShutdownMonitor) {
    
    
			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

			/** 准备刷新的上下文 */
			prepareRefresh();

			/** 初始化BeanFactory,并进行XML文件读取 */
			// 这里会判断能否刷新,并且返回一个BeanFactory, 刷新不代表完全情况,主要是先执行Bean的销毁,然后重新生成一个BeanFactory,再在接下来的步骤中重新去扫描等等
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			/** 对BeanFactory进行各种功能填充*/
			// 准备BeanFactory
			// 1. 设置BeanFactory的类加载器、SpringEL表达式解析器、类型转化注册器
			// 2. 添加三个BeanPostProcessor,注意是具体的BeanPostProcessor实例对象
			// 3. 记录ignoreDependencyInterface
			// 4. 记录ResolvableDependency
			// 5. 添加三个单例Bean
			prepareBeanFactory(beanFactory);

			try {
    
    
				// Allows post-processing of the bean factory in context subclasses.
				// 子类覆盖方法做额外的处理
				postProcessBeanFactory(beanFactory);

				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");

				/** 激活各种BeanFactory的处理器*/
				// BeanFactory准备好了之后,执行BeanFactoryPostProcessor,开始对BeanFactory进行处理
				// 默认情况下:
				// 此时beanFactory的beanDefinitionMap中有6个BeanDefinition,5个基础BeanDefinition+AppConfig的BeanDefinition
				// 而这6个中只有一个BeanFactoryPostProcessor:ConfigurationClassPostProcessor
				// 这里会执行ConfigurationClassPostProcessor进行@Component的扫描,扫描得到BeanDefinition,并注册到beanFactory中
				// 注意:扫描的过程中可能又会扫描出其他的BeanFactoryPostProcessor,那么这些BeanFactoryPostProcessor也得在这一步执行
				invokeBeanFactoryPostProcessors(beanFactory);  // scanner.scan()

				/** 注册拦截Bean创建的Bean处理器,这里只是注册,真正的调用是在getBean的时候*/
				// 将扫描到的BeanPostProcessors实例化并排序,并添加到BeanFactory的beanPostProcessors属性中去
				registerBeanPostProcessors(beanFactory);

				beanPostProcess.end();

				/** 为上下文初始化Message源,即不同语言的消息体,国际化处理 */
				// 设置ApplicationContext的MessageSource,要么是用户设置的,要么是DelegatingMessageSource
				initMessageSource();

				/** 初始化应用消息广播器,并放入"applicationEventMulticaster"bean 中*/
				// Initialize event multicaster for this context.
				// 设置ApplicationContext的applicationEventMulticaster,要么是用户设置的,要么是SimpleApplicationEventMulticaster
				initApplicationEventMulticaster();

				/** 留给子类来初始化其他的Bean*/
				// Initialize other special beans in specific context subclasses.
				// 给子类的模板方法
				onRefresh();

				/** 在所有注册的bean中查找Listener bean,注册到消息广播器中*/
				// Check for listener beans and register them.
				// 把定义的ApplicationListener的Bean对象,设置到ApplicationContext中去,并执行在此之前所发布的事件
				registerListeners();

				/** 初始化剩下的单实例(非惰性的)*/
				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

				/** 完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人*/
				// Last step: publish corresponding event.
				finishRefresh();
			}

			catch (BeansException ex) {
    
    
				if (logger.isWarnEnabled()) {
    
    
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
    
    
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
				contextRefresh.end();
			}
		}
	}

下面概括一下 ClassPathXmlApplicationContext 初始化的步骤,并从中解释一下它为我们提供的功能。
(1)初始化前的准备工作,例如对系统属性或者环境变量进行准备及验证。
在某种情况下项目的使用需要读取某些系统变量,而这个变量的设置很可能会影响着系统的正确性,那么 ClassPathXmlApplicationContext 为我们提供的这个准备函数就显得非常必要,它可以在 Spring 启动的时候提前对必须的变量进行存在性验证。
(2)初始化 BeanFactory,并进行 XML 文件读取
之前有提到 ClassPathXmlApplicationContext 包含着 BeanFactory 所提供的一切特征,那么在这一步骤中将会复用 BeanFactory中的配置文件读取解析及其他功能,这一步之后ClassPathXmlApplicationContext 实际上就已经包含了 BeanFactory 所提供的功能,也就是可以进行 Bean 的提取等基础操作了。
(3)对 BeanFactory 进行各种功能填充。
@Qualifier@Autowired 应该是大家非常熟悉的注解,那么这两个注解正是在这一步骤中增加的支持。
(4)子类覆盖方法做额外的处理。
Spring 之所以强大,为世人所推崇,除了它功能上为大家提供了便利外,还有一方面是它的完美架构,开放式的架构让使用它的程序员很容易根据业务需要扩展已经存在的功能。这种开放式的设计在 Spring 中随处可见,例如在本例中就提供了一个空的函数实现 postProcessBeanFactory 来方便程序员在业务上做进一步扩展。
(5)激活各种 BeanFactory 处理器。
(6)注册拦截 bean 创建的 bean 处理器,这里只是注册,真正的调用是在 getBean 时候
(7)为上下文初始化 Message 源,即对不同语言的消息体进行国际化处理。
(8)初始化应用消息广播器,并放入 “applicationEventMulticaster” bean 中。
(9)留给子类来初始化其他的 bean。
(10) 在所有注册的 bean 中查找 listener bean,注册到消息广播器中。
(11)初始化剩下的单实例(非惰性的)。
(12)完成刷新过程,通知生命周期处理器 lifecycleProcessor 刷新过程,同时发出 ContextRefreshEvent 通知别人。

四、环境准备

prepareRefresh 函数主要是做些准备工作,例如对系统属性及环境变量的初始化及验证。

想要了解更多请看书中内容:6.3环境准备。

五、加载 BeanFactory

obtainFreshBeanFactory

obtainFreshBeanFactory 方法从字面理解是获取 BeanFactory。之前有说过,ApplicationContext 是对 BeanFactory 的功能上的扩展,不但包含了 BeanFactory 的全部功能更在其基础上添加了大量的扩展应用,那么 obtainFreshBeanFactory 正是实现 BeanFactory 的地方,也就是经过了这个函数后 ApplicationContext 就已经拥有了 BeanFactorv 的全部功能。

源码

	protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    
    
		// 核心处理:初始化BeanFactory,并进行XML文件读取,并将得到的BeanFactory记录在当前实体的属性中
		// AbstractRefreshableApplicationContext
		refreshBeanFactory();
		// 返回当前实体的BeanFactory属性
		return getBeanFactory();
	}

方法将核心处理交给了refreshBeanFactory:

	protected final void refreshBeanFactory() throws BeansException {
    
    
		if (hasBeanFactory()) {
    
    
			destroyBeans();
			closeBeanFactory();
		}
		try {
    
    
			// 创建DefaultListableBeanFactory
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			// 为了序列化指定id,如果需要的话,让这个BeanFactory从id反序列化到BeanFactory对象
			beanFactory.setSerializationId(getId());

			/** 定制 beanFactory,设置相关属性,包括是否允许覆盖同名称的不同定义的对象以及循环依赖以及设置 @Autowired 和 @Qualifier 注解解析器 QualifierAnnotationAutowiredCandidateResolver*/
			customizeBeanFactory(beanFactory);
			/** 初始化DocumentReader,并进行xml文件读取及解析*/
			loadBeanDefinitions(beanFactory);
			this.beanFactory = beanFactory;
		}
		catch (IOException ex) {
    
    
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}

流程分析

我们详细分析上面的每个步骤。
(1)创建 DefaultListableBeanFactory。
在介绍 BeanFactory 的时候,不知道读者是否还有印象,声明方式为:BeanFactory bf = new XmlBeanFactory(“beanFactory Test.xml”),其中的 XmlBeanFactory 继承自 DefaultListableBeanFactory,并提了 XmlBeanDefinitionReader 类型的 reader 属性,也就是说 DefaultListableBeanFactory 是容器的基础。必须首要实例化,那么在这里就是实例化 DefaultListableBeanFactory
的步骤。
(2)指定序列化ID。
(3)定制 BeanFactory。
(4) 加载 BeanDefinition。
(5)使用全局变量记录 BeanFactory 类实例。
因为 DefaultListableBeanFactory 类型的变量 beanFactory 是函数内的局部变量,所以要使用全局变量记录解析结果。

定制 BeanFactory

这里已经开始了对 BeanFactory 的扩展,在基本容器的基础上,增加了是否允许覆盖是否允许扩展的设置并提供了注解@Qualifier 和@Autowired 的支持。
在这里插入图片描述

对于允许覆盖和允许依赖的设置这里只是判断了是否为空,如果不为空要进行设置,但是并没有看到在哪里进行设置,究竟这个设置是在哪里进行设置的呢?还是那句话,使用子类爱盖方法,例如:
在这里插入图片描述设置完后相信大家已经对于这两个属性的使用有所了解,或者可以回到前面的章节进行再一次查看。对于定制 BeanFactory,Spring 还提供了另外一个重要的扩展,就是设置 AutowireCandidateResolver。在 bean 加载部分中讲解创建 Bean 时,如果采用 autowireByType 方式注入,那么默认会使用 Spring 提供的 SimpleAutowireCandidateResolver,而对于默认的实现并没有过多的逻辑处理。在这里,Spring 使用了 QualifierAnnotationAutowireCandidateResolver,设置了这个解析器后 Spring 就可以支持注解方式的注入了。

在讲解根据类型自定注入的时候,我们说过解析 autowire 类型时首先会调用方法:

Object value = getAutowireCandidateResolver () .get SuggestedValue (descriptor);

因此我们知道,在 QualifierAnnotationAutowireCandidateResolver 中一定会提供了解析Qualifier 与 Autowire 注解的方法。
在这里插入图片描述

加载 BeanDefinition

在第一步中提到了将 ClassPathXmlApplicationContext 与 XmlBeanFactory 创建的对比,在实现配置文件的加载功能中除了我们在第一步中已经初始化的 DefaultListableBeanFactory 外,还需要 XmlBeanDefinitionReader 来读取 XML,那么在这个步骤中首先要做的就是初始化XmlBeanDefinitionReader。

	protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
    
    
		// Create a new XmlBeanDefinitionReader for the given BeanFactory.
		// 为指定beanFactory创建XmlBeanDefinitionReader
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

		// 对beanDefinitionReader进行环境变量的设置
		beanDefinitionReader.setEnvironment(this.getEnvironment());
		beanDefinitionReader.setResourceLoader(this);
		beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

		// 对BeanDefinitionReader进行设置,可以覆盖
		initBeanDefinitionReader(beanDefinitionReader);
		loadBeanDefinitions(beanDefinitionReader);
	}

在初始化了 DefaultListableBeanFactory 和 XmlBeanDefinitionReader后就可以进行配置文件的读取了。

	protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
    
    
		Resource[] configResources = getConfigResources();
		if (configResources != null) {
    
    
			reader.loadBeanDefinitions(configResources);
		}
		String[] configLocations = getConfigLocations();
		if (configLocations != null) {
    
    
			reader.loadBeanDefinitions(configLocations);
		}
	}

使用 XmlBeanDefinitionReader 的 loadBeanDefinitions 方法进行配置文件的加载机注册相信大家已经不陌生,这完全就是开始 BeanFactory 的套路。因为在 XmlBeanDefinitionReader 中已经将之前初始化的 DefaultListableBeanFactory 注册进去了,所以 XmlBeanDefinitionReader 所读取的 BeanDefinitionHolder 都会注册到 DefaultListableBeanFactory 中,也就是经过此步骤,类型DefaultListableBeanFactory 的变量 beanFactory 已经包含了所有解析好的配置。

六、功能扩展

进入函数 prepareBeanFactory 前,Spring 已经完成了对配置的解析,而 ApplicationContext在功能上的扩展也由此展开。

	protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    
    
		// 设置beanFactory的classLoader为当前context的classloader
		beanFactory.setBeanClassLoader(getClassLoader());

		/** 设置 beanFactory 的表达式语言处理器,Spring3 增加了表达式语言的支持,默认可以使用#(bean.xxx}的形式来调用相关属性值。*/
		// Spring5.3中新增的功能,可以选择是否开启Spel功能,shouldIgnoreSpel默认为false,表示开启
		if (!shouldIgnoreSpel) {
    
    
			beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
		}

		// 为beanFactory增加了一个默认的propertyEditorRegistrar,这个主要是对bean的属性等设置管理的一个工具
		beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

		/** 添加BeanPostProcessor */
		// 组成一个BeanPostProcessor,用来处理EnvironmentAware、EmbeddedValueResolverAware等回调
		beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

		/** 设置了几个忽略自动装配的接口 */
		// 如果一个属性对应的set方法在ignoredDependencyInterfaces接口中被定义了,则该属性不会进行自动注入(是Spring中的自动注入,不是@Autowired)
		beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
		beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
		beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
		beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationStartupAware.class);

		/** 设置了几个自动装配的特殊规则*/
		beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
		beanFactory.registerResolvableDependency(ResourceLoader.class, this);
		beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
		beanFactory.registerResolvableDependency(ApplicationContext.class, this);

		// Register early post-processor for detecting inner beans as ApplicationListeners.
		// ApplicationListenerDetector负责把ApplicantsListener类型的Bean注册到ApplicationContext中
		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

		/** 增加对AspectJ的支持 */
		// Aspectj本身是通过编译期进行代理的,在Spring中就跟LoadTimeWeaver有关
		if (!NativeDetector.inNativeImage() && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
    
    
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			// Set a temporary ClassLoader for type matching.
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}

		/** 添加了默认的系统环境bean */
		if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
    
    
			beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
    
    
			beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
    
    
			beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
		}
		if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) {
    
    
			beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup());
		}
	}

上面函数中主要进行了几个方面的扩展。

  • 增加对 SPEL 语言的支持.
  • 增加对属性编辑器的支持.
  • 增加对一些内置类,比如 EnvironmentAware、 MessageSourceAware的信息注入。
  • 设置了依赖功能可忽略的接口.
  • 注册一些固定依赖的属性.
  • 增加 AspectJ 的支持(会在第7章中进行详细的讲解)。
  • 将相关环境变量及属性注册以单例模式注册。

可能读者不是很理解每个步骤的具体含义,接下来我们会对各个步骤进行详细地分析。

增加SPEL语言的支持

Spring 表达式语言全称为“Spring Expression Language”,缩写为 “SpEL”,类似于 Struts 2x中使用的 OGNL 表达式语言,能在运行时构建复杂表达式、存取对象图属性、对象方法调用等,并且能与 Spring 功能完美整合,比如能用来配置 bean 定义。SpEL 是单独模块,只依赖于 core模块,不依赖于其他模块,可以单独使用。

SpEL 使用#{.…}作为定界符,所有在大框号中的字符都将被认为是 SpEL,使用格式如下:
在这里插入图片描述在源码中通过代码 beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver())注册语言解析器,就可以对 SPEL 进行解析了,那么在注册解析器后 Spring 又是在什么时候调用这个解析器进行解析呢?

之前我们讲解过 Spring 在 bean 进行初始化的时候会有属性填充的一步,而在这一步中Spring 会调用 AbstractAutowireCapableBeanFactory 类的 applyPropertyValues 函数来完成功能。就在这个函数中,会通过构造 BeanDefinitionValueResolver 类型实例 valueResolver 来进行属性值的解析。同时,也是在这个步骤中一般通过 AbstractBeanFactory 中的 evaluateBeanDefinitionString方法去完成 SPEL 的解析。
在这里插入图片描述当调用这个方法时会判断是否存在语言解析器,如果存在则调用语言解析器的方法进行解析,解析的过程是在 Spring 的 expression 的包内,这里不做过多解释。我们通过查看对 evaluateBeanDefinitionString 方法的调用层次可以看出,应用语言解析器的调用主要是在解析依赖注入bean 的时候,以及在完成 bean 的初始化和局性获取后进行属性填充的时候。

增加属性注册编辑器

在 Spring DI 注人的时候可以把普通属性注人进来,但是像 Date 类型就无法被识别。例如:

package com.cms.propertyeditor.error;

import java.util.Date;

/**
 * @author: coffee
 * @date: 2023/4/5 9:30 PM
 * @description: ...
 */
public class UserManage {
    
    

    private Date dateValue;

    public Date getDateValue() {
    
    
        return dateValue;
    }

    public void setDateValue(Date dateValue) {
    
    
        this.dateValue = dateValue;
    }
}

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation=
               "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id = "userManage" class="com.cms.propertyeditor.error.UserManage" >
        <property name="dateValue">
            <value>2023-04-05</value>
        </property>
    </bean>

</beans>
package com.cms.propertyeditor;

import com.cms.propertyeditor.error.UserManage;
import org.junit.jupiter.api.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author: coffee
 * @date: 2023/4/5 9:35 PM
 * @description: ...
 */
public class PropertyEditorTest {
    
    

    /**
     * 错误演示:类型不匹配。
     */
    @Test
    public void userManageErrorTest() {
    
    
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("com/cms/propertyeditor/error.xml");
        UserManage userManage = (UserManage) context.getBean("userManage");
        // nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'java.util.Date' for property 'dateValue': no matching editors or conversion strategy found
        System.out.println(userManage.getDateValue());
    }
}

如果直接这样使用,程序则会报异常,类型转换不成功。因为在 UserManager 中的 data Value属性是 Date 类型的,而在 XML中配置的却是 String 类型的,所以当然会报异常。

Spring 针对此问题提供了两种解决办法。

1. 使用自定义属性编辑器

使用自定义属性编辑器,通过继承 PropertyEditorSupport,重写 setAsText 方法,具体步骤如下。

package com.cms.propertyeditor.info;

import org.springframework.beans.PropertyEditorRegistry;
import org.springframework.beans.PropertyEditorRegistrySupport;

import java.beans.PropertyEditorSupport;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author: coffee
 * @date: 2023/4/5 9:46 PM
 * @description: 自定义属性编辑器。
 */
public class DatePropertyEditor extends PropertyEditorSupport {
    
    
    private String format = "yyyy-MM-dd";


    @Override
    public void setAsText(String arg0) throws IllegalArgumentException {
    
    
        System.out.println("arg0:" + arg0);
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        try{
    
    
            Date d = sdf.parse(arg0);
            this.setValue(d);
        }catch (ParseException e) {
    
    
            e.printStackTrace();;
        }
    }
}

配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation=
               "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">


    <bean id = "userManage" class="com.cms.propertyeditor.error.UserManage" >
        <property name="dateValue">
            <value>2023-04-05</value>
        </property>
    </bean>

    <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
        <property name="customEditors">
            <map>
                <!--往map集合中插入元素-->
                <entry key="java.util.Date" value="com.cms.propertyeditor.info.DatePropertyEditor"/>
            </map>
        </property>
    </bean>

</beans>

测试类:

    @Test
    public void userManageInfoTest() {
    
    
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("com/cms/propertyeditor/info.xml");
        UserManage userManage = (UserManage) context.getBean("userManage");
        // 输出正常:Wed Apr 05 00:00:00 CST 2023
        System.out.println(userManage.getDateValue());
    }

在配置文件中引入类型为 org.springframework.beans.factory.config.CustomEditorConfigurer的 bean,并在属性 customEditors 中加入自定义的属性编辑器,其中 key 为属性编辑器所对应的类型。通过这样的配置,当 Spring 在注入 bean 的属性时一旦遇到了 java.util.Date 类型的属性会自动调用自定义的 DatePropertyEditor 解析器进行解析,并用解析结果代替配置属性进行注入。

2.使用spring自带的属性编辑器

package com.cms.propertyeditor.info;

import org.springframework.beans.PropertyEditorRegistrar;
import org.springframework.beans.PropertyEditorRegistry;
import org.springframework.beans.propertyeditors.CustomDateEditor;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author: coffee
 * @date: 2023/4/6 10:03 AM
 * @description: 2.注册spring自带的属性编辑器CustomDateEditor
 */
public class DatePropertyEditorRegistrar implements PropertyEditorRegistrar {
    
    
    @Override
    public void registerCustomEditors(PropertyEditorRegistry registry) {
    
    
        registry.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));
    }
}

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation=
               "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">


    <bean id = "userManage" class="com.cms.propertyeditor.error.UserManage" >
        <property name="dateValue">
            <value>2023-04-05</value>
        </property>
    </bean>

    <!--注册spring自带编辑器-->
    <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
        <property name="propertyEditorRegistrars">
            <list>
                <bean class="com.cms.propertyeditor.info.DatePropertyEditorRegistrar"/>
            </list>
        </property>
    </bean>

</beans>
    @Test
    public void userManageInfo2Test() {
    
    
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("com/cms/propertyeditor/info-spring-custom.xml");
        UserManage userManage = (UserManage) context.getBean("userManage");
        // 输出正常:Wed Apr 05 00:00:00 CST 2023
        System.out.println(userManage.getDateValue());
    }

关于属性编辑器的详细源码分析,请看书。

添加 ApplicationContextAwareProcessor 处理器

了解了属性编辑器的使用后,接下来我们继续通过 AbstractApplicationContext 的prepareBeanFactory 方法的主线来进行函数跟踪。对于 beanFactory.addBeanPostProcessor(newApplicationContextAwareProcessor(this))其实主要目的就是注册个 BneaPostProcessor,而真正的逻辑还是在 ApplicationContextAwareProcessor 中。

ApplicationContextAwareProcessor 实现 BeanPostProcessor 接口,我们回顾下之前讲过的内容,在 bean 实例化的时候,也就是 Spring 激活 bean 的init-method的前后,会调用 BeanPostProcessor 的 postProcessBeforeInitialization 方法和 postProcessAfterInitialization 方法。同样,对ApplicationContextAwareProcessor 我们也关心这两个方法。

对于 postProcessA fterInitialization 方法,在 ApplicationContextAwareProcessor 中并没有做过多逻辑处理。

public Object postProcessAfterInitialization (Object bean, string beanName){
    
    
	return bean;
}

对于 postProcessAfterInitialization 方法,在 ApplicationContextAwareProcessor 中并没有做过多逻辑处理:

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    
    
		if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
				bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
				bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware ||
				bean instanceof ApplicationStartupAware)) {
    
    
			return bean;
		}

		AccessControlContext acc = null;

		if (System.getSecurityManager() != null) {
    
    
			acc = this.applicationContext.getBeanFactory().getAccessControlContext();
		}

		if (acc != null) {
    
    
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
    
    
				invokeAwareInterfaces(bean);
				return null;
			}, acc);
		}
		else {
    
    
			// 执行aware方法
			invokeAwareInterfaces(bean);
		}

		return bean;
	}
private void invokeAwareInterfaces(Object bean) {
    
    
		if (bean instanceof EnvironmentAware) {
    
    
			((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
		}
		if (bean instanceof EmbeddedValueResolverAware) {
    
    
			((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
		}
		if (bean instanceof ResourceLoaderAware) {
    
    
			((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
		}
		if (bean instanceof ApplicationEventPublisherAware) {
    
    
			((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
		}
		if (bean instanceof MessageSourceAware) {
    
    
			((MessageSourceAware) bean).setMessageSource(this.applicationContext);
		}
		if (bean instanceof ApplicationStartupAware) {
    
    
			((ApplicationStartupAware) bean).setApplicationStartup(this.applicationContext.getApplicationStartup());
		}
		if (bean instanceof ApplicationContextAware) {
    
    
			((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
		}
	}

postProcessBeforelnitialization 方法中调用了 invokeAwarelnterfaces。 从 invokeAwarelnterfaces方法中,我们或许已经或多或少了解了 Spring 的用意,实现这些 Aware 接口的 bean 在被初始化之后,可以取得一些对应的资源。

设置忽略依赖

当Spring 将 ApplicationContextAwareProcessor 注册后,那么在 invokeAwarelnterfaces 方法中间接调用的 Aware 类已经不是普通的 bean了,如 ResourceL.oaderAware、 ApplicationEventPublisherAware 等,那么当然需要在 Spring 做 bean 的依赖注人的时候忽略它们。而 ignoreDependencylnterface的作用正是在此。

		/** 设置了几个忽略自动装配的接口 */
		// 如果一个属性对应的set方法在ignoredDependencyInterfaces接口中被定义了,则该属性不会进行自动注入(是Spring中的自动注入,不是@Autowired)
		beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
		beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
		beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
		beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationStartupAware.class);

注册依赖

Spring 中有了忽略依赖的功能,当然也必不可少地会有注册依赖的功能。

		/** 设置了几个自动装配的特殊规则*/
		beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
		beanFactory.registerResolvableDependency(ResourceLoader.class, this);
		beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
		beanFactory.registerResolvableDependency(ApplicationContext.class, this);

当注册了依赖解析后,例如当注册了对 BeanFactory.class 的解析依赖后,当 bean 的属性注入的时候,一旦检测到属性为 BeanFactory 类型便会将 beanFactory 的实例注入进去。

七、BeanFactory 的后处理

BeanFacotry 作为 Spring 中容器功能的基础,用于存放所有已经加载的 bean,为了保证程序上的高可扩展性,Spring 针对 BeanFactory 做了大量的扩展,比如我们熟知的 PostProcessor等都是在这里实现的。

激活注册的 BeanFactoryPostProcessor

正式开始介绍之前我们先了解下 BeanFactoryPostProcessor 的用法。
BeanFactoryPostProcessor 接口跟 BeanPostProcessor 类似,可以对 bean 的定义(配置元数据)进行处理。也就是说,Spring IoC 容器允许 BeanFactoryPostProcessor 在容器实际实例化任何其他的 bean 之前读取配置元数据,并有可能修改它。如果你愿意,你可以配置多个BeanFactoryPostProcessor。你还能通过设置“order”属性来控制 BeanFactoryPostProcessor 的执行次序(仅当 BeanFactoryPostProcessor 实现了 Ordered 接口时你才可以设置此属性,因此在实现BeanFactoryPostProcessor 时,就应当考虑实现 Ordered 接口)。请参考 BeanFactoryPostProcessor和 Ordered 接口的 JavaDoc 以获取更详细的信息。
如果你想改变实际的 bean 实例(例如从配置元数据创建的对象),那么你最好使用BeanPostProcessor。同样地,BeanFactoryPostProcessor 的作用域范围是容器级的。它只和你所使用的容器有关。如果你在容器中定义一个 Bean FactoryPostProcessor,它仅仅对此容器中的bean 进行后置处理。BeanFactoryPostProcessor 不会对定义在另一个容器中的 bean 进行后置处理,即使这两个容器都是在同一层次上。在 Spring 中存在对于 BeanFactoryPostProcessor 的典型应用,比如 PropertyPlaceholderConfigurer。

1. BeanFactoryPostProcessor 的典型应用:PropertyPlaceholderConfigurer

有时候,阅读 Spring 的 Bean 描述文件时,你也许会遇到类似如下的一些配置:
在这里插入图片描述
其中竟然出现了变量引用:$(bean.message}。这就是 Spring 的分散配置,可以在另外的配置文件中为 bean.message 指定值。如在 bean.property 配置如下定义:
bean.message-Hi, can you find me?
当访问名为 message 的 bean 时,mes 属性就会被置为字符串“H,can you find me?”,但Spring 框架是怎么知道存在这样的配置文件呢?这就要靠 Property PlaceholderConfigurer 这个类的 bean.
在这里插入图片描述在这个 bean 中指定了配置文件为 config/bean.properties。到这里似乎找到问题的答案了,但是其实还有个问题。这个 “mesHandler” 只不过是 Spring 框架管理的一个 bean,并没有被别的 bean 或者对象引用,Spring 的 beanFactory 是;怎么知道要从这个 bean 中获取配置信息的呢?
查看层级结构可以看出 PropertyPlaceholderConfigurer 这个类间接继承了 BeanFactoryPostProcessor 接口。这是一个很特别的接口,当 Spring 加载任何实现了这个接口的 bean 的配置时,都会在 bean 工厂载入所有 bean 的配置之后执行 postProcessBeanFactory 方法。在PropertyResourceConfigurer 类中实现了 postProcessBeanFactory 方法,在方法中先后调用了mergeProperties、 convertProperties、 processProperties 这 3 个方法,分别得到配置,将得到的配置转换为合适的类型,最后将配置内容告知 BeanFactory。
正是通过实现 BeanFactoryPostProcessor 接口,BeanFactory 会在实例化任何 bean 之前获得配置信息,从而能够正确解析 bean 描述文件中的变量引用。

2. 使用自定义 BeanFactoryPostProcessor

我们以实现一个 BeanFactoryPostProcessor,去除潜在的“流氓”属性值的功能来展示自定义 BeanFactoryPostProcessor 的创建及使用,例如 bean 定义中留下 bollocks 这样的字眼。
在这里插入图片描述

package com.cms.beanfactorypostprocessor;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionVisitor;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.util.StringValueResolver;

import java.util.HashSet;
import java.util.Set;

/**
 * @author: coffee
 * @date: 2023/4/6 3:17 PM
 * @description: 使用自定义的BeanFactoryPostProcessor
 */
public class ObscenityRemovingBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    
    


    private Set<String> obscenties;

    public ObscenityRemovingBeanFactoryPostProcessor() {
    
    
        this.obscenties = new HashSet<>();
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    
    
        String[] beanNames = beanFactory.getBeanDefinitionNames();
        for (String beanName : beanNames) {
    
    
            BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
            StringValueResolver valueResover = new StringValueResolver() {
    
    
                public String resolveStringValue(String strVal) {
    
    
                    if (isObscene(strVal)) {
    
    
                        return " ***** ";
                    }
                    return strVal;
                }
            };
            BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResover);
            visitor.visitBeanDefinition(bd);
        }
    }

    public boolean isObscene (Object value) {
    
    
        String potentialObscenity = value.toString().toUpperCase();
        return this.obscenties.contains(potentialObscenity);
    }

    public void setObscenties (Set<String> obscenties){
    
    
        this.obscenties.clear();
        for (String obscenity : obscenties) {
    
    
            this.obscenties.add(obscenity.toUpperCase());
        }
    }

}

在这里插入图片描述通过 ObscenityRemovingBeanFactoryPostProcessor, Spring 很好地实现了屏蔽掉 obscenties 定义的不应该展示的属性。

3. 激活 BeanFactoryPostProcessor

org.springframework.context.support.AbstractApplicationContext#refresh:invokeBeanFactoryPostProcessors

了解了 BeanFactoryPostProcessor 的用法后便可以深人研究 BeanFactoryPostProcessor 的调用过程了。

				/** 激活各种BeanFactory的处理器*/
				// BeanFactory准备好了之后,执行BeanFactoryPostProcessor,开始对BeanFactory进行处理
				// 默认情况下:
				// 此时beanFactory的beanDefinitionMap中有6个BeanDefinition,5个基础BeanDefinition+AppConfig的BeanDefinition
				// 而这6个中只有一个BeanFactoryPostProcessor:ConfigurationClassPostProcessor
				// 这里会执行ConfigurationClassPostProcessor进行@Component的扫描,扫描得到BeanDefinition,并注册到beanFactory中
				// 注意:扫描的过程中可能又会扫描出其他的BeanFactoryPostProcessor,那么这些BeanFactoryPostProcessor也得在这一步执行
				invokeBeanFactoryPostProcessors(beanFactory);  // scanner.scan()
	protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    
    

		// 重点
		PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

		// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
		// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
		// 关于LoadTimeWeaver看这篇文章了解即可,https://www.cnblogs.com/wade-luffy/p/6073702.html
		if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
    
    
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}
	}
/**
	 * BeanFactoryPostProcessors按入场方式分为:
	 * 1. 程序员调用ApplicationContext的API手动添加
	 * 2. Spring自己扫描出来的
	 *
	 * BeanFactoryPostProcessor按类型又可以分为:
	 * 1. 普通BeanFactoryPostProcessor
	 * 2. BeanDefinitionRegistryPostProcessor
	 *
	 * 执行顺序顺序如下:
		 * 1. 执行手动添加的BeanDefinitionRegistryPostProcessor                       的postProcessBeanDefinitionRegistry()方法
	 * 2. 执行扫描出来的BeanDefinitionRegistryPostProcessor(实现了PriorityOrdered)的postProcessBeanDefinitionRegistry()方法
	 * 3. 执行扫描出来的BeanDefinitionRegistryPostProcessor(实现了Ordered)		   的postProcessBeanDefinitionRegistry()方法
	 * 4. 执行扫描出来的BeanDefinitionRegistryPostProcessor(普通)				   的postProcessBeanDefinitionRegistry()方法
	 * 5. 执行扫描出来的BeanDefinitionRegistryPostProcessor(所有)				   的postProcessBeanFactory()方法
	 * 6. 执行手动添加的BeanFactoryPostProcessor								   的postProcessBeanFactory()方法
	 * 7. 执行扫描出来的BeanFactoryPostProcessor(实现了PriorityOrdered)		   的postProcessBeanFactory()方法
	 * 8. 执行扫描出来的BeanFactoryPostProcessor(实现了Ordered)		   		   的postProcessBeanFactory()方法
	 * 9. 执行扫描出来的BeanFactoryPostProcessor(普通)				   		   的postProcessBeanFactory()方法
	 *
	 * ConfigurationClassPostProcessor就会在第2步执行,会进行扫描
	 */
	public static void 	invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
    
       // BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor

		// Invoke BeanDefinitionRegistryPostProcessors first, if any.
		Set<String> processedBeans = new HashSet<>();

		/** 对BeanDefinitionRegistry类型的处理*/
		if (beanFactory instanceof BeanDefinitionRegistry) {
    
    
			BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
			List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
			/**
			 * BeanDefinitionRegistryPostProcessor
			 */
			List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

			/**
			 * 硬编码注册的后处理器
			 */
			// beanFactoryPostProcessors集合一般情况下都是空的,除非我们手动调用容器的addBeanFactoryPostProcessor方法添加了
			// beanFactoryPostProcessors中可能包含了:普通BeanFactoryPostProcessor对象和BeanDefinitionRegistryPostProcessor对象
			// 对于BeanDefinitionRegistryPostProcessor对象,会执行自己的postProcessBeanDefinitionRegistry()方法
			for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
    
    
				if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
    
    
					BeanDefinitionRegistryPostProcessor registryProcessor =
							(BeanDefinitionRegistryPostProcessor) postProcessor;
					/** 对于BeanDefinitionRegistryPostProcessor类型,在BeanFactoryPostProcessor的基础上还有自己定义的方法,需要先调用*/
					registryProcessor.postProcessBeanDefinitionRegistry(registry);
					registryProcessors.add(registryProcessor);
				}
				else {
    
    
					/** 记录常规BeanFactoryPostProcessor */
					regularPostProcessors.add(postProcessor);
				}
			}

			// Do not initialize FactoryBeans here: We need to leave all regular beans
			// uninitialized to let the bean factory post-processors apply to them!
			// Separate between BeanDefinitionRegistryPostProcessors that implement
			// PriorityOrdered, Ordered, and the rest.
			List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

			// 执行扫描出来的BeanDefinitionRegistryPostProcessor

			// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
			String[] postProcessorNames =
					beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
    
    
				if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
    
    
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			// 升序排序
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
			currentRegistryProcessors.clear();

			// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
			postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
    
    
				// processedBeans表示该beanFactoryPostProcessor的postProcessBeanDefinitionRegistry()方法已经执行过了,不再重复执行
				if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
    
    
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
			currentRegistryProcessors.clear();

			// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
			// 执行哪些没有实现了PriorityOrdered或Ordered接口的普通BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry()方法
			// 在这个过程中可能会向BeanFactory中注册另外的BeanDefinitionRegistryPostProcessor,所以需要while,直到确定所有的BeanDefinitionRegistryPostProcessor都执行完了
			// 在这个过程中注册的BeanDefinitionRegistryPostProcessor,所实现的PriorityOrdered或Ordered接口可能会不按顺序执行
			// 比如 A注册了B和C,B又注册了D和E,那么B和C会按顺序执行,D和E也会按顺序执行,但是B、C、D、E整体不能保证是顺序执行
			boolean reiterate = true;
			while (reiterate) {
    
    
				reiterate = false;
				postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
				for (String ppName : postProcessorNames) {
    
    
					if (!processedBeans.contains(ppName)) {
    
    
						currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
						processedBeans.add(ppName);
						reiterate = true;
					}
				}
				sortPostProcessors(currentRegistryProcessors, beanFactory);
				registryProcessors.addAll(currentRegistryProcessors);
				invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
				currentRegistryProcessors.clear();
			}

			/** 常规BeanFactoryPostProcessors */
			// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
			// 执行完BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry()方法后,
			// 再执行BeanDefinitionRegistryPostProcessor的postProcessBeanFactory()方法
			invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);

			// 执行手动添加的普通BeanFactoryPostProcessor的postProcessBeanFactory()方法
			invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
		}

		else {
    
    
			// Invoke factory processors registered with the context instance.
			invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
		}

		/** 对于配置中读取的BeanFactoryPostProcessors的处理 */
		// 执行扫描出来的普通BeanFactoryPostProcessor
		// Do not initialize FactoryBeans here: We need to leave all regular beans
		// uninitialized to let the bean factory post-processors apply to them!
		String[] postProcessorNames =
				beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

		// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
		// Ordered, and the rest.
		List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
		List<String> orderedPostProcessorNames = new ArrayList<>();
		List<String> nonOrderedPostProcessorNames = new ArrayList<>();
		// 对后处理器进行分类
		for (String ppName : postProcessorNames) {
    
    
			if (processedBeans.contains(ppName)) {
    
    
				// skip - already processed in first phase above
			}
			else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
    
    
				priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
			}
			else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
    
    
				orderedPostProcessorNames.add(ppName);
			}
			else {
    
    
				nonOrderedPostProcessorNames.add(ppName);
			}
		}

		/** 按照优先级进行排序 */
		// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
		sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

		// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
		List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
		for (String postProcessorName : orderedPostProcessorNames) {
    
    
			orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		/** 按照order排序 */
		sortPostProcessors(orderedPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

		/** 无序,直接调用*/
		// Finally, invoke all other BeanFactoryPostProcessors.
		List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
		for (String postProcessorName : nonOrderedPostProcessorNames) {
    
    
			nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

		// Clear cached merged bean definitions since the post-processors might have
		// modified the original metadata, e.g. replacing placeholders in values...
		beanFactory.clearMetadataCache();
	}

从上面的方法中我们看到,对于 BeanFactoryPostProcessor 的处理主要分两种情况进行,一个是对于BeanDefinitionRegistry 类的特殊处理,另一种是对普通的 BeanFactoryPostProcessor 进行处理。而对于每种情况都需要考虑硬编码注入注册的后处理器以及通过配置注人的后处理器。
对于 BeanDefinitionRegistry 类型的处理类的处理主要包括以下内容。
(1)对于硬编码注册的后处理器的处理,主要是通过 AbstractApplicationContext 中的添加处理器方法 addBeanFactoryPostProcessor 进行添加。
在这里插入图片描述添加后的后处理器会存放在 beanFactoryPostProcessors 中,而在处理 BeanFactoryPostProcessor时候会首先检测 beanFactoryPostProcessors 是否有数据。当然,BeanDefinitionRegistryPostProcessor继承自 BeanFactoryPostProcessor,不但有 BeanFactoryPostProcessor 的特性,同时还有自己定义的个性化方法,也需要在此调用。所以,这里需要从 beanFactoryPostProcessors 中挑出BeanDefinitionRegistryPostProcessor 的后处理器,并进行其 postProcessBeanDefinitionRegistry 方法的激活。
(2)记录后处理器主要使用了三个 List 完成。

  • registryPostProcessors:记录通过硬编码方式注册的 BeanDefinitionRegistryPostProcessor类型的处理器。
  • regularPostProcessors:记录通过硬编码方式注册的 BeanFactoryPostProcessor 类型的处理器。
  • registryPostProcessorBeans: 记录通过配置方式注册的 BeanDefinitionRegistryPostProcessor类型的处理器。

(3)对以上所记录的 List 中的后处理器进行统一调用 BeanFactory PostProcessor 的postProcessBeanFactory 方法。
(4)对 beanFactoryPostProccssors 中非 BeanDefinitionRegistryPostProcessor 类型的后处理器进行统一的 BeanFactoryPostProcessor 的 postProcessBeanFactory 方法调用。
(5)普通 beanFactory 处理。
BeanDefinitionRegistryPostProcessor 只对 BeanDefinitionRegistry 类型的 ConfigurableListableBeanFactory 有效,所以如果判断所示的 beanFactory 并不是 BeanDefinitionRegistry,那么便可以忽略BeanDefinitionRegistryPostProcessor,而直接处理 BeanFactoryPostProcessor,当然获取的方式与上面的获取类似。
这里需要提到的是,对于硬编码方式手动添加的后处理器是不需要做任何排序的,但是在配置文件中读取的处理器,Sping 并不保证读取的顺序。所以,为了保证用户的调用顺序的要求,Spring 对于后处理器的调用支持按照 PriorityOrdered 或者 Ordered 的顺序调用。

注册 BeanPostProcessor

org.springframework.context.support.AbstractApplicationContext#refresh:registerBeanPostProcessors

上文中提到了 BeanFacotoryPostProcessors 的调用,现在我们来探索下 BeanPostProcessor,但是这里并不是调用,而是注册。真正的调用其实是在 bean 的实例化阶段进行的。这是一个很重要的步骤,也是很多功能 BeanFactory 不支持的重要原因。Spring 中大部分功能都是通过后处理器的方式进行扩展的,这是 Spring 框架的一个特性,但是在 BeanFactory 中其实并没有实现后处理器的自动注册,所以在调用的时候如果没有进行手动注册其实是不能使用的。但是在 ApplicationContext 中却添加了自动注册功能,如自定义这样一个后处理器:
在这里插入图片描述
那么使用 BeanFactory 方式进行 Spring 的 bean 的加载时是不会有任何改变的,但是使用ApplicationContext 方式获取 bean 的时候会在获取每个 bean 时打印出“=====”,而这个特性就在 registerBeanPostProcessors 方法中完成的。
我们继续探索 registerBeanPostProcessors 的方法实现。

/** 注册拦截Bean创建的Bean处理器,这里只是注册,真正的调用是在getBean的时候*/
// 将扫描到的BeanPostProcessors实例化并排序,并添加到BeanFactory的beanPostProcessors属性中去
registerBeanPostProcessors(beanFactory);
public static void registerBeanPostProcessors(
			ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
    
    

		String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

		/**
		 * BeanPostProcessorChecker 是一个普通的信息打印,可能会有些情况,
		 * 当 spring 的配置中的后处理器还没有被注册就已经开始了 bean 的初始化时
		 * 便会打印出 BeanPostProcessorChecker 中设定的信息
		 * */
		// beanProcessorTargetCount表示BeanFactory中所有的BeanPostProcessor数量,+1表示BeanPostProcessorChecker
		int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
		beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

		// Separate between BeanPostProcessors that implement PriorityOrdered,
		// Ordered, and the rest.
		List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
		List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
		List<String> orderedPostProcessorNames = new ArrayList<>();
		List<String> nonOrderedPostProcessorNames = new ArrayList<>();
		for (String ppName : postProcessorNames) {
    
    
			if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
    
    
				BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
				priorityOrderedPostProcessors.add(pp);
				if (pp instanceof MergedBeanDefinitionPostProcessor) {
    
    
					internalPostProcessors.add(pp);
				}
			}
			else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
    
    
				orderedPostProcessorNames.add(ppName);
			}
			else {
    
    
				nonOrderedPostProcessorNames.add(ppName);
			}
		}

		/** 第一步,注册所有实现 PriorityOrdered的 BeanPostProcessor */
		sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
		registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

		/** 第二步,注册所有实现 Ordered的 BeanPostProcessor */
		List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
		for (String ppName : orderedPostProcessorNames) {
    
    
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			orderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
    
    
				internalPostProcessors.add(pp);
			}
		}
		sortPostProcessors(orderedPostProcessors, beanFactory);
		registerBeanPostProcessors(beanFactory, orderedPostProcessors);

		/** 第三步,注册所有实现 无序的 BeanPostProcessor*/
		// Now, register all regular BeanPostProcessors.
		List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
		for (String ppName : nonOrderedPostProcessorNames) {
    
    
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			nonOrderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
    
    
				internalPostProcessors.add(pp);
			}
		}
		registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

		/** 第四步,注册所有 MergedBeanDefinitionPostProces sor 类型的 BeanPostProcessor,并非重复注册,
		 * 在beanFactory.addBeanPostProcessor 中会先移除已经存在的 BeanPostProcessor*/
		// MergedBeanDefinitionPostProcessor排在最后
		sortPostProcessors(internalPostProcessors, beanFactory);
		registerBeanPostProcessors(beanFactory, internalPostProcessors);

		/** 添加 ApplicationListener 探测器 */
		// Re-register post-processor for detecting inner beans as ApplicationListeners,
		// moving it to the end of the processor chain (for picking up proxies etc).
		// ApplicationListenerDetector放在所有BeanPostProcessor之后,注意ApplicationListenerDetector的equals()方法实现
		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
	}

配合源码以及注释,在 registerBeanPostProcessors 方法中所做的逻辑相信大家已经很清楚了,我们再做一下总结。
首先我们会发现,对于 BeanPostProcessor 的处理与 BeanFactoryPostProcessor 的处理极为相似,但是似乎又有些不一样的地方。经过反复的对比发现,对于 BeanFactoryPostProcessor的处理要区分两种情况,一种方式是通过硬编码方式的处理,另一种是通过配置文件方式的处理。那么为什么在 BeanPostProcessor 的处理中只考虑了配置文件的方式而不考虑硬编码的方式呢?提出这个问题,还是因为读者没有完全理解两者实现的功能。对于 BeanFactoryPostProcessor的处理,不但要实现注册功能,而且还要实现对后处理器的激活操作,所以需要载人配置中的定义,并进行激活;而对于 BeanPostProcessor 并不需要马上调用,再说,硬编码的方式实现的功能是将后处理器提取并调用,这里并不需要调用,当然不需要考虑硬编码的方式了,这里的功能只需要将配置文件的 BeanPostProcessor 提取出来并注册进入 beanFactory 就可以了。
对于 beanFactory 的注册,也不是直接注册就可以的。在 Spring 中支持对于 BeanPostProcessor 的排序,比如根据 PriorityOrdered 进行排序、根据 Ordered 进行排序或者无序,而 Spring在 BeanPostProcessor 的激活顺序的时候也会考虑对于顺序的问题而先进行排序。

初始化消息资源

在进行这段函数的解析之前,我们同样先来回顾 Spring 国际化的使用方法。
假设我们正在开发一个支持多国语言的 web 应用程序,要求系统能够根据客户端的系统的语言类型返回对应的界面:英文的操作系统返回英文界面,而中文的操作系统则返回中文界面—这便是典型的 j18n 国际化问题。对于有国际化要求的应用系统,我们不能简单地采用硬编码的方式编写用户界面信息、报错信息等内容,而必须为这些需要国际化的信息进行特殊处理。简单来说,就是为每种语言提供一套相应的资源文件,并以规范化命名的方式保存在特定的目录中,由系统自动根据客户端语言选择适合的资源文件。
“国际化信息”也称为“本地化信息”,一般需要两个条件才可以确定一个特定类型的本地化信息,它们分别是“语言类型”和“国家/地区的类型”。如中文本地化信息既有中国大陆地区的中文,又有中国台湾地区、中国香港地区的中文,还有新加坡地区的中文。Java 通过java.util.Locale 类表示一个本地化对象,它允许通过语言参数和国家/地区参数创建一个确定的本地化对象。
java.util.Locale 是表示语言和国家/地区信息的本地化类,它是创建国际化应用的基础。下面给出几个创建本地化对象的示例:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_43783527/article/details/129485887