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

相关推荐
seventeennnnn22 分钟前
谢飞机的Java高级开发面试:从Spring Boot到分布式架构的蜕变之旅
spring boot·微服务架构·java面试·分布式系统·电商支付
超级小忍2 小时前
服务端向客户端主动推送数据的几种方法(Spring Boot 环境)
java·spring boot·后端
时间会给答案scidag2 小时前
报错 400 和405解决方案
vue.js·spring boot
Wyc724093 小时前
SpringBoot
java·spring boot·spring
ladymorgana4 小时前
【Spring Boot】HikariCP 连接池 YAML 配置详解
spring boot·后端·mysql·连接池·hikaricp
GJCTYU6 小时前
spring中@Transactional注解和事务的实战理解附代码
数据库·spring boot·后端·spring·oracle·mybatis
风象南7 小时前
SpringBoot敏感配置项加密与解密实战
java·spring boot·后端
写不出来就跑路8 小时前
暑期实习感悟与经验分享:从校园到职场的成长之路
java·开发语言·经验分享·spring boot
程序员张312 小时前
Maven编译和打包插件
java·spring boot·maven
灵犀学长14 小时前
EasyExcel之SheetWriteHandler:解锁Excel写入的高阶玩法
spring boot·excel