SpringBoot(十九):SpringBoot运行启动时执行3次SpringApplication#run(args)加载了哪些配置文件?以及配置文件之间的覆盖性。
bootstrap.yml(bootstrap.properties)用来程序引导时执行,应用于更加早期配置信息读取,如可以使用来配置application.yml中使用到参数等
application.yml(application.properties) 应用程序特有配置信息,可以用来配置后续各个模块中需使用的公共参数等。
加载过程中,配置文件加载顺序为:
bootstrap.yml > application.yml > application-dev(prod).yml
通过对代码进行Debug发现SpringApplication#run(...)方法被调用了3次。
项目结构:
监控加载的配置文件,断点设置在:ConfigFileApplicationListener#load(...) 501行,可以监控都读取了哪些配置文件。
最终监控到执行SpringApplication#run(args)的顺序:
@SpringBootApplication(scanBasePackages = {"com.dx"}, proxyBeanMethods = false) @EnableFeignClients(basePackages = {"com.dx.domain.feign"}) @EnableShackleTemplates(basePackages = {"com.dx.service"}) @EnableEurekaClient public class App { /** * 主程序入口(jar格式) * @param args 命令行参数 * @throws Exception 执行异常 */ public static void main(String[] args) throws Exception { configureApplication(new SpringApplicationBuilder()).run(args); } /** * 定义程序入口 * @param builder SpringApplicationBuilder * @return SpringApplicationBuilder */ private static SpringApplicationBuilder configureApplication(SpringApplicationBuilder builder) { return builder.sources(App.class).bannerMode(Banner.Mode.CONSOLE).logStartupInfo(true) .registerShutdownHook(true).web(WebApplicationType.SERVLET); } }
org.springframework.context.annotation.AnnotationConfigApplicationContext@7876d598, started on Tue Mar 13 11:10:31 CST 2021
SpringApplication#run(String... args)运行流程:
SpringApplication#run(String... args) |-ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments); SpringApplication#prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) |-listeners.environmentPrepared((ConfigurableEnvironment)environment); SpringApplicationRunListeners#environmentPrepared(ConfigurableEnvironment environment) |-listener.environmentPrepared(environment); EventPublishingRunListener#environmentPrepared(ConfigurableEnvironment environment) |-this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment)); SimpleApplicationEventMulticaster#multicastEvent(ApplicationEvent event) |-constructor(...) SimpleApplicationEventMulticaster#multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) |-this.invokeListener(listener, event); SimpleApplicationEventMulticaster#invokeListener(ApplicationListener<?> listener, ApplicationEvent event) |-this.doInvokeListener(listener, event); SimpleApplicationEventMulticaster#doInvokeListener(ApplicationListener listener, ApplicationEvent event) |-listener.onApplicationEvent(event); BootstrapApplicationListener#onApplicationEvent(ApplicationEnvironmentPreparedEvent event) |-context = this.bootstrapServiceContext(environment, event.getSpringApplication(), configName); BootstrapApplicationListener#bootstrapServiceContext(ConfigurableEnvironment environment, final SpringApplication application, String configName)
BootstrapApplicationListener#bootstrapServiceContext(...)源码分析:
private ConfigurableApplicationContext bootstrapServiceContext(ConfigurableEnvironment environment, final SpringApplication application, String configName) { StandardEnvironment bootstrapEnvironment = new StandardEnvironment(); MutablePropertySources bootstrapProperties = bootstrapEnvironment.getPropertySources(); Iterator var6 = bootstrapProperties.iterator(); while(var6.hasNext()) { PropertySource<?> source = (PropertySource)var6.next(); bootstrapProperties.remove(source.getName()); } String configLocation = environment.resolvePlaceholders("${spring.cloud.bootstrap.location:}"); String configAdditionalLocation = environment.resolvePlaceholders("${spring.cloud.bootstrap.additional-location:}"); Map<String, Object> bootstrapMap = new HashMap(); bootstrapMap.put("spring.config.name", configName); bootstrapMap.put("spring.main.web-application-type", "none"); if (StringUtils.hasText(configLocation)) { bootstrapMap.put("spring.config.location", configLocation); } if (StringUtils.hasText(configAdditionalLocation)) { bootstrapMap.put("spring.config.additional-location", configAdditionalLocation); } bootstrapProperties.addFirst(new MapPropertySource("bootstrap", bootstrapMap)); Iterator var9 = environment.getPropertySources().iterator(); while(var9.hasNext()) { PropertySource<?> source = (PropertySource)var9.next(); if (!(source instanceof StubPropertySource)) { bootstrapProperties.addLast(source); } } SpringApplicationBuilder builder = (new SpringApplicationBuilder(new Class[0])).profiles(environment.getActiveProfiles()).bannerMode(Mode.OFF).environment(bootstrapEnvironment).registerShutdownHook(false).logStartupInfo(false).web(WebApplicationType.NONE); SpringApplication builderApplication = builder.application(); if (builderApplication.getMainApplicationClass() == null) { builder.main(application.getMainApplicationClass()); } if (environment.getPropertySources().contains("refreshArgs")) { builderApplication.setListeners(this.filterListeners(builderApplication.getListeners())); } builder.sources(new Class[]{BootstrapImportSelectorConfiguration.class}); ConfigurableApplicationContext context = builder.run(new String[0]); context.setId("bootstrap"); this.addAncestorInitializer(application, context); bootstrapProperties.remove("bootstrap"); this.mergeDefaultProperties(environment.getPropertySources(), bootstrapProperties); return context; }
监控到尝试加载资源文件:
**加载 bootstrap 文件** file:./config/bootstrap.[properties|xml|yml|yaml] file:./bootstrap.[properties|xml|yml|yaml] classpath:/config/bootstrap.[properties|xml|yml|yaml] classpath:/bootstrap.[properties|xml|yml|yaml] **加载 bootstrap-composite 文件** file:./config/bootstrap-composite.[properties|xml|yml|yaml] file:./bootstrap-composite.[properties|xml|yml|yaml] classpath:/config/bootstrap-composite.[properties|xml|yml|yaml] classpath:/bootstrap-composite.[properties|xml|yml|yaml]
第一次SpringApplication#run执行过程中,SpringApplication#prepareEnvironment(...)执行过程中加载在资源文件:
application.yaml...
file:./config/application.[properties|xml|yml|yaml]
file:./application.[properties|xml|yml|yaml]
classpath:/config/application.[properties|xml|yml|yaml]
classpath:/application.[properties|xml|yml|yaml]
file:./config/application-composite.[properties|xml|yml|yaml]
file:./application-composite.[properties|xml|yml|yaml]
classpath:/config/application-composite.[properties|xml|yml|yaml]
classpath:/application-composite.[properties|xml|yml|yaml]
args = {String[4]@5280}
0 = "--spring.config.name=application"
1 = "--spring.cloud.bootstrap.enabled=false"
2 = "--encrypt.failOnError=false" 3 = "--spring.config.location=classpath:/config/uat/"
监控到尝试加载资源文件:
**加载 application 文件** classpath:/config/uat/application-default.[properties|xml|yml|yaml]
org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@784c5ef5, started on Tue Mar 13 11:16:25 CST 2021, parent: org.springframework.context.annotation.AnnotationConfigApplicationContext@7876d598
bootstrap.yml、application.yml、application-dev.yml配置文件之间覆盖性验证:
1)如果三个文件都配置了server.port,后加载的配置覆盖前者
加载顺序:bootstrap.yml->application.yml->applicaiton-dev.yml
2)如果是nacos的配置中心,必须配置到boostrap.yml
如果是bootstrap.yml、application.yml、application-dev.yml都配置了spring.cloud.nacos.config,那么是boostrap.yml中生效。
如果是bootstrap.yml中未配置,其他两个文件配置了,也不生效。spring.cloud.nacos.config采用默认值。
基础才是编程人员应该深入研究的问题,比如:
1)List/Set/Map内部组成原理|区别
2)mysql索引存储结构&如何调优/b-tree特点、计算复杂度及影响复杂度的因素。。。
3)JVM运行组成与原理及调优
4)Java类加载器运行原理
5)Java中GC过程原理|使用的回收算法原理
6)Redis中hash一致性实现及与hash其他区别
7)Java多线程、线程池开发、管理Lock与Synchroined区别
8)Spring IOC/AOP 原理;加载过程的。。。
【+加关注】。