Spring "spring.profiles.include"覆盖

34

我的意图是在Spring Boot应用程序中拥有两个配置文件 - 开发和生产。 开发配置文件仅旨在覆盖生产配置文件的某些变量(例如,使用内存数据库而不是云中的数据库)。 由于我期望未来对生产配置文件进行一些更改,因此在开发配置文件中复制变量似乎不是解决方案。

因此,在 Spring文档中,我读到spring.profiles.include 只会添加指定配置文件中的属性。

有时,具有特定于配置文件的属性并将其添加到活动配置文件中而不是替换它们非常有用。可以使用 spring.profiles.include属性无条件地添加活动配置文件。

但是,根据我的检查,它实际上是覆盖它。 因此,当有两个配置文件foo和bar时,在单独的yaml文件中:

application-foo.yaml:

myproperty: 44

应用程序栏(application-bar).yaml:

spring:
  profiles:
    include: foo
    active: bar,foo
myproperty: 55

在IDE中设置-Dspring.profiles.active=bar变量时,myproperty的运行时值为44。这意味着bar被覆盖了,而它原本只应该添加属性,而不是覆盖它们。启动应用程序时,我得到以下结果:

激活以下配置文件:foo,bar

我按照答案中提出的建议,在application-bar.yaml中添加了spring.profiles.active=bar,但没有效果-当属性存在或不存在时没有区别(我也尝试使用破折号列表而不是逗号分隔值)。

我的问题是,这就是它应该工作的方式吗(那么Spring Reference就是误导性的)?如果是,有没有解决方法?

github上添加链接以获取应用程序源代码。

5个回答

27

我们以稍微不同的方式实现了Spring的活动配置文件。假设默认属性文件application.yml包含所有默认值,在生产和开发环境中相同。

为生产和开发文件创建单独的属性,分别命名为application-prd.ymlapplication-dev.yml。这些文件可能包含额外的属性或覆盖一些默认属性。

在应用启动期间,我们将spring.profiles.active作为环境变量传递。例如,

-Dspring.profiles.active=prd

将会选取application-prd.yml以及application.yml

或者

-Dspring.profiles.active=dev

将会选取application-dev.yml以及application.yml


谢谢,我认为这对我的目的已经足够好了。它仍然不能让开发人员能够覆盖自定义属性文件,因此我需要创建额外的文件(最终有application.yaml、application-foo.yaml和application-bar.yaml),但只要我能够满足要求就可以了。 - Daniel Szymatowicz

14
根据Spring Boot文档此处所述,spring.profiles.include用于添加来自其他配置文件的属性。 如果该属性在活动配置文件中不存在,则将从其他配置文件中添加该属性。 但是,如果存在,则会覆盖前面的值,以最后一个应用的为准。
有时候,拥有特定于配置文件的属性且将其添加到活动配置文件中而不是替换非常有用。可以使用spring.profiles.include属性无条件地添加到活动配置文件中。

8
我知道这个链接 - 它提到了“spring.profiles.include”属性可以用来无条件地添加活动配置文件。但是这个描述对我来说有些模糊。不过没关系,那么有没有办法只从其他配置文件中导入设置,而不是让它们覆盖当前的设置呢? - Daniel Szymatowicz
这个引用没有意义,如何在不替换的情况下“无条件添加”?如果属性同时存在于两者中,哪一个会被使用?如果它被无条件地添加,那么它将替换已有的内容。如果它不会在已经存在时被添加,那就是有条件的添加。 - dan carter
好的,Spring文档所说的是无条件添加“配置文件”。它并不是在谈论添加“属性”。当然,一旦配置文件被添加,通常的替换规则适用于两者都存在的属性(后面的覆盖前面的)。 - dan carter

11

Spring Boot 2.4更新了包含多个配置文件的机制,使用了一个新的profile groups功能,而不是在特定配置文件中使用spring.profiles.include。这意味着您的配置已经无法适用于新版本的Spring Boot,需要进行更改。

尽管如此,您的使用情况似乎并不适合于使用配置文件组合功能,因为它更多的是覆盖默认值,而不是将两个配置文件组合在一起。因此,我建议采用另一个答案中建议的方法,将公共和默认属性放在共享的application.yaml文件中,只在特定配置文件中包含环境特定的值和覆盖。

