从配置文件中获取属性应该是SpringBoot开发中最为常用的功能之一,但就是这么常用的功能,仍然有很多开发者在这个方面踩坑。
我整理了几种获取配置属性的方式,目的不仅是要让大家学会如何使用,更重要的是弄清配置加载、读取的底层原理,一旦出现问题可以分析出其症结所在,而不是一报错取不到属性,无头苍蝇般的重启项目,在句句卧槽中逐渐抓狂~
以下示例源码 Springboot 版本均为 2.7.6
下边我们一一过下这几种玩法和原理,看看有哪些是你没用过的!话不多说,开始搞~
一、Environment
使用 Environment 方式来获取配置属性值非常简单,只要注入Environment类调用其方法getProperty(属性key)即可,但知其然知其所以然,简单了解下它的原理,因为后续的几种获取配置的方法都和它息息相关。
@Slf4j
@SpringBootTest
public class EnvironmentTest {
@Resource
private Environment env;
@Test
public void var1Test() {
String var1 = env.getProperty("env101.var1");
log.info("Environment 配置获取 {}", var1);
}
}
1、什么是 Environment?
Environment 是 springboot 核心的环境配置接口,它提供了简单的方法来访问应用程序属性,包括系统属性、操作系统环境变量、命令行参数、和应用程序配置文件中定义的属性等等。
2、配置初始化
Springboot 程序启动加载流程里,会执行SpringApplication.run中的prepareEnvironment()方法进行配置的初始化,那初始化过程每一步都做了什么呢?
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
/**
* 1、创建 ConfigurableEnvironment 对象:首先调用 getOrCreateEnvironment() 方法获取或创建
* ConfigurableEnvironment 对象,该对象用于存储环境参数。如果已经存在 ConfigurableEnvironment 对象,则直接使用它;否则,根据用户的配置和默认配置创建一个新的。
*/
ConfigurableEnvironment environment = getOrCreateEnvironment();
/**
* 2、解析并加载用户指定的配置文件,将其作为 PropertySource 添加到环境对象中。该方法默认会解析 application.properties 和 application.yml 文件,并将其添加到 ConfigurableEnvironment 对象中。
* PropertySource 或 PropertySourcesPlaceholderConfigurer 加载应用程序的定制化配置。
*/
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 3、加载所有的系统属性,并将它们添加到 ConfigurableEnvironment 对象中
ConfigurationPropertySources.attach(environment);
// 4、通知监听器环境参数已经准备就绪
listeners.environmentPrepared(bootstrapContext, environment);
/**
* 5、将默认的属性源中的所有属性值移到环境对象的队列末尾,
这样用户自定义的属性值就可以覆盖默认的属性值。这是为了避免用户无意中覆盖了 Spring Boot 所提供的默认属性。
*/
DefaultPropertiesPropertySource.moveToEnd(environment);
Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
"Environment prefix cannot be set via properties.");
// 6、将 Spring Boot 应用程序的属性绑定到环境对象上,以便能够正确地读取和使用这些配置属性
bindToSpringApplication(environment);
// 7、如果没有自定义的环境类型,则使用 EnvironmentConverter 类型将环境对象转换为标准的环境类型,并添加到 ConfigurableEnvironment 对象中。
if (!this.isCustomEnvironment) {
EnvironmentConverter environmentConverter = new EnvironmentConverter(getClassLoader());
environment = environmentConverter.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
}
// 8、再次加载系统配置,以防止被其他配置覆盖
ConfigurationPropertySources.attach(environment);
return environment;
}
看看它的配置加载流程步骤:
-
创建 环境对象
ConfigurableEnvironment
用于存储环境参数; -
configureEnvironment
方法加载默认的application.properties
和application.yml
配置文件;以及用户指定的配置文件,将其封装为 PropertySource 添加到环境对象中; -
attach()
: 加载所有的系统属性,并将它们添加到环境对象中; -
listeners.environmentPrepared()
: 发送环境参数配置已经准备就绪的监听通知; -
moveToEnd()
: 将 系统默认 的属性源中的所有属性值移到环境对象的队列末尾,这样用户自定义的属性值就可以覆盖默认的属性值。 -
bindToSpringApplication