领先一步
VMware 提供培训和认证,以加快您的进度。
了解更多Spring Boot 2.4.0.M2 已发布,它带来了一些关于加载application.properties
和application.yml
文件方式的有趣变化。
如果你的应用程序只使用单个application.properties
或application.yml
文件,这种相当典型的设置,你可能不会注意到任何区别。但是,如果你的应用程序使用了更复杂的设置(例如特定于配置文件的属性),你可能需要继续阅读以了解我们做了哪些更改以及原因。
在最近版本的Spring Boot中,我们一直在努力改进对Kubernetes的支持。我们在Spring Boot 2.3中想要添加但未能添加的一项功能是对卷挂载配置的支持。
卷挂载配置是Kubernetes的一项流行功能,其中使用ConfigMap
指令将配置直接显示在文件系统上。你可以挂载包含多个键和值的组合的完整YAML文件,也可以使用更简单的目录树格式,其中文件名是键,文件的内容是值。
我们希望同时提供这两种支持,并以一种与我们现有的application.properties
和application.yml
支持自然融合的方式。为此,我们需要修改令人头疼的ConfigFileApplicationListener
类。
几年前,来自视频游戏《Trap Adventure 2》的一些有趣的片段开始流行起来。它们非常类似于软件中可能发生的情况。有时你只是发现自己有一些很难更改的代码区域。在Spring Boot中,ConfigFileApplicationListener
最终变成了这些“陷阱冒险”之一。
这并不是说代码写得很糟糕,或者缺少测试。只是当我们向其中添加功能时,我们最终把自己弄得一团糟。
我们对这段代码的两个主要问题与特定于配置文件的文档(主要是YAML)有关。即
你可以从特定于配置文件的文档中启用其他配置文件。
很难知道文档将按什么顺序添加。
以下是一个示例
spring.profiles: !dev spring.profiles.include: local security.user.password: userc
这里我们有一个多文档YAML文件(一个由三个用---
分隔的逻辑文档组成的单个文件)。
如果你使用--spring.profiles.active=prod
运行,那么security.user.password
的值是多少?runlocal
属性是否已设置?你确定吗?由于在处理时该配置文件未激活,中间文档是否已包含?
我们经常会遇到关于此文件处理逻辑的问题,但是每当我们尝试修复它们时,就会为其他人破坏某些东西。我们最终决定唯一前进的道路是重新考虑整个事情。
因此,在Spring Boot 2.4中,我们计划对加载属性和YAML文件的方式进行两项重大更改
文档将按定义的顺序加载。
配置文件不再可以从特定于配置文件的文档中激活。
从Spring Boot 2.4开始,加载属性和YAML文件时将应用一个简单的规则。文件中较低位置声明的属性将覆盖较高位置的属性。
这遵循普通的.properties
文件已经使用的相同排序规则。可以认为每一行都在一个Map
中放入一个条目。当将具有相同键的新值放入Map
时,任何现有条目都将被替换。
遵循这些规则,给定一个多文档YAML文件,较低的文档将覆盖较高文档中的值
test: "overridden-value"
在Spring Boot 2.4中,我们决定将类似YAML的多文档支持引入Java属性文件。多文档属性文件使用注释(#
)后跟熟悉的三个破折号表示法来分割文档(我们选择使用注释,这样现有的IDE工具就不会中断)。
例如,上述YAML代码段的属性等效项将是
test=value #--- test=overridden-value
上面的例子有点人为,因为它实际上并没有意义总是覆盖一个值。更常见的设置是声明第二个文档只在特定配置文件下激活。
在Spring Boot 2.3中,你将使用spring.profiles
键来执行此操作。在Spring Boot 2.4中,我们决定将属性更改为spring.config.activate.on-profile
。
例如,如果我们只想在dev
配置文件激活时覆盖test
,我们可以使用以下内容
test=value #--- spring.config.activate.on-profile=dev test=overridden-value
你仍然可以使用spring.profiles.active
属性从application.properties
或application.yaml
文件中激活或包含配置文件。
例如,以下是完全有效的
test=value spring.profiles.active=local #--- spring.config.activate.on-profile=dev test=overridden value
你不再允许做的一件事是将该属性与spring.config.activate.on-profile
结合使用。例如,以下文件现在将抛出异常
test=value #--- spring.config.activate.on-profile=dev spring.profiles.active=local # 将失败 test=overridden value
我们希望这项新的限制最终会使你的application.properties
和application.yml
文件更容易理解和推理。我们也希望它能使Spring Boot本身更容易管理和维护。但是,我们知道至少有一个有效的用例,人们希望将一个配置文件扩展到多个子配置文件中。为了支持这一点,我们正在添加一个名为“配置文件组”的功能。
配置文件组是 Spring Boot 2.4 中的一项新功能,允许您将单个配置文件扩展到多个子配置文件。例如,假设您有一组复杂的 `@Configuration` 类,您可以使用 `@Profile` 注解有条件地启用它们。您可能有一个带有 `@Profile("proddb")` 的数据库配置,一个带有 `@Profile("prodmq")` 的消息配置等等。
使用多个独立的配置文件可能会使您的代码更容易理解,但在部署方面并不理想。您不希望强制用户记住他们必须始终同时激活 `proddb`、`prodmq`、`prodmetrics` 等。相反,您只需要他们能够激活单个 `prod` 配置文件即可。组允许您做到这一点。
要定义一个组,您可以在 `application.properties` 或 `application.yml` 文件中使用 `spring.profiles.group` 属性。例如:
spring.profiles.group.prod=proddb,prodmq,prodmetrics
现在我们已经解决了配置文件处理的基本问题,我们终于可以考虑我们想要提供的新的功能了。我们在 Spring Boot 2.4 中交付的主要功能是支持导入附加配置。
在早期版本的 Spring Boot 中,除了 `application.properties` 和 `application.yml` 之外,导入其他属性或 yaml 文件非常困难。您可以使用 `spring.config.additional-location` 属性,但是您需要尽早设置它,并且它对可以处理的文件类型非常有限。
使用最新的里程碑版本,您可以在 `application.properties` 或 `application.yml` 文件中直接使用新的 `spring.config.import` 属性。例如,您可能希望导入一个“git忽略”的 `developer.properties` 文件,以便您团队中的任何开发人员都可以快速更改仅供他们使用的属性。
application.name=myapp spring.config.import=developer.properties
您甚至可以将 `spring.config.import`声明与 `spring.config.activate.on-profile` 属性结合使用。例如,这里我们只在激活 `prod` 配置文件时加载 `prod.properties`
spring.config.activate.on-profile=prod spring.config.import=prod.properties
导入可以被认为是附加文档,插入到声明它们的文档下方。它们遵循与常规多文档文件相同的自上而下的顺序:无论声明多少次,导入都只会导入一次。
导入定义使用类似 URL 的语法作为其值。如果您的位置没有前缀,则它被认为是常规文件或文件夹。但是,如果您使用 `configtree:` 前缀,则表示您告诉 Spring Boot 您期望在该位置找到一个 Kubernetes 风格的卷挂载配置树。
例如,您可以在 `application.properties` 中声明以下内容:
spring.config.import=configtree:/etc/config
如果您有以下挂载内容:
etc/ +- config/ +- my/ | +- application +- test
最终,您的 Spring `Environment` 中将包含 `my.application` 和 `test` 属性。`my.application` 的值将是 `/etc/config/my/application` 的内容,`test` 的值将是 `/etc/config/test` 的内容。
如果您只想在特定云平台上激活卷挂载配置树(或任何属性),您可以使用 `spring.config.activate.on-cloud-platform` 属性。它的工作方式类似于 `spring.config.activate.on-profile` 属性,但使用 `CloudPlatform` 值而不是配置文件名称。
如果我们只想在部署到 Kubernetes 时启用上面的 configtree 示例,我们可以执行以下操作:
spring.config.activate.on-cloud-platform=kubernetes spring.config.import=configtree:/etc/config
在 `spring.config.import` 属性中指定的 location 字符串是完全可插入的,可以通过编写一些自定义类来扩展。我们预计第三方库将来可能会开始支持自定义位置。例如,您可以想象第三方 jar 支持 `archaius://…`、`vault://…` 或 `zookeeper://…` 等位置。
如果您有兴趣添加其他位置支持,请查看 `org.springframework.boot.context.config` 包中 `ConfigDataLocationResolver` 和 `ConfigDataLoader` 的 javadoc。
如果您正在升级现有的 Spring Boot 应用程序,并且您不希望使用所有这些新功能,您可以切换回旧的处理器。为此,您可以将 `spring.config.use-legacy-processing` 设置为 `true` 到您的 `application.properties` 或 `application.yml` 文件中。这应该可以让您获得与 Spring Boot 2.3 应用程序相同的应用程序配置处理。
如果您确实发现需要切换到旧版处理,因为我们错过了一个特定的用例,请在 GitHub 上提出问题,我们将尝试解决它。
我们希望新的配置数据处理类有用,并且不会造成太多升级难题。如果您想了解更多信息,您可以查看更新的参考文档。