覆盖 Spring Boot 配置项

Spring Boot中的配置项默认是在application.properties中。如:

1
test.item=lefer

现在考虑两个场景:

  • 场景1:不修改配置文件将test.item的值更改为另一个值
  • 场景2:lefer 是一个密文,使用前需要做转换

下面说说这2个场景的实现方法。

通过命令行参数覆盖配置项

场景1的实现非常简单,只要在启动时,指定对应参数就能覆盖配置项,比如:

java -Dtest.item=orous -jar test.jar

这时 Spring Boot 会自动将该配置项的值替换成 orous 。更进一步,如果在命令参数里指定的参数在配置文件中不存在,那么等同于在配置文件中新增了一个配置项和对应值。之所以会出现这种现象,是Spring Boot的配置加载机制决定的,从官方文档可以看到,Spring Boot 加载配置项的顺序如下:

  1. home目录下的devtools全局设置属性(~/.spring-boot-devtools.properties,如果devtools激活)。
  2. 测试用例上的@TestPropertySource注解。
  3. 测试用例上的@SpringBootTest#properties注解。
  4. 命令行参数
  5. 来自SPRING_APPLICATION_JSON的属性(环境变量或系统属性中内嵌的内联JSON)。
  6. ServletConfig初始化参数。
  7. ServletContext初始化参数。
  8. 来自于java:comp/env的JNDI属性。
  9. Java系统属性(System.getProperties())。
  10. 操作系统环境变量。
  11. RandomValuePropertySource,只包含random.*中的属性。
  12. 没有打进jar包的Profile-specific应用属性(application-{profile}.properties和YAML变量)。
  13. 打进jar包中的Profile-specific应用属性(application-{profile}.properties和YAML变量)。
  14. 没有打进jar包的应用配置(application.properties和YAML变量)。
  15. 打进jar包中的应用配置(application.properties和YAML变量)。
  16. @Configuration类上的@PropertySource注解。
  17. 默认属性(使用SpringApplication.setDefaultProperties指定)。

命令行参数的优先级高于打进jar包的配置文件。而且还看到外部配置文件优先级是高于内部配置文件的,所以我们还可以用jar外的配置文件去覆写jar内的配置文件。

通过应用监听器在初始化应用时覆盖属性值

场景2可以通过实现ApplicationListener<ApplicationEnvironmentPreparedEvent>接口来实现。示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class PropertyModify implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
@Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
ConfigurableEnvironment environment = event.getEnvironment();
String oldValue = environment.getProperty("test.item");
System.out.println("old value:" + oldValue);
String newValue = "orous"; //这里可以实现转换逻辑
Properties props = new Properties();
props.put("test.item", newValue);
environment.getPropertySources().addFirst(new PropertiesPropertySource("my_properties", props));
}
}

然后在启动类里注册这个监听器:

1
2
3
4
// SpringApplication.run(BootestsApplication.class, args);
SpringApplication app = new SpringApplication(BootestsApplication.class);
app.addListeners(new PropertyModify());
app.run(args);

此时再启动,你会发现 test.item 的值已经被改成了 orous 。这种场景非常适合 password 的配置。

END