如何使用其他配置文件覆盖特定于配置文件的属性?

时间:2017-11-16 12:42:32

标签: spring-boot

我目前在spring boot中有以下配置设置:

application.properties

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}

application-load-fixtures.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)位于同一位置,并且它们也都是特定于配置文件的。

有什么方法可以解决这个问题?

提前致谢!

1 个答案:

答案 0 :(得分:5)

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

然而,在经过一些测试和尝试之后,我非常确定它是这样的(或者至少以类似的方式): 可能某种地图用于收集所有不同地点和可能性的所有属性,您可以像记录here那样定义它们。例如,属性my.valueapplication.properties中定义,因此存储在提到的地图中。然后找到相同的属性作为Java系统属性。由于这种定义属性的方式在PropertySource中更高 - 它将覆盖之前在地图中找到的值。在此之前,根据文档很清楚,Java系统属性将获胜。

但是,当我们在相同的优先级别上来两个不同的来源,比如两个不同的配置文件特定属性文件时,我认为文档不是100%明确的。但它在 24.4

中说
  

如果指定了多个配置文件,则应用last-wins策略。例如,spring.profiles.active属性指定的配置文件将添加到通过SpringApplication API配置的配置文件之后,因此优先。

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

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