本文从SpringBoot源码分析 配置文件的加载原理和配置文件的优先级
跟入源码之前,先提一个问题:
SpringBoot 既可以加载指定目录下的配置文件获取配置项,也可以通过启动参数(VM Options)传入配置项,为什么通过启动参数传入的配置项会“顶掉”配置文件中的配置?示例:
application.yml server.port: 8888 spring.profiles.active: dev
application-dev.yml
spring.think: hello在IDEA中使用命令行配置项
VM Options
-Dserver.port=5555
如下图:
启动结果:
Tomcat started on port(s): 5555 (http) with context path ''
同时在application.yml 和 启动参数(VM options)中设置 server.port, 最终采用了 启动参数 中的值。
下面开始从main函数启动处,跟入SpringBoot源码,看看SpringBoot是如何处理的。系统说明
JDK:1.8
SpringBoot 版本: 2.0.2.RELEASE
IDE: IntelliJ IDEA 2017跟入源码正文
#ApplicationConfigLoadFlow.java public static void main(String[] args) { SpringApplication.run(ApplicationConfigLoadFlow.class, args); }
从SpringApplication.run 函数开始,一个方法一个方法的跟入源码。需要跟入的方法给与注释或高亮。IDEA 快捷键:进入方法: Ctrl + 鼠标左键光标前进/后退: Ctrl + Shirt + 右方向键/左方向键
依次跟入源码:
#SpringApplication.java return run(new Class<?>[] { primarySource }, args)
#SpringApplication.java return new SpringApplication(primarySources).run(args);
#SpringApplication.java
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
//跟入
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
configureIgnoreBeanInfo(environment);
进入public ConfigurableApplicationContext run(String... args) 方法后,我们重点看 prepareEnvironment这个方法。
这个方法之前的源码的从类名和源码注释上知道stopWatch用于计时,上下文context还未初始化,listeners监听器存储了EventPushlingRunListener。
通过IDEA 一行行debug可以看到是在 prepareEnvironment方法执行后,server.port 配置项才被加载入 environment 环境配置中。
如下图所示。注意:配置文件中的配置还未载入,请先接着往后看。
因此,我们重新打断点跟入prepareEnvironment方法。
#SpringApplication.java
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
//跟入
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
同样的套路,通过debug发现实在getOrCreateEnvironment方法执行后得到server.port的值
#SpringApplication.java
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
}
if (this.webApplicationType == WebApplicationType.SERVLET) {
//跟入
return new StandardServletEnvironment();
}
虚拟机启动参数的加载 是在StandardServletEnvironment 的实例化过程中完成的。
跟入StandardServletEnvironm