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实例化时被调用的。主要是要理解函数作为参数传递的写法。
下面就是执行监听器回调,最后调用了this.postProcessorsFactory.apply(classLoader);来得到一个EnvironmentPostProcessorsFactory类型实例,其实际类型其实是ReflectionEnvironmentPostProcessorsFactory
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);
}
}
这个类的方法不好理解
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