Spring "spring.profiles.include" 覆盖

Spring "spring.profiles.include" overrides

我的意图是在 spring 引导应用程序中有两个配置文件 - 开发和生产一个。开发配置文件只是为了覆盖生产配置文件的一些变量(例如内存数据库而不是云中的数据库)。由于我预计将来会对生产配置文件进行一些更改,因此在开发配置文件中复制变量似乎不是解决方案。

所以,在 Spring Reference 中,我读到 spring.profiles.include 应该只从引用的配置文件中添加属性。

Sometimes, it is useful to have profile-specific properties that add to the active profiles rather than replace them. The spring.profiles.include property can be used to unconditionally add active profiles.

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

申请-foo.yaml:

myproperty: 44

申请-bar.yaml:

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

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

The following profiles are active: foo,bar

我在另一个问题中按照此 answer 的建议将 spring.profiles.active=bar 添加到 application-bar.yaml,但它没有效果 - 当 属性 存在时没有区别或不(我也尝试使用破折号列表而不是逗号分隔值)。

我的问题是,它应该如何工作(然后 Spring 参考具有误导性)?如果是这样,有什么解决办法吗?

link 添加到 github 上的应用程序源代码。

根据 spring 引导文档 herespring.profiles.include 用于添加来自其他配置文件的属性。如果 属性 不在活动配置文件中,它将从其他配置文件添加 属性。但是如果它存在,那么它将覆盖并且最后一个被应用的获胜

Sometimes, it is useful to have profile-specific properties that add to the active profiles rather than replace them. The spring.profiles.include property can be used to unconditionally add active profiles.

我们实施 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-bar.yaml 中添加新的配置文件:

spring.profiles.include: foo,foo-override
myproperty: 33

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

顺序是:33 in bar44 in foo 覆盖 被 55 in foo-override 覆盖。

给定:

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

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

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

    1. 当配置文件 foo 或 boo 被激活时,属性来自 application-foo.yml(或 application-bar.yml)将 add/override 来自 application-default.yml.
    2. 当配置文件 foo,bar 被激活时,bar 中的属性将 add/override 来自 application-foo.yml 的属性,然后是来自 application-default.yml.
    3. 的属性

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

  2. 第二种情况(使用spring.profiles.include

    1. 来自 include 语句的属性 add/overrides 来自使用 spring.profiles.include
    2. 的 application-*.yml 文件的属性

    即:如果 application-boo.yml 包含 spring.profiles.include=foo,则 application-foo.bar adds/override properties from from application-bar.yml 的属性 add/override 来自 application-default.yml.

    的属性

    另一方面(我想)如果 application-boo.yml 包含 spring.profiles.include=default,foo 那么 application-foo.yml 中的属性将 add/override 来自 application-default.yml 的属性add/override 来自 application-bar.yml 的那些。所以myproperty: bar。我不建议将 defaultspring.profiles.include 结合使用,因为这样它会混合两种情况,并且考虑到 application-default.yml 在 springboot 中有特殊处理,覆盖策略是违反直觉的。

我也承认我一点也不喜欢在 application-*.yml 文件中使用 spring.profiles.active。我更喜欢使用系统属性(包括 Maven)或环境变量来激活配置文件。 IMO 它使整个配置文件对我来说更清晰。

如果根据我(上文)的推理,我走错了路,请告诉我。

Spring Boot 2.4 更改了包含多个配置文件的机制以使用新的 profile groups 功能,而不是在特定于配置文件的文档中使用 spring.profiles.include。这意味着您的配置不再对 Spring Boot 的新版本有效,需要更改。

也就是说,您的用例似乎不太适合配置文件组,因为它并没有真正结合两个配置文件,而是覆盖了默认值。因此,我建议使用建议 的方法,将公共属性和默认属性放在共享 application.yaml 文件中,并且只在特定配置文件的文档中包含特定于环境的值和覆盖。

application.yaml

spring:
  myproperty: 44 # Default value

申请-bar.yaml

spring:
  myproperty: 55 # Override default

请注意 Spring 引导支持 multi-document files,因此如果需要,可以将它们组合成一个 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.profiles.include,除非 legacy mode is enabled using spring.config.use-legacy-processing=true. Per the 2.4 Spring Boot Config Data Migration Guide:

you can still use the spring.profiles.include property, but only in non profile-specific documents.

此方法已被 profile groups 功能取代。根据 迁移指南:

As discussed above, it’s no longer possible to use spring.profiles.include in a profile-specific document so this file isn’t valid.

Since this use-case is quite common, we’ve tried to provide another way to support it. In Spring Boot 2.4 you can use the “profile groups” feature.

此功能记录在 Spring 引导参考指南的 Profile Groups 部分:

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.

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

The spring.profile.group property cannot be used in profile-specific documents.