本文基于spring boot 2.2.0 release版本
spring boot配置文件加载是通过ConfigFileApplicationListener监听器完成的。
先来看一下该类的注释:
* {@link EnvironmentPostProcessor} that configures the context environment by loading
* properties from well known file locations. By default properties will be loaded from
* 'application.properties' and/or 'application.yml' files in the following locations:
* file:./config/
* file:./
* classpath:config/
* classpath:
* The list is ordered by precedence (properties defined in locations higher in the list
* override those defined in lower locations).
* Alternative search locations and names can be specified using
* {@link #setSearchLocations(String)} and {@link #setSearchNames(String)}.
* Additional files will also be loaded based on active profiles. For example if a 'web'
* profile is active 'application-web.properties' and 'application-web.yml' will be
* considered.
* The 'spring.config.name' property can be used to specify an alternative name to load
* and the 'spring.config.location' property can be used to specify alternative search
* locations or specific files.
上面注释的大概意思是说,该类默认加载file:./config/、file:./、classpath:config/、classpath:路径下的’application.properties’和’application.yml’文件,且这些路径是按照优先级排序的,前面路径下的文件会覆盖后面路径的。可以调用setSearchLocations方法修改上述路径位置,该类也会根据激活的profile加载对应环境的配置文件,属性spring.config.name和spring.config.location也可以用来设置加载配置文件的文件名和路径。
下面详细分析该类加载配置文件的原理。
一、创建ConfigFileApplicationListener
ConfigFileApplicationListener是监听器,实现ApplicationListener接口。我们使用spring boot,需要先创建SpringApplication对象,那么先来看一下SpringApplication类的构造方法:
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//加载ApplicationListener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
getSpringFactoriesInstances方法用于从spring.factories文件中加载ApplicationListener实现类。ConfigFileApplicationListener就配置在spring.factories文件中。
二、事件触发加载配置文件
对配置文件加载是通过事件触发的。
spring boot启动过程会发布ApplicationEnvironmentPreparedEvent事件,然后调用ConfigFileApplicationListener.onApplicationEvent方法处理该事件。
下面我们看一下onApplicationEvent方法:
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationEnvironmentPreparedEvent) {
//处理ApplicationEnvironmentPreparedEvent事件
onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
}
if (event instanceof ApplicationPreparedEvent) {
onApplicationPreparedEvent(event);
}
}
private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
//从spring.factories文件加载EnvironmentPostProcessor对象
List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();
//ConfigFileApplicationListener也实现了EnvironmentPostProcessor
postProcessors.add(this);
//对EnvironmentPostProcessor实现类排序
AnnotationAwareOrderComparator.sort(postProcessors);
for (EnvironmentPostProcessor postProcessor : postProcessors) {
//调用postProcessEnvironment
postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());
}
}
从onApplicationEnvironmentPreparedEvent中可以看到接下来将继续调用ConfigFileApplicationListener.postProcessEnvironment方法。
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {