Spring Boot-加载配置文件ConfigDataEnvironmentPostProcessor

org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor是 Spring Boot 中的一个关键组件,它负责处理配置数据(config data),并将其应用于 Spring 应用上下文中。下面我们详细解读这个类的产生背景、作用和工作原理。

产生背景

在 Spring Boot 中,配置数据是指来自各种外部来源(如 YAML 文件、properties 文件、环境变量、命令行参数等)的配置信息。Spring Boot 提供了一种机制来自动读取这些配置信息,并将它们绑定到应用中的 Bean 上。为了更好地管理和处理这些配置数据,Spring Boot 引入了配置数据功能,其中包括 `ConfigData` 和 `ConfigDataLocation` 等概念。

作用

`ConfigDataEnvironmentPostProcessor` 的主要作用是处理配置数据,并将这些数据合并到应用的环境配置中。具体来说,它执行以下几个关键任务:

  1. 加载配置数据:从不同的配置源(如文件系统、类路径、云配置中心等)加载配置数据。

  2. 解析配置数据:解析加载的配置数据,并将其转换为 Spring 可以理解的格式。

  3. 合并配置数据:将解析后的配置数据合并到 `ConfigurableEnvironment` 中。

  4. 处理占位符:解析配置数据中的占位符,并将其替换为实际的值。

工作原理

`ConfigDataEnvironmentPostProcessor` 的工作原理涉及以下几个步骤:

  1. 实例化:在 Spring 应用启动时,`ConfigDataEnvironmentPostProcessor` 会作为 `BeanFactoryPostProcessor` 的一部分被实例化。

  2. 配置数据定位:通过 `ConfigDataLocationResolver` 来确定配置数据的位置。

  3. 加载配置数据:使用 `ConfigDataLoader` 来加载配置数据。

  4. 解析配置数据:使用 `ConfigDataParser` 来解析加载的数据。

  5. 合并配置数据:将解析后的配置数据合并到 `ConfigurableEnvironment` 中。

  6. 处理占位符:在合并过程中处理配置数据中的占位符。

源码流程:

这个类有个成员变量postProcessorsFactory,是个函数,函数签名是接受ClassLoader类型参数,返回EnvironmentPostProcessorsFactory类型参数。这个类的无参构造是在SpringApplication实例化时被调用的。这里主要是要理解、熟悉函数作为参数传递的用法。这个函数实际传的值是org.springframework.boot.env.EnvironmentPostProcessorsFactory#fromSpringFactories(),

下面就是执行监听器回调,最后调用了this.postProcessorsFactory.apply(classLoader);来得到一个EnvironmentPostProcessorsFactory类型实例,其实际类型其实是ReflectionEnvironmentPostProcessorsFactory

java 复制代码
public class EnvironmentPostProcessorApplicationListener implements SmartApplicationListener, Ordered {

	private final Function<ClassLoader, EnvironmentPostProcessorsFactory> postProcessorsFactory;


	/**
	 * Create a new {@link EnvironmentPostProcessorApplicationListener} with
	 * {@link EnvironmentPostProcessor} classes loaded through {@code spring.factories}.
	 */
	public EnvironmentPostProcessorApplicationListener() {
		this(EnvironmentPostProcessorsFactory::fromSpringFactories, new DeferredLogs());
	}

	EnvironmentPostProcessorApplicationListener(
			Function<ClassLoader, EnvironmentPostProcessorsFactory> postProcessorsFactory, DeferredLogs deferredLogs) {
		this.postProcessorsFactory = postProcessorsFactory;
		this.deferredLogs = deferredLogs;
	}

	@Override
	public void onApplicationEvent(ApplicationEvent event) {
		if (event instanceof ApplicationEnvironmentPreparedEvent) {
			onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
		}
		if (event instanceof ApplicationPreparedEvent) {
			onApplicationPreparedEvent();
		}
		if (event instanceof ApplicationFailedEvent) {
			onApplicationFailedEvent();
		}
	}


	private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
		ConfigurableEnvironment environment = event.getEnvironment();
		SpringApplication application = event.getSpringApplication();
		for (EnvironmentPostProcessor postProcessor : getEnvironmentPostProcessors(application.getResourceLoader(),
				event.getBootstrapContext())) {
			postProcessor.postProcessEnvironment(environment, application);
		}
	}

	List<EnvironmentPostProcessor> getEnvironmentPostProcessors(ResourceLoader resourceLoader,
			ConfigurableBootstrapContext bootstrapContext) {
		ClassLoader classLoader = (resourceLoader != null) ? resourceLoader.getClassLoader() : null;
		EnvironmentPostProcessorsFactory postProcessorsFactory = this.postProcessorsFactory.apply(classLoader);
		return postProcessorsFactory.getEnvironmentPostProcessors(this.deferredLogs, bootstrapContext);
	}
}

还是读取spring.factories文件得到 EnvironmentPostProcessor用于可扩展的设计。

这个类的方法不好理解,这里用了Instantiator,构建Instantiator时第二个参数是一个方法,告诉Instantiator,在创建EnvironmentPostProcessor实例的时候,如果构造函数或setter方法中有DeferredLogFactory类型的参数,则使用logFactory作为实际值,下面几个add作用也是一样。

java 复制代码
class ReflectionEnvironmentPostProcessorsFactory implements EnvironmentPostProcessorsFactory {

	@Override
	public List<EnvironmentPostProcessor> getEnvironmentPostProcessors(DeferredLogFactory logFactory,
			ConfigurableBootstrapContext bootstrapContext) {
		Instantiator<EnvironmentPostProcessor> instantiator = new Instantiator<>(EnvironmentPostProcessor.class,
				(parameters) -> {
					parameters.add(DeferredLogFactory.class, logFactory);
					parameters.add(Log.class, logFactory::getLog);
					parameters.add(ConfigurableBootstrapContext.class, bootstrapContext);
					parameters.add(BootstrapContext.class, bootstrapContext);
					parameters.add(BootstrapRegistry.class, bootstrapContext);
				});
		return (this.classes != null) ? instantiator.instantiateTypes(this.classes)
				: instantiator.instantiate(this.classLoader, this.classNames);
	}


}

org.springframework.boot.context.config.ConfigDataEnvironment#processAndApply

相关推荐
bjzhang752 分钟前
SpringBoot开发——集成Tess4j实现OCR图像文字识别
spring boot·ocr·tess4j
flying jiang7 分钟前
Spring Boot 入门面试五道题
spring boot
小菜yh8 分钟前
关于Redis
java·数据库·spring boot·redis·spring·缓存
爱上语文2 小时前
Springboot的三层架构
java·开发语言·spring boot·后端·spring
荆州克莱2 小时前
springcloud整合nacos、sentinal、springcloud-gateway,springboot security、oauth2总结
spring boot·spring·spring cloud·css3·技术
serve the people2 小时前
springboot 单独新建一个文件实时写数据,当文件大于100M时按照日期时间做文件名进行归档
java·spring boot·后端
罗政7 小时前
[附源码]超简洁个人博客网站搭建+SpringBoot+Vue前后端分离
vue.js·spring boot·后端
Java小白笔记10 小时前
关于使用Mybatis-Plus 自动填充功能失效问题
spring boot·后端·mybatis
小哇66610 小时前
Spring Boot,在应用程序启动后执行某些 SQL 语句
数据库·spring boot·sql
luoluoal13 小时前
java项目之企业级工位管理系统源码(springboot)
java·开发语言·spring boot