application.properties 是否可以依赖多个配置文件?

Is it possible to have application.properties depend on multiple profiles?

是否可以让 Spring 引导属性文件依赖于两个或多个配置文件?类似于 application-profile1-profile2.properties?

Spring Boot 不支持开箱即用。它仅支持描述的单个配置文件 here.

但是,它确实提供了足够的灵活性,可以使用 EnvironmentPostProcessor 添加您自己的 属性 源。

下面是一个如何实现这个的例子:

public class MultiProfileEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
    private final ResourceLoader resourceLoader = new DefaultResourceLoader();

    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        String[] activeProfiles = environment.getActiveProfiles();

        for (int i = 2; i <= activeProfiles.length; i++) {
            Generator.combination(activeProfiles).simple(i)
                    .forEach(profileCombination -> {
                        String propertySourceName = String.join("-", profileCombination);
                        String location = "classpath:/application-" + propertySourceName + ".properties";

                        if (resourceLoader.getResource(location).exists()) {
                            try {
                                environment.getPropertySources().addFirst(new ResourcePropertySource(propertySourceName, location));
                            } catch (IOException e) {
                                throw new RuntimeException("could not add property source '" + propertySourceName + "'", e);
                            }
                        }
                    });
        }
    }

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;
    }
}

有两点需要注意:

  • 此实现仅支持 .properties 个文件,但也可以轻松扩展到 .yml 个文件。
  • getActiveProfiles 已经 returns 配置文件中最后一个获胜的顺序。此实现依赖于此顺序并利用此顺序构建不同的文件名。即,如果活动配置文件是:profile1、profile2、profile3,则支持 application-profile1-profile3.properties 但不支持 application-profile3-profile1.properties,并且 application-profile1-profile3.properties 将覆盖 application-profile1.properties 或 [=17= 中定义的属性].
  • 此实现使用第三方库 com.github.dpaukov:combinatoricslib3 来创建不同的配置文件集。
  • 属性 源被添加到 属性 源列表的前面以覆盖现有源。但是,如果您有自定义的 属性 源应该优先,您需要稍微修改一下以按顺序考虑它们,即利用 Environment.addAfter.
  • 等方法
  • 使用 spring.factories 文件注册 EnvironmentPostProcessor。

我知道的方法有 4 种。

  1. 像 Asi Bross Said 一样以编程方式插入 .yaml.properties。使用ResourceLoaderYamlPropertySourceLoader插入。

  2. 使用.yaml。但是当你有另一个 spring 项目依赖它时它会被替换。

  3. 使用属性而不是配置文件。 (对于 api 项目)

    1. 使用一个@PropertySource定义属性文件A.
    2. 从属性文件 A 中获取变量并将它们分配给另一个 @PropertySource 文件路径表达式中的参数。

    例如:

    resources
    /-application.properties  <-- remove or empty,because it will be override by application project
    /-moduleA
         /-application.properties               <-- Intellij can identify properties files started with application-
         /-application-mysql-dev.properties
         /-application-psql-dev.properties
         /-application-psql-prod.properties
    

    resources/moduleA/application.properties内容:

    moduleA.custom.profile1=mysql
    moduleA.custom.profile2=dev
    

    Java 配置文件的内容:

    @SpringBootApplication
    @PropertySources({
            @PropertySource("/moduleA/application.properties"),
            @PropertySource("/moduleA/application-${moduleA.custom.profile1}-${moduleA.custom.profile2}.properties"),
    })
    public class ModuleConfig {}
    
  4. 使用属性而不是配置文件。 (申请项目)

    resources
    /-application.properties
    /-application-mysql-dev.properties
    /-application-psql-dev.properties
    /-application-psql-prod.properties
    

    resources/application.properties的内容:

    moduleA.custom.profile1=mysql
    moduleA.custom.profile2=dev
    

    SpringMvcApplication.java的内容:

    @SpringBootApplication
    @PropertySource("/application-${moduleA.custom.profile1}-${moduleA.custom.profile2}.properties")
    public class SpringMvcApplication {...}