EnvironmentPostProcessor实现属性文件加载原理
关于EnvironmentPostProcessor自定属性文件加载可以参考官网Customize the Environment or ApplicationContext Before It Starts
本文以springboot2.6为例,讲解EnvironmentPostProcessor实现文件加载原理,EnvironmentPostProcessor子类实现的加载本质上SpringFactoriesLoader进行类的加载,加载时机是通过ApplicationEnvironmentPreparedEvent事件监听来实现。
SpringBoot2.4以前是ConfigFileApplicationListener,SpringBoot2.4+是通过EnvironmentPostProcessorApplicationListener,SpringBoot2.4版本对外部配置进行大幅度调整,由于ConfigFileApplicationListener过于笨重职责过多替换成EnvironmentPostProcessorApplicationListener、ConfigDataEnvironmentPostProcessor来实现。
关键类方法
ConfigFileApplicationListener (SpringBoot2.4前)
org.springframework.boot.context.config.ConfigFileApplicationListener#onApplicationEnvironmentPreparedEvent方法
EnvironmentPostProcessorApplicationListener(SpringBoot2.4+)
org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEnvironmentPreparedEvent方法
详细分析
SpringBoot2.4+ 源码解析
SpringBoot启动发布ApplicationEnvironmentPreparedEvent
org.springframework.boot.SpringApplication.prepareEnvironment方法
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
// Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach(environment);
//发布ApplicationEnvironmentPreparedEvent事件
listeners.environmentPrepared(bootstrapContext, environment);
DefaultPropertiesPropertySource.moveToEnd(environment);
Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
"Environment prefix cannot be set via properties.");
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = convertEnvironment(environment);
}
ConfigurationPropertySources.attach(environment);
return environment;
}
EnvironmentPostProcessorApplicationListener收到ApplicationEnvironmentPreparedEvent事件并处理EnvironmentPostProcessor子类
//事件回调处理
@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();
//获取EnvironmentPostProcessors实现子类并调用postProcessEnvironment方法
for (EnvironmentPostProcessor postProcessor : getEnvironmentPostProcessors(application.getResourceLoader(),
event.getBootstrapContext())) {
postProcessor.postProcessEnvironment(environment, application);
}
}
SpringBoot2.4前版本 源码解析
SpringBoot启动发布ApplicationEnvironmentPreparedEvent
org.springframework.boot.SpringApplication.prepareEnvironment方法
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
// Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach(environment);
//发布ApplicationEnvironmentPreparedEvent事件
listeners.environmentPrepared(bootstrapContext, environment);
DefaultPropertiesPropertySource.moveToEnd(environment);
Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
"Environment prefix cannot be set via properties.");
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = convertEnvironment(environment);
}
ConfigurationPropertySources.attach(environment);
return environment;
}
ConfigFileApplicationListener收到ApplicationEnvironmentPreparedEvent事件并处理EnvironmentPostProcessor子类
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationEnvironmentPreparedEvent) {
onApplicationEnvironmentPreparedEvent(
(ApplicationEnvironmentPreparedEvent) event);
}
if (event instanceof ApplicationPreparedEvent) {
onApplicationPreparedEvent(event);
}
}
private void onApplicationEnvironmentPreparedEvent(
ApplicationEnvironmentPreparedEvent event) {
List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();
postProcessors.add(this);
AnnotationAwareOrderComparator.sort(postProcessors);
for (EnvironmentPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessEnvironment(event.getEnvironment(),
event.getSpringApplication());
}
}
总结
通过上面分析我们已清楚EnvironmentPostProcessor实现配置文件加载的原理,同时也体会到理解Spring event妙用。