spring-boot - 如何使用不同的配置文件覆盖特定于配置文件的属性?

标签 spring-boot

我目前在 Spring Boot 中有以下配置设置:

应用程序属性

app.database.host=${DB_HOST}
app.database.port=${DB_PORT}
app.database.name=${DB_NAME}
app.database.user=${DB_USER}
app.database.password=${DB_PASSWORD}
app.database.schema=${DB_SCHEMA:public}
spring.datasource.url=jdbc:postgresql://${app.database.host}:${app.database.port}/${app.database.name}
spring.datasource.username=${app.database.user}
spring.datasource.password=${app.database.password}
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect

application-local-dev.properties:

app.database.host=${DB_HOST:localhost}
app.database.port=${DB_PORT:5432}
app.database.name=${DB_NAME:db_name}
app.database.user=${DB_USER:root}
app.database.password=${DB_PASSWORD:root}
app.database.schema=${DB_SCHEMA:public}

应用程序加载固定装置.properties:

spring.profiles.include=local-dev
spring.profiles.active=load-fixtures,local-dev
app.database.name=${DB_NAME:db_name}_fixtures

这里的想法是,在默认模式下启动应用程序时,如果缺少数据库名称等关键属性,它将无法启动。 它们应该通过环境变量传递。

出于开发目的,在设置项目时这是不必要的开销,因为我们有一个带有静态凭据的 docker 容器,我想将它们作为默认值提供。因此,我创建了一个配置文件 local-dev ,它将使用默认值来连接到我们的 docker 数据库,并且仍然能够通过环境变量覆盖它们,以防有人需要。 到这里为止,一切正常。

但是现在,我们还有一个配置文件,用于将夹具加载到数据库中(删除所有表,重新创建并用数据填充它们)。 出于显而易见的原因,我想确保这不能在任意数据库上完成,因此我创建了一个配置文件 load-fixtures ,它应该继承 local-dev 的所有属性,并且覆盖数据库名称。然而,这种做法似乎是错误的。我可以在 spring 日志中看到配置文件已正确加载:

2017-11-16 13:32:11.508  INFO 23943 --- [           main] Main:
The following profiles are active: load-fixtures,local-dev

但它仍然使用 local-dev 配置文件提供的数据库名称。

当我删除该行

app.database.name=${DB_NAME:db_name}

local-dev 配置文件中,它可以工作。

但是,我想要避免的是,每当我们向 local-devload-fixtures 添加新的配置属性时,都必须向项目。

据我了解,配置文件特定属性优先于非配置文件特定属性。而且非默认位置属性优先于默认位置的属性。但在这里,两个配置文件(local-devload-fixtures)位于同一位置,并且它们也都是特定于配置文件的。

解决这个问题的正确方法是什么?

提前致谢!

最佳答案

我最近遇到了完全相同的问题,并且必须弄清楚 Spring 应用于几个特定于配置文件的属性文件的优先级。不幸的是,这没有很好的记录,而且我没有找到负责该问题的代码的位置。

但是经过一些测试和尝试后,我很确定它的工作原理如下(或至少以类似的方式): 可能某种 map 用于收集所有不同地点和可能性的所有属性,您可以像记录的 here 那样定义它们。 。例如,属性 my.valueapplication.properties 中定义,并存储在上述映射中。然后找到与Java系统属性相同的属性。由于这种定义属性的方式在 PropertySource 顺序中较高,因此它将覆盖之前在 map 中找到的值。到目前为止,根据文档可以清楚地看出 Java 系统属性将获胜。

但是,当我们在相同的优先级上找到两个不同的源(例如两个不同的配置文件特定属性文件)时,我认为文档并不是 100% 清晰。然而24.4中说:

If several profiles are specified, a last-wins strategy applies. For example, profiles specified by the spring.profiles.active property are added after those configured through the SpringApplication API and therefore take precedence.

也许这只是这里的例子不是最佳的,或者我只是没有正确理解它。但我想“最后获胜”策略也适用于 spring.profiles.active 中定义的所有配置文件。这意味着如果您运行 java -jar -Dspring.profiles.active=dev,fix application.jar ,application-fix.properties 中的属性将覆盖属性的值在 application-dev.properties 中具有相同的 key 。

因此,在您的情况下,考虑应用程序的输出,我猜您指定了类似 java -jar -Dspring.profiles.active=load-fixtures,local-dev application.jar 之类的内容。如果我是正确的,您只需将其更改为 java -jar -Dspring.profiles.active=local-dev,load-fixtures application.jar

关于spring-boot - 如何使用不同的配置文件覆盖特定于配置文件的属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47329937/

相关文章:

spring - 用于在单元测试中导入 bean 的 @Import 与 @ContextConfiguration

java - IncationTargetException 有问题

Gradle:添加系统属性失败

java - 从终端运行使用 Maven 编译的主类

java - 为什么 @ConfigurationProperties 类的默认值不起作用?

java - Thymeleaf Security 不适用于 Spring Boot 1.3.5

spring-boot - Spring Boot节俭

jackson - 如何确保 Spring Boot 额外的 Jackson 模块是相同版本?

来自配置的 Spring 注释值

java - Springboot : difference between responsibilities of dependencies grouped as STARTER vs CORE