application.yaml

spring:
  myproperty: 44 # Default value

application-bar.yaml

spring:
  myproperty: 55 # Override default

注意,Spring Boot支持多文档文件,因此如果需要,这些文件可以合并成一个单独的application.yaml文件:
spring:
  myproperty: 44 # Default value
---
spring.config.activate.on-profile: bar # These configs apply to the bar profile
spring:
  myproperty: 55 # Override default

相关的2.4变化

从Spring Boot 2.4开始,除非使用spring.config.use-legacy-processing=true启用遗留模式,否则无法在特定于配置文件的文档中使用spring.profiles.include。根据2.4 Spring Boot Config Data迁移指南:

您仍然可以在非特定于配置文件的文档中使用spring.profiles.include属性。

这种方法已被配置文件组功能所取代。根据迁移指南:

如上所述,不再能在特定配置文件中使用spring.profiles.include,因此该文件无效。
由于这种用例非常常见,我们尝试提供另一种支持方式。在Spring Boot 2.4中,您可以使用“配置文件组”功能。
此功能在Spring Boot参考指南的配置文件组部分有所记录。

A profile group allows you to define a logical name for a related group of profiles.

For example, we can create a production group that consists of our proddb and prodmq profiles.

spring:
  profiles:
    group:
      production:
      - "proddb"
      - "prodmq"

Our application can now be started using --spring.profiles.active=production to active the production, proddb and prodmq profiles in one hit.

迁移指南指出spring.profile.group属性不能在特定配置文件中使用。

spring.profile.group属性不能在特定配置文件中使用。


组只是配置文件列表的别名。它们可能会给人一种“文档”的印象,但实际上是“无用”的。只需在application-$name.yml中定义配置文件设置,并在application.yml中使用spring.profiles.active激活所需的配置文件即可。 - gavenkoa

7
你可以在application-bar.yaml中添加一个新的配置文件:
spring.profiles.include: foo,foo-override
myproperty: 33

---
spring.profiles: foo-override
myproperty: 55

顺序为:bar中的33foo中的44覆盖,再被foo-override中的55所覆盖。

2

给定:

  • 文件:application-default.yml,application-foo.yml,application-bar.yml
  • 在application-default.yml中,myproperty:default
  • 在application-foo.yml中,myproperty:foo
  • 在application-bar.yml中,myproperty:bar

我认为这两种使用配置文件的用例在含义上有点相反:

  1. 在最常见的情况下(-Dspring.profiles.active但没有spring.profiles.include):

    1. 当激活配置文件foo或boo时,来自application-foo.yml(或application-bar.yml)的属性将添加/覆盖来自application-default.yml的属性。
    2. 当激活配置文件foo、bar时,则来自bar的属性将添加/覆盖来自application-foo.yml的属性,然后再添加/覆盖来自application-default.yml的属性。

    例如:-Dspring.profiles.active=foo,bar,来自application-bar.yml的属性胜出(覆盖)-> myproperty: bar

  2. 在第二种情况下(使用spring.profiles.include):

    1. include语句中的属性将添加/覆盖使用spring.profiles.include的application-*.yml文件中的属性。

    即:如果application-boo.yml包含spring.profiles.include=foo,则来自application-foo.bar的属性将添加/覆盖来自application-bar.yml的属性,然后再添加/覆盖来自application-default.yml的属性。

    另一方面(我猜),如果application-boo.yml包括spring.profiles.include=default,foo,则来自application-foo.yml的属性将添加/覆盖来自application-default.yml的属性,然后再添加/覆盖来自application-bar.yml的属性。因此,myproperty: bar。我不建议在与spring.profiles.include组合使用时使用default,因为这样会混淆两种情况,并且覆盖策略在考虑springboot中的application-default.yml的特殊处理时是反直觉的。

我也承认我不太喜欢在application-*.yml文件中使用spring.profiles.active。我更喜欢使用系统属性(包括maven)或环境变量来激活配置文件。我认为这样可以让整个配置文件的使用更加清晰。

如果我的观点有误,请告诉我。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接