SpringBoot 和多个外部配置文件

我有多个要从类路径加载的属性文件。在 /src/main/resources下有一个默认设置,它是 myapp.jar的一部分。我的 springcontext期望文件在类路径上。也就是说。

<util:properties id="Job1Props"
location="classpath:job1.properties"></util:properties>


<util:properties id="Job2Props"
location="classpath:job2.properties"></util:properties>

我还需要用外部集重写这些属性的选项。我在 cwd中有一个外部配置文件夹。根据 Spring 启动 doc 配置文件夹应该在类路径上。但是,doc 并不清楚它是否只会从那里覆盖 application.properties或者在 config 中覆盖所有属性。

当我测试它时,只有 application.properties被拾取,其余的属性仍然从 /src/main/resources被拾取。我已经尝试将它们作为逗号分隔的列表提供给 spring.config.location,但是仍然没有覆盖默认设置。

如何使多个外部配置文件覆盖默认配置文件?

作为解决方案,我目前使用的 app.config.location(应用程序特定属性) ,我通过命令行提供

java -jar myapp.jar app.config.location=file:./config

我把 applicationcontext改成了

< util: properties id = “ Job1Props” Location = “{ app.config.location }/job1.properties”>

<util:properties id="Job2Props"
location="{app.config.location}/job2.properties"></util:properties>

这就是我在加载 Application 时如何在文件和类路径之间进行分离的方法。
编辑:

//pseudo code


if (StringUtils.isBlank(app.config.location)) {
System.setProperty(APP_CONFIG_LOCATION, "classpath:");
}

我真的不想使用上面的解决方案,并让 Spring 覆盖类路径上的所有外部配置文件,就像它覆盖 application.properties文件一样。

593683 次浏览

更新 : 由于 spring.config.location 的行为现在覆盖了默认值,而不是添加到默认值。您需要 使用 spring.config.additional-location来保持默认值。这是从1.x 到2的行为变化。X


使用 SpringBoot 时,属性按以下顺序加载(请参阅 SpringBoot 参考指南中的 外部化配置)。

  1. 命令行参数。
  2. Java 系统属性(System.getProperties ())。
  3. 操作系统环境变量。
  4. 来自 java 的 JNDI 属性: comp/env
  5. 只具有随机属性的 RRandom ValuePropertySource。 * 。
  6. 在打包的 jar 之外的应用程序属性(Application.properties,包括 YAML 和配置文件变体)。
  7. 在 jar 中打包的应用程序属性(Application.properties,包括 YAML 和配置文件变体)。
  8. @ Configuration 类上的@PropertySource 注释。
  9. 默认属性(使用 SpringApplication.setDefaultProperties 指定)。

