SpringBoot 配置文件加载
SpringBoot2.4以后
SpringBoot2.4及以后,取消ConfigFileApplicationListener,改成了EnvironmentPostProcessor、RandomPropertySource
EnvironmentPostProcessor
EnvironmentPostProcessor子类实现的加载本质上SpringFactoriesLoader进行类的加载,加载时机是通过ApplicationEnvironmentPreparedEvent事件监听来实现。 SpringBoot2.4以前是ConfigFileApplicationListener,SpringBoot2.4+是通过EnvironmentPostProcessorApplicationListener,SpringBoot2.4版本对外部配置进行大幅度调整,由于ConfigFileApplicationListener过于笨重职责过多替换成EnvironmentPostProcessorApplicationListener、ConfigDataEnvironmentPostProcessor来实现。
具体可以查看官方说明:
Provide ConfigFileApplicationListener replacement · spring-projects/spring-boot@3352024 (github.com)
EnvironmentPostProcessor提供了一个接入点,允许用户在Spring上下文构建之前,设置一些环境信息Environment。
官方文档:Customize the Environment or ApplicationContext Before It Starts
其中一种配置方式是starter机制一样,是在META-INF/spring.factories文件里配置的
ConfigDataEnvironment
在这个文件里配置了配置文件路径等信息
ConfigDataEnvironmentPostProcessor
优先级总结
-
后缀优先级:
yml>yaml>properties
-
以下优先级从低到高,每行也是从低到高
1. `optional:classpath:/;optional:classpath:/config/` 2. `optional:file:./;optional:file:./config/;optional:file:./config/*/` 3. `optional:classpath:custom-config/` 4. `optional:file:./custom-config/`
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以前
ConfigFileApplicationListener
ConfigFileApplicationListener类的属性如下,根据属性可以大致看出支持的配置和功能:
-
默认配置文件的路径:DEFAULT_SEARCH_LOCATIONS,注意具体处理的时候进行了反转,优先级如下:
从高到低
-
file:./custom-config/
-
classpath:custom-config/
-
file:./config/
-
file:./
-
classpath:/config/
-
classpath:/
-
-
支持定义配置文件:配置spring.profiles.active对应的值,如dev。application-dev.properties
-
支持定义使用的配置文件名:spring.config.name
-
支持定义使用的配置文件所在路径:spring.config.location。需要在环境变量里配置
-
支持定义使用的配置文件所在路径:spring.config.additional-location。需要在环境变量里配置
-
等等
public class ConfigFileApplicationListener implements EnvironmentPostProcessor, SmartApplicationListener, Ordered { private static final String DEFAULT_PROPERTIES = "defaultProperties"; // Note the order is from least to most specific (last one wins) private static final String DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/"; private static final String DEFAULT_NAMES = "application"; private static final Set<String> NO_SEARCH_NAMES = Collections.singleton(null); /** * The "active profiles" property name. */ public static final String ACTIVE_PROFILES_PROPERTY = "spring.profiles.active"; /** * The "includes profiles" property name. */ public static final String INCLUDE_PROFILES_PROPERTY = "spring.profiles.include"; /** * The "config name" property name. */ public static final String CONFIG_NAME_PROPERTY = "spring.config.name"; /** * The "config location" property name. */ public static final String CONFIG_LOCATION_PROPERTY = "spring.config.location"; /** * The "config additional location" property name. */ public static final String CONFIG_ADDITIONAL_LOCATION_PROPERTY = "spring.config.additional-location"; /** * The default order for the processor. */ public static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 10; }
onApplicationEnvironmentPreparedEvent
在ApplicationEnvironmentPreparedEvent事件的处理。主要是将加载后置处理器
private void onApplicationEnvironmentPreparedEvent( ApplicationEnvironmentPreparedEvent event) { // 加载在META-INF/spring.factories里定义的EnvironmentPostProcessor对应的类名 List<EnvironmentPostProcessor> postProcessors = loadPostProcessors(); // 将自己也加入其中 postProcessors.add(this); // 根据order排序 AnnotationAwareOrderComparator.sort(postProcessors); // 遍历执行 for (EnvironmentPostProcessor postProcessor : postProcessors) { postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication()); } }
postProcessors:
postProcessors = {ArrayList@2862} size = 5 0 = {SystemEnvironmentPropertySourceEnvironmentPostProcessor@2885} 1 = {SpringApplicationJsonEnvironmentPostProcessor@2884} 2 = {CloudFoundryVcapEnvironmentPostProcessor@2883} 3 = {HostInfoEnvironmentPostProcessor@2886} 4 = {ConfigFileApplicationListener@2741}
ConfigFileApplicationListener的加载自定义属性开始
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment,
SpringApplication application) {
addPropertySources(environment, application.getResourceLoader());
}
/**
* Add config file property sources to the specified environment.
* @param environment the environment to add source to
* @param resourceLoader the resource loader
* @see #addPostProcessors(ConfigurableApplicationContext)
*/
protected void addPropertySources(ConfigurableEnvironment environment,
ResourceLoader resourceLoader) {
// 自定义属性的加载
RandomValuePropertySource.addToEnvironment(environment);
// 开始加载操作
new Loader(environment, resourceLoader).load();
}
对比
SpringBoot2.4及以后,和SpringBoot2.4之前相比,多了读取config文件夹下的子文件夹里的配置文件的功能!如读取:file:./config/mysql/application.properties
容易踩坑:SpringBoot2.4及以后,将备份的配置文件保存到config/backup/文件夹里,会导致备份的配置文件属性也被读取