Insight springboot 默认配置文件加载实现

简介

Spring Boot allows you to externalize your configuration so you can work with the same application code in different environments.

You can use properties files, YAML files, environment variables and command-line arguments to externalize configuration.

Spring Boot uses a very particular PropertySource order that is designed to allow sensible overriding of values.

参考:https://docs.spring.io/spring-boot/docs/1.5.15.RELEASE/reference/htmlsingle/#boot-features-external-config

springboot 基本包含所有配置的形式,自带的配置文件、默认的配置文件、命令行入参、运行容器的环境变量、工程指定的配置文件。all in one,服务不可谓不周到,并且根据约定习惯,提供合理的加载顺序和覆盖机制。

配置文件的格式支持key-value、yaml、json。

spring 的黑魔法总是很多,本文主要探究application-{profile}.properties的加载实现。

调用链

SpringApplication#run()
SpringApplication#prepareEnvironment()
SpringApplicationRunListeners#environmentPrepared()
SimpleApplicationEventMulticaster#multicastEvent()
ConfigFileApplicationListener#onApplicationEnvironmentPreparedEvent()
ConfigFileApplicationListener#postProcessEnvironment()
ConfigFileApplicationListener#addPropertySources()

application-{profile}.properties的加载实现

通过嵌套循环,尝试按照如下的规则加载符合的配置文件。

  1. 遍历所有的profiles
  2. 遍历所有约定的路径 outside of your packaged jar、packaged inside your jar
  3. 遍历所有约定的文件名,默认application
  4. 遍历所有约定文件的格式,[properties, xml, yml, yaml]
// The default profile for these purposes is represented as null. We add it
// last so that it is first out of the queue (active profiles will then
// override any settings in the defaults when the list is reversed later).
this.profiles.add(null);

// 使用while的原因:随着配置文件的解析,可能会有新的profiles 增加,保证所有的profiles 都会遍历到
while (!this.profiles.isEmpty()) {
	Profile profile = this.profiles.poll();
    // [file:./config/, file:./, classpath:/config/, classpath:/]
	for (String location : getSearchLocations()) {
		if (!location.endsWith("/")) {
			// location is a filename already, so don't search for more
			// filenames
			load(location, null, profile);
		}
		else {
            // 默认application
			for (String name : getSearchNames()) {
                // 尝试加载不同后缀、不同profile的配置文件
				load(location, name, profile);
			}
		}
	}
	this.processedProfiles.add(profile);
}

addConfigurationProperties(this.propertiesLoader.getPropertySources());

关于ApplicationListener 使用的思考

通过查看源码,发现ApplicationEventMulticaster 分发事件的时候,支持异步调用,这样的话,配置文件注册到容器中是随机的,这样不会影响到约定的配置文件顺序吗?

支持异步的原因

文档中有说明:By default, all listeners are invoked in the calling thread. This allows the danger of a rogue listener blocking the entire application, but adds minimal overhead. Specify an alternative task executor to have listeners executed in different threads, for example from a thread pool.

同时:文档也指出如果使用线程池异步分发,需要注意的点。However, note that asynchronous execution will not participate in the caller's thread context (class loader, transaction association) unless the TaskExecutor explicitly supports this.

配置文件顺序的保障

通过强制指定注册的位置,保证我们读取配置列表的顺序永远一致!

if (existingSources.contains(DEFAULT_PROPERTIES)) {
	existingSources.addBefore(DEFAULT_PROPERTIES, configurationSources);
}
else {
	existingSources.addLast(configurationSources);
}

总结

通过分析默认配置文件解析的实现,发现spring boot框架为了自适应和智能,做了非常多的工作。简约而不简单。

对于多场景配置文件的支持,兼容约定配置的设计,以及配置文件规则约定的实现和解析,都是值得揣摩和反复思考的。

框架对于具体需求的实现、兼容性、扩展性的设计,对于我们日常应用开发都有很大的借鉴意义。

其他

json格式的配置加载实现:org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor

properties配置文件加载实现:org.springframework.boot.env.PropertiesPropertySourceLoader

yaml 配置文件加载实现:org.springframework.boot.env.YamlPropertySourceLoader

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值