当解析属性时(例如,@Value("${myprop}")解析是以相反的顺序进行的(因此从9开始)。

要添加不同的文件,您可以使用 spring.config.location属性,它使用逗号分隔的属性文件列表或文件位置(目录)。

-Dspring.config.location=your/config/dir/

上面的代码将添加一个目录,用于查询 application.properties文件。

-Dspring.config.location=classpath:job1.properties,classpath:job2.properties

这将把2个属性文件添加到加载的文件中。

默认的配置文件和位置是在额外指定的 spring.config.location之前加载的,这意味着后者将始终覆盖前面的配置文件中设置的属性。(另请参阅 Spring 引导参考指南的 这部分)。

如果 spring.config.location包含目录(而不是文件) ,那么它们应该以/结尾(并且在加载之前,它们将与从 spring.config.name生成的名称一起附加)。始终使用默认的搜索路径 classpath:,classpath:/config,file:,file:config/,与 spring.config.location的值无关。通过这种方式,您可以在 application.properties中为应用程序设置默认值(或者使用 spring.config.name选择的任何其他基名) ,并在运行时用不同的文件覆盖它,保持默认值。

看一下 PropertyPlaceholderConfigrer,我发现它比注释更容易使用。

例如:。

@Configuration
public class PropertiesConfiguration {




@Bean
public PropertyPlaceholderConfigurer properties() {
final PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
//        ppc.setIgnoreUnresolvablePlaceholders(true);
ppc.setIgnoreResourceNotFound(true);


final List<Resource> resourceLst = new ArrayList<Resource>();


resourceLst.add(new ClassPathResource("myapp_base.properties"));
resourceLst.add(new FileSystemResource("/etc/myapp/overriding.propertie"));
resourceLst.add(new ClassPathResource("myapp_test.properties"));
resourceLst.add(new ClassPathResource("myapp_developer_overrides.properties")); // for Developer debugging.


ppc.setLocations(resourceLst.toArray(new Resource[]{}));


return ppc;
}

我刚刚遇到了与此类似的问题,并最终找到了原因: application.properties 文件的所有权和 rwx 属性错误。因此,当 tomcat 启动 application.properties 文件时,它位于正确的位置,但是属于另一个用户:

$ chmod 766 application.properties


$ chown tomcat application.properties

我也有同样的问题。我希望能够在启动时用外部文件覆盖内部配置文件,类似于 Spring Boot application.properties 检测。 在我的例子中,它是一个 user.properties 文件,其中存储了我的应用程序用户。

我的要求:

从以下位置加载文件(按此顺序)

  1. 类路径
  2. 工作目录的一个 abc 0亚目。
  3. 工作目录
  4. 从启动时命令行参数给出的目录或文件位置

我想出了以下解决方案:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.PathResource;
import org.springframework.core.io.Resource;


import java.io.IOException;
import java.util.Properties;


import static java.util.Arrays.stream;


@Configuration
public class PropertiesConfig {


private static final Logger LOG = LoggerFactory.getLogger(PropertiesConfig.class);


private final static String PROPERTIES_FILENAME = "user.properties";


@Value("${properties.location:}")
private String propertiesLocation;


@Bean
Properties userProperties() throws IOException {
final Resource[] possiblePropertiesResources = {
new ClassPathResource(PROPERTIES_FILENAME),
new PathResource("config/" + PROPERTIES_FILENAME),
new PathResource(PROPERTIES_FILENAME),
new PathResource(getCustomPath())
};
// Find the last existing properties location to emulate spring boot application.properties discovery
final Resource propertiesResource = stream(possiblePropertiesResources)
.filter(Resource::exists)
.reduce((previous, current) -> current)
.get();
final Properties userProperties = new Properties();


userProperties.load(propertiesResource.getInputStream());


LOG.info("Using {} as user resource", propertiesResource);


return userProperties;
}


private String getCustomPath() {
return propertiesLocation.endsWith(".properties") ? propertiesLocation : propertiesLocation + PROPERTIES_FILENAME;
}


}

现在应用程序使用类路径资源,但是也检查其他给定位置的资源。存在的最后一个资源将被挑选和使用。 我可以使用 java-jar myapp.jar —— properties ties.location =/directory/myproperties ties.properties 来启动我的应用程序,使用一个属性位置来浮动我的船。

这里有一个重要的细节: 在@Value 注释中使用一个空的 String 作为 properties. location 的默认值,以避免未设置属性时出现错误。

Location 的约定是: 使用属性文件的目录或路径作为 properties. location。

如果只想重写特定的属性,可以将 setIgnoreResourceNotFind (true)的 PropertiesFactoryBean 与资源数组一起作为位置使用。

我确信这个解决方案可以扩展到处理多个文件..。

剪辑

这里是我的多文件解决方案:)像以前一样,这可以与 PropertiesFactoryBean 组合。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.PathResource;
import org.springframework.core.io.Resource;


import java.io.IOException;
import java.util.Map;
import java.util.Properties;


import static java.util.Arrays.stream;
import static java.util.stream.Collectors.toMap;


@Configuration
class PropertiesConfig {


private final static Logger LOG = LoggerFactory.getLogger(PropertiesConfig.class);
private final static String[] PROPERTIES_FILENAMES = {"job1.properties", "job2.properties", "job3.properties"};


@Value("${properties.location:}")
private String propertiesLocation;


@Bean
Map<String, Properties> myProperties() {
return stream(PROPERTIES_FILENAMES)
.collect(toMap(filename -> filename, this::loadProperties));
}


private Properties loadProperties(final String filename) {
final Resource[] possiblePropertiesResources = {
new ClassPathResource(filename),
new PathResource("config/" + filename),
new PathResource(filename),
new PathResource(getCustomPath(filename))
};
final Resource resource = stream(possiblePropertiesResources)
.filter(Resource::exists)
.reduce((previous, current) -> current)
.get();
final Properties properties = new Properties();


try {
properties.load(resource.getInputStream());
} catch(final IOException exception) {
throw new RuntimeException(exception);
}


LOG.info("Using {} as user resource", resource);


return properties;
}


private String getCustomPath(final String filename) {
return propertiesLocation.endsWith(".properties") ? propertiesLocation : propertiesLocation + filename;
}


}

这是一种使用弹簧启动的简单方法

Java

@Configuration
@Profile("one")
@PropertySource("file:/{selected location}/app.properties")
public class TestClass {


@Autowired
Environment env;


@Bean
public boolean test() {
System.out.println(env.getProperty("test.one"));
return true;
}
}

应用程序属性上下文,在你的 选定地点

test.one = 1234

你的 弹簧启动应用程序

@SpringBootApplication


public class TestApplication {


public static void main(String[] args) {
SpringApplication.run(testApplication.class, args);
}
}

和预定义的 应用性能上下文

spring.profiles.active = one

您可以编写任意多的配置类,只需设置 Spring.profile 激活 = 配置文件名/名称{用逗号分隔}即可启用/禁用它们

正如您所看到的,Spring boot 非常棒,只是需要一些时间来熟悉它,值得一提的是,您也可以在字段中使用@Value

@Value("${test.one}")
String str;

在 Spring 启动时,Spring.config.location 可以正常工作,只需提供逗号分隔的属性文件。

请参阅下面的代码

@PropertySource(ignoreResourceNotFound=true,value="classpath:jdbc-${spring.profiles.active}.properties")
public class DBConfig{


@Value("${jdbc.host}")
private String jdbcHostName;
}
}

