likes
comments
collection
share

springboot配置文件加载顺序和机制

作者站长头像
站长
· 阅读数 16

前言

springboot提供强大的,多样的配置加载,你知道他的加载机制嘛?他是怎么运作的?我们怎么自定义扩展呢?今天就来扒一扒spring的配置文件加载顺序和机制。只有了解了,我们才能在多配置中找到正确的配置,处理问题

测试

测试1

当只有一个配置文件时 resources/application.yml并配置:

client:
	name: 张三

输出如下:

springboot配置文件加载顺序和机制

测试2

当存在两个配置文件 resources/application.yml 配置1resources/application.properties 配置2 。resources/application.yml 中的配置不变,resources/application.properties 如下:

client.name = 李四

输出如下:

springboot配置文件加载顺序和机制

结论:可以看到 配置2 和 配置1 同时存在时 , application.properties 中的配置将会覆盖 application.yml 中的配置属性。

测试3

当存在两个配置文件 resources/application.yml 配置1resources/config/application.yml 配置2

输出如下:

springboot配置文件加载顺序和机制

结论:可以看到 配置2 中的配置会覆盖 配置1 中的属性。

测试4

在项目根路径添加配置文件。这种在idea中测试需要创建文件,然后拷贝target目录中,然后命令启动项目测试: java -jar boot-client-0.0.1-SNAPSHOT.jar

结论:/config/application.yml > /application.yml

结论

  • 项目根路径上(projectPath)的配置文件优先级高于类路径下的配置(resources)文件
  • 同级别目录下 config下的配置高于 当前跟路径下的配置。比如 resources/application.properties 中的配置优先级高于 resources/application.yml
  • 同级别目录下 application.properties 配置优先级高于 application.yml
  • 经过测试,在使用 java -jar 启动项目时, spring.config.location 指定的配置文件优先级最高。 比如:java -jar boot-client-0.0.1-SNAPSHOT.jar --spring.config.name=applicationtest.yml --spring.config.location=file:/Users/zhaolangjing/code/github/poe4j/boot-client/target/applicationName.yml
  • 配置文件加载获取属性配置优先级:

spring.config.location >

${project.path}/config/application.properties >

${project.path}/config/application.yml >

${project.path}/application.properties >

${project.path}/application.yml >

${classpath}/config/application.properties >

${classpath}/config/application.yml >

${classpath}/application.properties >

${classpath}/application.yml >

原理解析

StandardServletEnvironment

我们在 StandardServletEnvironment 类中的 initPropertySources() 方法上打上断点,当

initPropertySources方法执行结束完成之后,我们可以看到属性: List<PropertySource<?>> propertySourceList 列表中属性文件的排序。如下图:

springboot配置文件加载顺序和机制

从图中我们可以看出,spring给对象属性赋值的逻辑,给配置文件拍好顺序后,采用最前匹配原则赋值。

ConfigDataEnvironmentPostProcessor

ConfigDataEnvironmentPostProcessor就是用来解析配置文件的后置处理器。大家可以自行去阅读源码理解其加载配置文件的过程。

EnvironmentPostProcessor

springboot环境后置处理器接口。 那么假如我们想自定义一些环境配置,就可以实现该接口,比如我们远程加载一些配置文件,比如从SVN,git等等。

  • 允许在刷新应用程序上下文之前自定义应用程序。
  • Environment环境后处理器实现必须在 中 META-INF/spring.factories注册,使用此类的完全限定名作为键。
  • 实现 Ordered 希望按特定顺序调用,可以实现接口或使用 @Order 注释。

自定义实现环境后置处理器

我们自定义实现一个后置处理器,用于替换我们前面前面示例代码中的 client.name的值。要实现这个功能要实现以下功能:

  • 实现 EnvironmentPostProcessor 接口并实现 postProcessEnvironment 方法。
    • 添加配置内容(可以使用 Properties 也可以用 Map)client.name = "奥特曼"
    • 将配置内容按照规定格式放入容器列表中
    • 放入时要注意放入的位置,我们应该放在默认加载的配置文件最前面的位置
  • 添加 META-INF/spring.factories , 并写入我们自己的后置处理器,让spring容器加载该bean。

代码如下:

第一步,添加META-INF/spring.factories 并写入自己的处理器类

org.springframework.boot.env.EnvironmentPostProcessor=com.poe4j.boot.client.MyEnvironmentPostProcessor

第二步 MyEnvironmentPostProcessor 实现EnvironmentPostProcessor。

@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
	// 1 
    Properties myProperties = new Properties();
    myProperties.setProperty("client.name", "奥特曼");
    myProperties.setProperty("client.path", MyEnvironmentPostProcessor.class.getName());

    // 2
    PropertiesPropertySource PropertiesPropertySource = new PropertiesPropertySource(
            "myClient", myProperties);

    // 3
    MutablePropertySources mutablePropertySources = environment.getPropertySources();
    Optional<PropertySource<?>> first = mutablePropertySources.stream().filter(v -> v.getName().contains("application")).findFirst();
    if (first.isPresent()) {
        mutablePropertySources.addBefore(first.get().getName(), propertySources);
    } else {
        mutablePropertySources.addLast(propertySources);
    }
}

1 使用Properties 添加配置,设置值:client.name = “奥特曼”。

2 将我们添加的配置内容实例化到 PropertiesPropertySource 。

3 将 PropertiesPropertySource 装到 mutablePropertySources中。这一步要注意放入的位置。比如我这里演示的是先通过 mutablePropertySources 迭代拿到 已有的通过配置文件加载的 PropertySource 。 如果找到了,那么就将我们的配置文件放到该文件的前面。如果没找到就放到 mutablePropertySources 的最后。ps:mutablePropertySources.stream().filter(v -> v.getName().contains("application")).findFirst() 这段代码的查找逻辑并不是很严谨,这里只是为了演示方便。请大家自行修改。

我们查看一个实际结果:

springboot配置文件加载顺序和机制

可以看到我们的自定义处理器的配置确实生效了。

附录

问题1:

在遇到application.properties文件中文乱码时(我使用的idea),需要在idea的setting中修改 Editor -> File Encodings ,做出如下修改:

将Properties Files (*.properties)下的Default encoding for properties files设置为UTF-8,将Transparent native-to-ascii conversion前的勾选上,一定要吧Transparent native-to-ascii conversion勾选上,不然不生效。

springboot配置文件加载顺序和机制

转载自:https://juejin.cn/post/7223358128329785405
评论
请登录