我目前在 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-dev
和 load-fixtures
添加新的配置属性时,都必须向项目。
据我了解,配置文件特定属性优先于非配置文件特定属性。而且非默认位置属性优先于默认位置的属性。但在这里,两个配置文件(local-dev
和 load-fixtures
)位于同一位置,并且它们也都是特定于配置文件的。
解决这个问题的正确方法是什么?
提前致谢!
最佳答案
我最近遇到了完全相同的问题,并且必须弄清楚 Spring 应用于几个特定于配置文件的属性文件的优先级。不幸的是,这没有很好的记录,而且我没有找到负责该问题的代码的位置。
但是经过一些测试和尝试后,我很确定它的工作原理如下(或至少以类似的方式):
可能某种 map 用于收集所有不同地点和可能性的所有属性,您可以像记录的 here 那样定义它们。 。例如,属性 my.value
在 application.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/