可以将 jdbc.properties 的默认版本放在应用程序中。

java -jar target/myapp.jar --spring.config.location=classpath:file:///C:/Apps/springtest/jdbc.properties,classpath:file:///C:/Apps/springtest/jdbc-dev.properties

根据使用 spring.profiles.active 属性设置的配置文件值,将拾取 jdbc.host 的值。 所以当(在窗户上)

set spring.profiles.active=dev

Host 将从 jdbc-dev. properties 获取值。

为了

set spring.profiles.active=default

Host 将从 jdbc.properties 获取值。

Spring boot 允许我们为不同的环境编写不同的配置文件,例如,我们可以为生产环境、 qa 环境和本地环境提供单独的属性文件

Application-local. properties 文件,根据我的本地机器进行配置

spring.profiles.active=local


spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=users
spring.data.mongodb.username=humble_freak
spring.data.mongodb.password=freakone


spring.rabbitmq.host=localhost
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.port=5672


rabbitmq.publish=true

类似地,我们可以根据需要编写 application-prod. properties 和 application-qa. properties 的任意多个属性文件

然后编写一些脚本来启动不同环境的应用程序,例如。

mvn spring-boot:run -Drun.profiles=local
mvn spring-boot:run -Drun.profiles=qa
mvn spring-boot:run -Drun.profiles=prod

我发现这是一个可以遵循的有用模式:

@RunWith(SpringRunner)
@SpringBootTest(classes = [ TestConfiguration, MyApplication ],
properties = [
"spring.config.name=application-MyTest_LowerImportance,application-MyTest_MostImportant"
,"debug=true", "trace=true"
]
)

在这里,我们重写了“ application.yml”的使用,以使用“ application-MyTest _ LowerImport. yml”和“ application-MyTest _ Mostimportant. yml”
(Spring 还将查找. properties 文件)

还包括额外的奖金是调试和跟踪设置,在一个单独的行,以便您可以注释出来,如果需要的话; ]

调试/跟踪非常有用,因为 Spring 会转储它加载的所有文件和它试图加载的文件的名称。
在运行时,您将在控制台中看到这样的行:

TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_MostImportant.properties' (file:./config/application-MyTest_MostImportant.properties) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_MostImportant.xml' (file:./config/application-MyTest_MostImportant.xml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_MostImportant.yml' (file:./config/application-MyTest_MostImportant.yml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_MostImportant.yaml' (file:./config/application-MyTest_MostImportant.yaml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_LowerImportance.properties' (file:./config/application-MyTest_LowerImportance.properties) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_LowerImportance.xml' (file:./config/application-MyTest_LowerImportance.xml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_LowerImportance.yml' (file:./config/application-MyTest_LowerImportance.yml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_LowerImportance.yaml' (file:./config/application-MyTest_LowerImportance.yaml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application-MyTest_MostImportant.properties' (file:./application-MyTest_MostImportant.properties) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application-MyTest_MostImportant.xml' (file:./application-MyTest_MostImportant.xml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application-MyTest_MostImportant.yml' (file:./application-MyTest_MostImportant.yml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application-MyTest_MostImportant.yaml' (file:./application-MyTest_MostImportant.yaml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application-MyTest_LowerImportance.properties' (file:./application-MyTest_LowerImportance.properties) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application-MyTest_LowerImportance.xml' (file:./application-MyTest_LowerImportance.xml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application-MyTest_LowerImportance.yml' (file:./application-MyTest_LowerImportance.yml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application-MyTest_LowerImportance.yaml' (file:./application-MyTest_LowerImportance.yaml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application-MyTest_MostImportant.properties' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application-MyTest_MostImportant.xml' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application-MyTest_MostImportant.yml' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application-MyTest_MostImportant.yaml' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application-MyTest_LowerImportance.properties' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application-MyTest_LowerImportance.xml' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application-MyTest_LowerImportance.yml' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application-MyTest_LowerImportance.yaml' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/application-MyTest_MostImportant.properties' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/application-MyTest_MostImportant.xml' resource not found
DEBUG 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Loaded config file 'file:/Users/xxx/dev/myproject/target/test-classes/application-MyTest_MostImportant.yml' (classpath:/application-MyTest_MostImportant.yml)
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/application-MyTest_MostImportant.yaml' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/application-MyTest_LowerImportance.properties' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/application-MyTest_LowerImportance.xml' resource not found
DEBUG 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Loaded config file 'file:/Users/xxx/dev/myproject/target/test-classes/application-MyTest_LowerImportance.yml' (classpath:/application-MyTest_LowerImportance.yml)
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/application-MyTest_LowerImportance.yaml' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_MostImportant-test.properties' (file:./config/application-MyTest_MostImportant-test.properties) resource not found

Spring boot1.X 和 Spring Boot2.X 不提供与 Externalized Configuration相同的选项和行为。

Deinum 的非常好的回答是指 SpringBoot1特性。
我将在这里更新 Spring Boot 2

环境属性源和秩序

SpringBoot2使用一个非常特殊的 PropertySource顺序,该顺序的设计目的是允许对值进行合理的重写。按以下顺序考虑属性:

  • 主目录上的 Devtools 全局设置属性 (~/. spring-boot-devtools. properties when devtools is active) .

  • 测试中的 @TestPropertySource注释。

  • 测试中的 @SpringBootTest#properties注释属性 直线参数

  • 属性(嵌入在 环境变量或系统财产)

  • ServletConfig初始参数。

  • ServletContext初始参数。

  • 来自 java:comp/env的 JNDI 属性。

  • Java 系统属性(System.getProperties())。

  • 操作系统环境变量。

  • 只具有随机属性的 RandomValuePropertySource。 * 。

  • 特定于配置文件的应用程序属性 (application-{profile}.properties和 YAML 变体)

  • 在 jar 中打包的特定于配置文件的应用程序属性 (application-{profile}.properties和 YAML 变体)

  • 打包的 jar 之外的应用程序属性 (application.properties和 YAML 变体)

  • 打包在 jar 中的应用程序属性 (application.properties和 YAML 变体)

  • @Configuration类上的 @PropertySource注释。默认值 属性(通过设置 (SpringApplication.setDefaultProperties) .

若要指定外部属性文件,您应该会对以下选项感兴趣:

  • 特定于配置文件的应用程序属性 (application-{profile}.properties和 YAML 变体)

  • 打包的 jar 之外的应用程序属性 (application.properties和 YAML 变体)

  • @Configuration类上的 @PropertySource注释。默认值 属性(通过设置 (SpringApplication.setDefaultProperties) .

您只能使用这3个选项中的一个,或者根据您的需求组合它们。
例如,对于非常简单的情况,只使用特定于概要文件的属性就足够了,但在其他情况下,您可能希望同时使用特定于概要文件的属性、默认属性和 @PropertySource

Application.properties 文件的默认位置

关于 application.properties文件(和变体) ,在默认情况下,Spring 加载它们并按照以下顺序在环境中添加它们的属性:

  • 工作目录的 a/config 子目录

  • 工作目录

  • 类路径/配置包

  • 类路径根

更高的优先级是如此的字面化:
classpath:/,classpath:/config/,file:./,file:./config/.

如何使用具有特定名称的属性文件?

默认位置并不总是足够的: 默认位置如默认文件名(application.properties)可能不适合。此外,在 OP 问题中,您可能需要指定除 application.properties以外的多个配置文件(和变体)。
因此,spring.config.name将是不够的。

在这种情况下,应该使用 spring.config.location环境属性(以逗号分隔的目录位置或文件路径列表)提供显式位置。
要想了解文件名模式,最好使用文件路径列表而不是目录列表。
例如:

java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties

这种方式是最详细的,只是指定文件夹,但它也是非常精细地指定我们的配置文件和清楚地记录有效使用的属性的方式。

Location 现在替换默认位置,而不是添加到它们

在 SpringBoot1中,spring.config.location参数将在 Spring 环境中添加指定的位置。
但是从 SpringBoot2开始,spring.config.location替换了 Spring 环境中指定位置使用的默认位置,如 在文件中所述。

配置自定义配置位置时,请使用 它们替换默认位置 例如,如果 spring.config.location配置为 classpath:/custom-config/ file:./custom-config/搜查令 变成如下:

  1. file:./custom-config/

  2. classpath:custom-config/

spring.config.location现在是一种确保必须显式指定任何 application.properties文件的方法。
对于不应该打包 application.properties文件的超级 JAR,这是相当不错的。

为了在使用 Spring Boot 2时保持旧的 spring.config.location行为,您可以使用新的 spring.config.additional-location属性而不是仍然添加位置 如文件所述spring.config.location:

或者,当使用以下命令配置自定义配置位置时,也可以使用 spring.config.additional-location,它们除了使用 默认位置。


在实践中

因此,假设与 OP 问题中一样,您需要指定2个外部属性文件,并且在 uber jar 中包含1个属性文件。

仅使用指定的配置文件:

-Dspring.config.location=classpath:/job1.properties,classpath:/job2.properties,classpath:/applications.properties

将配置文件添加到默认位置:

-Dspring.config.additional-location=classpath:/job1.properties,classpath:/job2.properties

在最后一个示例中,classpath:/applications.properties不是必需的,因为缺省位置有这个,而且这里的缺省位置没有被覆盖,而是被扩展了。

@ mxsb 解决方案的修改版本,它允许我们定义多个文件,在我的例子中是 yml 文件。

在我的应用程序开发中。我添加了这个配置,它允许我在它们中注入所有包含-dev.yml 的 yml。这也可以是特定文件的列表。 “ classspath:/test/test.yml,classspath:/test2/test.yml”

application:
properties:
locations: "classpath*:/**/*-dev.yml"

这有助于获得属性映射。

@Configuration


public class PropertiesConfig {


private final static Logger LOG = LoggerFactory.getLogger(PropertiesConfig.class);


@Value("${application.properties.locations}")
private String[] locations;


@Autowired
private ResourceLoader rl;


@Bean
Map<String, Properties> myProperties() {
return stream(locations)
.collect(toMap(filename -> filename, this::loadProperties));
}


private Properties loadProperties(final String filename) {


YamlPropertySourceLoader loader = new YamlPropertySourceLoader();
try {
final Resource[] possiblePropertiesResources = ResourcePatternUtils.getResourcePatternResolver(rl).getResources(filename);
final Properties properties = new Properties();
stream(possiblePropertiesResources)
.filter(Resource::exists)
.map(resource1 -> {
try {
return loader.load(resource1.getFilename(), resource1);
} catch (IOException e) {
throw new RuntimeException(e);
}
}).flatMap(l -> l.stream())
.forEach(propertySource -> {
Map source = ((MapPropertySource) propertySource).getSource();
properties.putAll(source);
});


return properties;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

但是,如果像我的情况一样,我需要为每个配置文件分割 yml 文件并加载它们,并在 bean 初始化之前将其直接注入 Spring 配置中。

config
- application.yml
- application-dev.yml
- application-prod.yml
management
- management-dev.yml
- management-prod.yml

你就明白了

组成部分略有不同

@Component
public class PropertiesConfigurer extends     PropertySourcesPlaceholderConfigurer
implements EnvironmentAware, InitializingBean {


private final static Logger LOG = LoggerFactory.getLogger(PropertiesConfigurer.class);


private String[] locations;


@Autowired
private ResourceLoader rl;
private Environment environment;


@Override
public void setEnvironment(Environment environment) {
// save off Environment for later use
this.environment = environment;
super.setEnvironment(environment);
}


@Override
public void afterPropertiesSet() throws Exception {
// Copy property sources to Environment
MutablePropertySources envPropSources = ((ConfigurableEnvironment) environment).getPropertySources();
envPropSources.forEach(propertySource -> {
if (propertySource.containsProperty("application.properties.locations")) {
locations = ((String) propertySource.getProperty("application.properties.locations")).split(",");
stream(locations).forEach(filename -> loadProperties(filename).forEach(source ->{
envPropSources.addFirst(source);
}));
}
});
}




private List<PropertySource> loadProperties(final String filename) {
YamlPropertySourceLoader loader = new YamlPropertySourceLoader();
try {
final Resource[] possiblePropertiesResources = ResourcePatternUtils.getResourcePatternResolver(rl).getResources(filename);
final Properties properties = new Properties();
return stream(possiblePropertiesResources)
.filter(Resource::exists)
.map(resource1 -> {
try {
return loader.load(resource1.getFilename(), resource1);
} catch (IOException e) {
throw new RuntimeException(e);
}
}).flatMap(l -> l.stream())
.collect(Collectors.toList());
} catch (IOException e) {
throw new RuntimeException(e);
}
}

}

当我试图解决这个问题的时候遇到了很多问题。这是我的设置,

开发环境: Windows 10, Java: 1.8.0 _ 25, Spring Boot: 2.0, Spring: 5.0.7发布

我发现 Spring 坚持“合理的配置默认值”的概念。这意味着,您必须将所有属性文件作为 war 文件的一部分。进入之后,可以使用“—— spring.config.add-location”命令行属性覆盖它们,以指向外部属性文件。但是,如果属性文件不是原始 war 文件的一部分,这将不起作用。

演示代码: Https://github.com/gselvara/spring-boot-property-demo/tree/master

如果希望覆盖 application.properties 文件中指定的值,可以在运行应用程序时更改活动配置文件,并为配置文件创建应用程序属性文件。因此,举例来说,让我们指定活动配置文件“覆盖”,然后假设您已经创建了名为“ application-覆盖”的新应用程序属性文件。属性下,然后可以运行

java -jar yourApp.jar --spring.profiles.active="override" --spring.config.location="file:/tmp/,classpath:/"

在 spring.config.location 下指定的值按相反的顺序计算。因此,在我的示例中,首先计算类争用,然后计算文件值。

如果 jar 文件和应用程序覆盖. properties 文件在工作目录中,那么实际上可以简单地使用

java -jar yourApp.jar --spring.profiles.active="override"

因为 SpringBoot 会为您找到属性文件

如果资源文件夹中有 application-intranet.properties,则可以使用类似的 -Dspring.profiles.active=intranet。 注意: Intranet 是我特定的文件名,你的应该是不同的