SpringBoot 的配置加载主要通过事件广播机制来完成,即由 SpringApplication 启动过程中,通过调用 SpringApplicationRunListener.environmentPrepared() 触发 ConfigFileApplicationListener 对 ApplicationEvent 事件的响应。
由于本文主要分析配置加载的流程,对于启动过程中的事件传播不做过多的介绍,直接从 ConfigFileApplicationListener 开始学习具体的配置加载流程。
1 |
|
在 ConfigFileApplicationListener 里面,实际上是可以监听两类事件的,其中对 ApplicationEnvironmentPreparedEvent 事件的处理就是我们要学习的重点。该事件处理主要由 EnvironmentPostProcessor 完成的,默认情况下有三种 EnvironmentPostProcessor 实现,其中两种从 META-INF/spring.factories 加载获得,最后一种则是 ConfigFileApplicationListener 本身,也是我们要学习的重点,其实现了 EnvironmentPostProcessor 接口,并对 postProcessEnvironment() 方法进行了重写。
1 |
|
整个流程分为两个步骤:
- 通过内部类
Loader完成Environment的加载 - 完成
Environment与SpringApplication的绑定
ConfigFileApplicationListener#Loader 实现
1 | public void load() { |
在内部类 Loader 的实现里面,主要包括以下几个步骤:
- 添加
Environment.setActiveProfiles()指定(或默认)的Profile到 LIFO 队列,并在队列最后添加一个空元素,以保证默认的配置文件优先加载,如:application.yml优先application-dev.yml加载; - 遍历
Profile队列,依次进行加载,流程分为两个步骤:- 按查询路径、文件名、后缀名等查找配置文件
- 解析配置文件,并将其添加到对应的分组
- 查找配置文件所在路径
- 按配置的查询路径查找配置文件,默认为:
file:./config/,file:./,classpath:/config/,classpath:/,可通过spring.config.location进行指定; - 相同路径下,按配置的文件名前缀依次查找配置文件,默认为
application,可通过spring.config.name进行调整; - 相同的文件名前缀,则按
PropertySourcesLoader支持的文件名后缀进行查找,默认为:properties,xml,yml,yaml,其中properties,xml为PropertiesPropertySourceLoader提供支持,yml,yaml由YamlPropertySourceLoader提供支持;
- 按配置的查询路径查找配置文件,默认为:
- 解析配置文件
- 对于
properties及xml文件,直接加载profile对应的文件即可; - 对于
yml及yaml文件,由于该类文件语法中支持分块配置,Spring 通过spring.profiles配置项可将文件分成多个块,加载过程也可以按块加载。未指定 profile 的情况下,直接加载application.yml的默认块,若指定 profile 为 dev,则按application-dev.yml#default,application-dev.yml#dev,application.yml#dev进行依次加载;
- 对于
- 将解析后所得的
PropertySources添加到Environment;
PropertySourcesLoader 实现
配置文件的解析与组装都是由 PropertySourcesLoader 完成的,PropertySourcesLoader 会将加载到的配置信息进行分组,并封装到 EnumerableCompositePropertySource 之中。
1 | public PropertySource<?> load(Resource resource, String group, String name, String profile) throws IOException { |
总结
Environment 加载需要理解文件的查找方式、加载顺序及加载完成后的配置优先级。
查找方式:在文中已经描述的很清楚,按路径、文件名、后缀名依次逐级递进查找。
加载顺序:相对就复杂了很多,以一张图概括如下:
图3.3 Environment加载顺序

这里对 yaml 文件画的比较简单,实际上它与 yml 类似,也是分三步加载的。
- 配置优先级:与加载顺序非常类似,唯一的区别是,组级别的顺序是相反的,先加载的组优先级低于后加载的组,即上图中的 dev 组会覆盖掉 default 组的配置。
最后,再献上一张实验的结果图,与上图的内容一致,任意理解一个即可。
图3.4 Environment加载实验结果
