Externalized Configuration

Spring Boot 允许你外部化配置,以便可以在不同的环境中使用相同的应用程序代码。你可以使用各种外部配置源,包括 Java 属性文件、YAML 文件、环境变量和命令行参数。

Spring Boot lets you externalize your configuration so that you can work with the same application code in different environments. You can use a variety of external configuration sources including Java properties files, YAML files, environment variables, and command-line arguments.

可以使用 @Value 批注将属性值直接注入到 Bean 中,通过 Spring 的 Environment 抽象访问,或通过 @ConfigurationPropertiesbound to structured objects

Property values can be injected directly into your beans by using the @Value annotation, accessed through Spring’s Environment abstraction, or be bound to structured objects through @ConfigurationProperties.

Spring Boot 使用了一个非常特殊的 PropertySource 顺序,该顺序旨在允许合理地覆盖值。后面的属性源可以覆盖前面定义的值。源按以下顺序考虑:

Spring Boot uses a very particular PropertySource order that is designed to allow sensible overriding of values. Later property sources can override the values defined in earlier ones. Sources are considered in the following order:

  1. Default properties (specified by setting SpringApplication.setDefaultProperties).

  2. {url-spring-framework-javadoc}/org/springframework/context/annotation/PropertySource.html[@PropertySource] annotations on your @Configuration classes. Please note that such property sources are not added to the Environment until the application context is being refreshed. This is too late to configure certain properties such as logging. and spring.main. which are read before refresh begins.

  3. Config data (such as application.properties files).

  4. A RandomValuePropertySource that has properties only in random.*.

  5. OS environment variables.

  6. Java System properties (System.getProperties()).

  7. JNDI attributes from java:comp/env.

  8. ServletContext init parameters.

  9. ServletConfig init parameters.

  10. Properties from SPRING_APPLICATION_JSON (inline JSON embedded in an environment variable or system property).

  11. Command line arguments.

  12. properties attribute on your tests. Available on @SpringBootTest and the test annotations for testing a particular slice of your application.

  13. {url-spring-framework-javadoc}/org/springframework/test/context/DynamicPropertySource.html[@DynamicPropertySource] annotations in your tests.

  14. {url-spring-framework-javadoc}/org/springframework/test/context/TestPropertySource.html[@TestPropertySource] annotations on your tests.

  15. Devtools global settings properties in the $HOME/.config/spring-boot directory when devtools is active.

配置数据文件按以下顺序考虑:

Config data files are considered in the following order:

  1. Application properties packaged inside your jar (application.properties and YAML variants).

  2. Profile-specific application properties packaged inside your jar (application-{profile}.properties and YAML variants).

  3. Application properties outside of your packaged jar (application.properties and YAML variants).

  4. Profile-specific application properties outside of your packaged jar (application-{profile}.properties and YAML variants).

建议在整个应用程序中使用一种格式。如果您在同一位置含有 `.properties`和 YAML 格式的配置文件,则 `.properties`优先。

It is recommended to stick with one format for your entire application. If you have configuration files with both .properties and YAML format in the same location, .properties takes precedence.

如果您使用环境变量而不是系统属性,则大多数操作系统不允许使用以句点分隔的键名,不过您可以改用下划线(例如,configprop:spring.config.name[format=envvar] 而不是 configprop:spring.config.name[])。有关详细信息,请参见 Binding From Environment Variables

If you use environment variables rather than system properties, most operating systems disallow period-separated key names, but you can use underscores instead (for example, configprop:spring.config.name[format=envvar] instead of configprop:spring.config.name[]). See Binding From Environment Variables for details.

如果您的应用程序在 servlet 容器或应用程序服务器中运行,则 JNDI 属性(在 `java:comp/env`中)或 servlet 上下文初始化参数可用于代替环境变量或系统属性,或者与它们一起使用。

If your application runs in a servlet container or application server, then JNDI properties (in java:comp/env) or servlet context initialization parameters can be used instead of, or as well as, environment variables or system properties.

为了提供一个具体的示例,假设您开发一个 @Component,该 `@Component`使用一个 `name`属性,如下例所示:

To provide a concrete example, suppose you develop a @Component that uses a name property, as shown in the following example: include-code::MyBean[]

在应用程序类路径中(例如,在 jar 内部),您可以有一个 application.properties`文件,该文件为 `name`提供明智的默认属性值。在新的环境中运行时,可以在 jar 外部提供一个 `application.properties`文件,该文件覆盖 `name。对于一次性测试,您可以使用特定命令行开关启动(例如,java -jar app.jar --name="Spring")。

On your application classpath (for example, inside your jar) you can have an application.properties file that provides a sensible default property value for name. When running in a new environment, an application.properties file can be provided outside of your jar that overrides the name. For one-off testing, you can launch with a specific command line switch (for example, java -jar app.jar --name="Spring").

`env`和 `configprops`端点可用于确定属性具有特定值的原因。您可以使用这两个端点来诊断意外的属性值。有关详细信息,请参见“Production ready features”部分。

The env and configprops endpoints can be useful in determining why a property has a particular value. You can use these two endpoints to diagnose unexpected property values. See the "Production ready features" section for details.

Accessing Command Line Properties

默认情况下,SpringApplication`将任何命令行选项参数(即以 `--`开头的参数,例如 `--server.port=9000)转换为一个 property,然后将它们添加到 Spring Environment。如前所述,命令行属性始终优先于基于文件的属性源。

By default, SpringApplication converts any command line option arguments (that is, arguments starting with --, such as --server.port=9000) to a property and adds them to the Spring Environment. As mentioned previously, command line properties always take precedence over file-based property sources.

如果您不希望命令行属性添加到 Environment,则可以使用 `SpringApplication.setAddCommandLineProperties(false)`禁用它们。

If you do not want command line properties to be added to the Environment, you can disable them by using SpringApplication.setAddCommandLineProperties(false).

JSON Application Properties

环境变量和系统属性通常有受限,这意味着无法使用某些属性名称。为了解决此问题,Spring Boot 允许您将属性块编码到一个 JSON 结构中。

Environment variables and system properties often have restrictions that mean some property names cannot be used. To help with this, Spring Boot allows you to encode a block of properties into a single JSON structure.

当您的应用程序启动时,所有 spring.application.json`或 `SPRING_APPLICATION_JSON`属性都将被解析并添加到 `Environment

When your application starts, any spring.application.json or SPRING_APPLICATION_JSON properties will be parsed and added to the Environment.

例如,`SPRING_APPLICATION_JSON`属性可在 UN*X shell 中作为环境变量在命令行上提供:

For example, the SPRING_APPLICATION_JSON property can be supplied on the command line in a UN*X shell as an environment variable:

$ SPRING_APPLICATION_JSON='{"my":{"name":"test"}}' java -jar myapp.jar

在下例中,最终得到 Spring 中的 my.name=test

In the preceding example, you end up with my.name=test in the Spring Environment.

同样,JSON 也可以作为一个系统属性提供:

The same JSON can also be provided as a system property:

$ java -Dspring.application.json='{"my":{"name":"test"}}' -jar myapp.jar

或者可以使用命令行参数提供 JSON:

Or you could supply the JSON by using a command line argument:

$ java -jar myapp.jar --spring.application.json='{"my":{"name":"test"}}'

如果要部署到经典应用程序服务器,也可以使用名为 java:comp/env/spring.application.json 的 JNDI 变量。

If you are deploying to a classic Application Server, you could also use a JNDI variable named java:comp/env/spring.application.json.

尽管 JSON 中的 null 值将被添加到结果属性源中,但 PropertySourcesPropertyResolvernull 属性当作缺少值。这意味着 JSON 无法使用 null 值覆盖低阶属性源中的属性。

Although null values from the JSON will be added to the resulting property source, the PropertySourcesPropertyResolver treats null properties as missing values. This means that the JSON cannot override properties from lower order property sources with a null value.

External Application Properties

应用程序启动时,Spring Boot 将自动查找并加载以下位置中的 application.propertiesapplication.yaml 文件:

Spring Boot will automatically find and load application.properties and application.yaml files from the following locations when your application starts:

  1. From the classpath[style="loweralpha"]

    1. The classpath root

    2. The classpath /config package

  2. From the current directory[style="loweralpha"]

    1. The current directory

    2. The config/ subdirectory in the current directory

    3. Immediate child directories of the config/ subdirectory

该列表按优先级排序(较低项中的值覆盖较早项)。加载的文件中的文档以 PropertySources 形式添加到 Spring Environment 中。

The list is ordered by precedence (with values from lower items overriding earlier ones). Documents from the loaded files are added as PropertySources to the Spring Environment.

如果不希望将 application 作为配置文件的名称,可以通过指定 configprop:spring.config.name[] 环境属性切换到其他文件名。例如,要查找 myproject.propertiesmyproject.yaml 文件,可以按如下方式运行应用程序:

If you do not like application as the configuration file name, you can switch to another file name by specifying a configprop:spring.config.name[] environment property. For example, to look for myproject.properties and myproject.yaml files you can run your application as follows:

$ java -jar myproject.jar --spring.config.name=myproject

还可以通过使用 configprop:spring.config.location[] 环境属性引用显式位置。该属性接受一个或多个要检查位置的逗号分隔列表。

You can also refer to an explicit location by using the configprop:spring.config.location[] environment property. This property accepts a comma-separated list of one or more locations to check.

以下示例显示如何指定两份不同的文件:

The following example shows how to specify two distinct files:

$ java -jar myproject.jar --spring.config.location=\
	optional:classpath:/default.properties,\
	optional:classpath:/override.properties

如果存在 locations are optional ,可以使用前缀 optional: ,而不在意是否存在。

Use the prefix optional: if the locations are optional and you do not mind if they do not exist.

非常早地使用 spring.config.namespring.config.locationspring.config.additional-location 来确定要加载哪些文件。必须将它们定义为环境属性(通常是操作系统环境变量、系统属性或命令行参数)。

spring.config.name, spring.config.location, and spring.config.additional-location are used very early to determine which files have to be loaded. They must be defined as an environment property (typically an OS environment variable, a system property, or a command-line argument).

如果 spring.config.location 包含目录(而不是文件),它们应以 / 结尾。在加载之前,将在运行时将它们追加到从 spring.config.name 生成的名称。spring.config.location 中指定的文件会被直接导入。

If spring.config.location contains directories (as opposed to files), they should end in /. At runtime they will be appended with the names generated from spring.config.name before being loaded. Files specified in spring.config.location are imported directly.

目录和文件位置值都会被展开以检查 profile-specific files 。例如,如果 spring.config.location 的值为 classpath:myconfig.properties,那么还会发现适当的 classpath:myconfig-<profile>.properties 文件已加载。

Both directory and file location values are also expanded to check for profile-specific files. For example, if you have a spring.config.location of classpath:myconfig.properties, you will also find appropriate classpath:myconfig-<profile>.properties files are loaded.

在大多数情况下,添加的每个 configprop:spring.config.location[] 项都会引用单个文件或目录。位置按指定的顺序进行处理,后面的位置可以覆盖前面的位置。

In most situations, each configprop:spring.config.location[] item you add will reference a single file or directory. Locations are processed in the order that they are defined and later ones can override the values of earlier ones.

如果有复杂的位置设置,并且使用特定于配置文件,则可能需要提供更多提示,以便 Spring Boot 知道应该如何将它们分组。位置组是同一级别所有位置的集合。例如,可能希望对所有类路径位置进行分组,然后对所有外部位置进行分组。位置组中的项应以 ; 分隔。有关更多详细信息,请参阅 “Profile Specific Files” 部分中的示例。

If you have a complex location setup, and you use profile-specific configuration files, you may need to provide further hints so that Spring Boot knows how they should be grouped. A location group is a collection of locations that are all considered at the same level. For example, you might want to group all classpath locations, then all external locations. Items within a location group should be separated with ;. See the example in the “Profile Specific Files” section for more details.

使用 spring.config.location 配置的位置会替换默认位置。例如,如果将 spring.config.location 配置为值 optional:classpath:/custom-config/,optional:file:./custom-config/,那么考虑的位置的完整集合是:

Locations configured by using spring.config.location replace the default locations. For example, if spring.config.location is configured with the value optional:classpath:/custom-config/,optional:file:./custom-config/, the complete set of locations considered is:

  1. optional:classpath:custom-config/

  2. optional:file:./custom-config/

如果你希望添加其他位置,而不是替换它们,则可以使用 spring.config.additional-location。从其他位置加载的属性可以覆盖默认位置中的属性。例如,如果配置的 spring.config.additional-location 值为 optional:classpath:/custom-config/,optional:file:./custom-config/,考虑的位置的完整集合为:

If you prefer to add additional locations, rather than replacing them, you can use spring.config.additional-location. Properties loaded from additional locations can override those in the default locations. For example, if spring.config.additional-location is configured with the value optional:classpath:/custom-config/,optional:file:./custom-config/, the complete set of locations considered is:

  1. optional:classpath:/;optional:classpath:/config/

  2. optional:file:./;optional:file:./config/;optional:file:./config/*/

  3. optional:classpath:custom-config/

  4. optional:file:./custom-config/

此搜索顺序允许你在一个配置文件中指定默认值,然后在另一个配置文件中选择性重写这些值。你可以在默认位置之一中(或使用 spring.config.name 选择的任何其他基本名称)的 application.properties(或使用 spring.config.name 选择的任何其他基本名称)中为你的应用程序提供默认值。然后可以使用位于自定义位置之一中的不同文件在运行时覆盖这些默认值。

This search ordering lets you specify default values in one configuration file and then selectively override those values in another. You can provide default values for your application in application.properties (or whatever other basename you choose with spring.config.name) in one of the default locations. These default values can then be overridden at runtime with a different file located in one of the custom locations.

Optional Locations

默认情况下,当指定的配置数据位置不存在时,Spring Boot 将抛出一个 ConfigDataLocationNotFoundException,并且你的应用程序将不会启动。

By default, when a specified config data location does not exist, Spring Boot will throw a ConfigDataLocationNotFoundException and your application will not start.

如果你想指定一个位置,但你不介意它是否一直存在,则可以使用 optional: 前缀。你可以在 spring.config.locationspring.config.additional-location 属性以及 spring.config.import 声明中使用此前缀。

If you want to specify a location, but you do not mind if it does not always exist, you can use the optional: prefix. You can use this prefix with the spring.config.location and spring.config.additional-location properties, as well as with spring.config.import declarations.

例如,即使不存在 myconfig.properties 文件,spring.config.import 值为 optional:file:./myconfig.properties 也可以允许你的应用程序启动。

For example, a spring.config.import value of optional:file:./myconfig.properties allows your application to start, even if the myconfig.properties file is missing.

如果你想要忽略所有 ConfigDataLocationNotFoundExceptions 并始终继续启动你的应用程序,你可以使用 spring.config.on-not-found 属性。使用 SpringApplication.setDefaultProperties(…​) 或通过系统/环境变量将值设置为 ignore

If you want to ignore all ConfigDataLocationNotFoundExceptions and always continue to start your application, you can use the spring.config.on-not-found property. Set the value to ignore using SpringApplication.setDefaultProperties(…​) or with a system/environment variable.

Wildcard Locations

如果配置文件位置包含最后一个路径段的 * 字符,它会被视为通配符位置。通配符会在加载配置时展开,以便也检查立即子目录。当存在多种配置属性源时,诸如 Kubernetes 之类的环境中会特别有用通配符位置。

If a config file location includes the * character for the last path segment, it is considered a wildcard location. Wildcards are expanded when the config is loaded so that immediate subdirectories are also checked. Wildcard locations are particularly useful in an environment such as Kubernetes when there are multiple sources of config properties.

例如,如果你有一些 Redis 配置和一些 MySQL 配置,你可能想要将这两部分配置分开,同时要求两者都存在于 application.properties 文件中。这可能会导致两个单独的 application.properties 文件挂载在不同的位置,例如 /config/redis/application.properties/config/mysql/application.properties。在这种情况下,拥有 config/*/ 的通配符位置将导致处理这两个文件。

For example, if you have some Redis configuration and some MySQL configuration, you might want to keep those two pieces of configuration separate, while requiring that both those are present in an application.properties file. This might result in two separate application.properties files mounted at different locations such as /config/redis/application.properties and /config/mysql/application.properties. In such a case, having a wildcard location of config/*/, will result in both files being processed.

默认情况下,Spring Boot 在默认搜索位置中包括 config/*/。这意味着将搜索 jar 外部 /config 目录的所有子目录。

By default, Spring Boot includes config/*/ in the default search locations. It means that all subdirectories of the /config directory outside of your jar will be searched.

你可以自己使用 spring.config.locationspring.config.additional-location 属性使用通配符位置。

You can use wildcard locations yourself with the spring.config.location and spring.config.additional-location properties.

通配符位置对于作为目录的搜索位置只包含一个 and end with /,或者对于作为文件的搜索位置只包含一个 */<filename> 是必需的。具有通配符的位置根据文件名的绝对路径按字母顺序排序。

A wildcard location must contain only one and end with / for search locations that are directories or */<filename> for search locations that are files. Locations with wildcards are sorted alphabetically based on the absolute path of the file names.

通配符位置仅适用于外部目录。你不能在 classpath: 位置中使用通配符。

Wildcard locations only work with external directories. You cannot use a wildcard in a classpath: location.

Profile Specific Files

除了 application 属性文件之外,Spring Boot 还会尝试使用命名约定 application-{profile} 加载特定于概要的文件。例如,如果你的应用程序激活了名为 prod 的概要并使用了 YAML 文件,那么 application.yamlapplication-prod.yaml 都将被考虑。

As well as application property files, Spring Boot will also attempt to load profile-specific files using the naming convention application-{profile}. For example, if your application activates a profile named prod and uses YAML files, then both application.yaml and application-prod.yaml will be considered.

特定于概要的属性从与标准 application.properties 相同的位置加载,其中特定于概要的文件始终覆盖非特定于概要的文件。如果指定了多个概要,则应用“最近者优先”策略。例如,如果通过 configprop:spring.profiles.active[] 属性指定了概要 prod,live,则 application-prod.properties 中的值可以被 application-live.properties 中的值覆盖。

Profile-specific properties are loaded from the same locations as standard application.properties, with profile-specific files always overriding the non-specific ones. If several profiles are specified, a last-wins strategy applies. For example, if profiles prod,live are specified by the configprop:spring.profiles.active[] property, values in application-prod.properties can be overridden by those in application-live.properties.

“最近者优先”策略在 location group 级别应用。classpath:/cfg/,classpath:/ext/ 的 configprop:spring.config.location[] 将不会具有与 classpath:/cfg/;classpath:/ext/ 相同的替代规则。

The last-wins strategy applies at the location group level. A configprop:spring.config.location[] of classpath:/cfg/,classpath:/ext/ will not have the same override rules as classpath:/cfg/;classpath:/ext/.

例如,在继续上述我们的 prod,live 示例时,我们可能拥有以下文件:

For example, continuing our prod,live example above, we might have the following files:

/cfg
  application-live.properties
/ext
  application-live.properties
  application-prod.properties

当我们有 configprop:spring.config.location[] 时,在所有 /ext 文件之前处理所有 /cfg 文件:

When we have a configprop:spring.config.location[] of classpath:/cfg/,classpath:/ext/ we process all /cfg files before all /ext files:

  1. /cfg/application-live.properties

  2. /ext/application-prod.properties

  3. /ext/application-live.properties

当我们反而有 classpath:/cfg/;classpath:/ext/(带有 ; 分隔符)时,在同一级别处理 /cfg/ext

When we have classpath:/cfg/;classpath:/ext/ instead (with a ; delimiter) we process /cfg and /ext at the same level:

  1. /ext/application-prod.properties

  2. /cfg/application-live.properties

  3. /ext/application-live.properties

如果未设置任何活动概要,Environment 有一组默认概要(默认情况下为 [default])。换言之,如果没有明确激活任何概要,则会考虑 application-default 中的属性。

The Environment has a set of default profiles (by default, [default]) that are used if no active profiles are set. In other words, if no profiles are explicitly activated, then properties from application-default are considered.

属性文件只会加载一次。如果你已经直接 imported 了特定于概要的属性文件,则不会再次导入它。

Properties files are only ever loaded once. If you have already directly imported a profile specific property files then it will not be imported a second time.

Importing Additional Data

应用程序属性可以使用 spring.config.import 属性从其他位置导入更多配置数据。导入在被发现时处理,并被视为立即在声明导入的位置下方插入的附加文档。

Application properties may import further config data from other locations using the spring.config.import property. Imports are processed as they are discovered, and are treated as additional documents inserted immediately below the one that declares the import.

例如,你可能在 classpath application.properties 文件中拥有以下内容:

For example, you might have the following in your classpath application.properties file:

spring:
  application:
    name: "myapp"
  config:
    import: "optional:file:./dev.properties"

这将触发从当前目录中导入一个 dev.properties 文件(如果存在此文件)。导入的 dev.properties 的值将优先于触发导入的文件。在上面的示例中,dev.properties 可以将 spring.application.name 重新定义为一个不同的值。

This will trigger the import of a dev.properties file in current directory (if such a file exists). Values from the imported dev.properties will take precedence over the file that triggered the import. In the above example, the dev.properties could redefine spring.application.name to a different value.

无论声明次数如何,导入只导入一次。导入在一个文档内部的 properties/yaml 文件中的定义顺序无关紧要。例如,下面的两个示例生成相同的结果:

An import will only be imported once no matter how many times it is declared. The order an import is defined inside a single document within the properties/yaml file does not matter. For instance, the two examples below produce the same result:

spring:
  config:
    import: "my.properties"
my:
  property: "value"
my:
  property: "value"
spring:
  config:
    import: "my.properties"

在上面的两个示例中,my.properties 文件中的值将优先于触发其导入的文件。

In both of the above examples, the values from the my.properties file will take precedence over the file that triggered its import.

多个位置可以指定在一个 spring.config.import 键下。位置将按照它们定义的顺序处理,其中后面的导入优先。

Several locations can be specified under a single spring.config.import key. Locations will be processed in the order that they are defined, with later imports taking precedence.

在适当的时候,Profile-specific variants 也考虑进行导入。上面的示例将导入 my.properties,以及任何 my-<profile>.properties 的变体。

When appropriate, Profile-specific variants are also considered for import. The example above would import both my.properties as well as any my-<profile>.properties variants.

Spring Boot 包括可插入 API,该 API 支持各种不同的位置地址。默认情况下,您可以导入 Java 属性、YAML 和 “configuration trees”。

Spring Boot includes pluggable API that allows various different location addresses to be supported. By default you can import Java Properties, YAML and “configuration trees”.

第三方 jar 可以为额外的技术提供支持(文件不必是本地的,没有此项要求)。例如,您可以想象外部存储(例如 Consul、Apache ZooKeeper 或 Netflix Archaius)中的配置数据。

Third-party jars can offer support for additional technologies (there is no requirement for files to be local). For example, you can imagine config data being from external stores such as Consul, Apache ZooKeeper or Netflix Archaius.

如果您想支持您自己的位置,请查看 org.springframework.boot.context.config 包中的 ConfigDataLocationResolverConfigDataLoader 类。

If you want to support your own locations, see the ConfigDataLocationResolver and ConfigDataLoader classes in the org.springframework.boot.context.config package.

Importing Extensionless Files

一些云平台无法为已装载的文件添加文件扩展名。要导入这些没有扩展名的文件,你需要向 Spring Boot 提供一个提示,以便它知道如何加载它们。你可以通过在方括号中放置扩展名提示来执行此操作。

Some cloud platforms cannot add a file extension to volume mounted files. To import these extensionless files, you need to give Spring Boot a hint so that it knows how to load them. You can do this by putting an extension hint in square brackets.

例如,假设你有希望导入为 yaml 的 s0 文件。你可以使用以下命令从 s1 导入它:

For example, suppose you have a /etc/config/myconfig file that you wish to import as yaml. You can import it from your application.properties using the following:

spring:
  config:
    import: "file:/etc/config/myconfig[.yaml]"

Using Configuration Trees

在云平台(例如 Kubernetes)上运行应用程序时,你通常需要读取平台提供的配置值。为此目的使用环境变量很常见,但这可能存在缺陷,尤其是在该值应保密时。

When running applications on a cloud platform (such as Kubernetes) you often need to read config values that the platform supplies. It is not uncommon to use environment variables for such purposes, but this can have drawbacks, especially if the value is supposed to be kept secret.

作为环境变量的替代方案,许多云平台现在允许你将配置映射到已装载的数据卷。例如,Kubernetes 可以卷装载 s4 和 s5。

As an alternative to environment variables, many cloud platforms now allow you to map configuration into mounted data volumes. For example, Kubernetes can volume mount both ConfigMaps and Secrets.

可以使用两种常见的卷装载模式:

There are two common volume mount patterns that can be used:

  1. A single file contains a complete set of properties (usually written as YAML).

  2. Multiple files are written to a directory tree, with the filename becoming the '`key’ and the contents becoming the '`value’.

对于第一个案例,您可以直接使用 `spring.config.import`导入 YAML 或 Properties 文件,如 above中所述。对于第二个案例,您需要使用 `configtree:`前缀,以便 Spring Boot 知道它需要公开所有文件作为属性。

For the first case, you can import the YAML or Properties file directly using spring.config.import as described above. For the second case, you need to use the configtree: prefix so that Spring Boot knows it needs to expose all the files as properties.

例如,让我们想象一下 Kubernetes 挂载了以下卷:

As an example, let’s imagine that Kubernetes has mounted the following volume:

etc/
  config/
    myapp/
      username
      password

`username`文件的内容将是 config 值,而 `password`的内容将是机密。

The contents of the username file would be a config value, and the contents of password would be a secret.

要导入这些属性,您可以将以下内容添加到您的 `application.properties`或 `application.yaml`文件中:

To import these properties, you can add the following to your application.properties or application.yaml file:

spring:
  config:
    import: "optional:configtree:/etc/config/"

然后,您可以通过 `Environment`以通常的方式访问或注入 `myapp.username`和 `myapp.password`属性。

You can then access or inject myapp.username and myapp.password properties from the Environment in the usual way.

config 树下的文件夹和文件名称构成了属性名称。在上面的示例中,要以 username`和 `password`作为属性来访问这些属性,您可以将 `spring.config.import`设置为 `optional:configtree:/etc/config/myapp

The names of the folders and files under the config tree form the property name. In the above example, to access the properties as username and password, you can set spring.config.import to optional:configtree:/etc/config/myapp.

带点表示法的文件名也正确地映射了。例如,在上面的示例中,`/etc/config`中的名为 `myapp.username`的文件将在 `Environment`中产生一个 `myapp.username`属性。

Filenames with dot notation are also correctly mapped. For example, in the above example, a file named myapp.username in /etc/config would result in a myapp.username property in the Environment.

根据预期的内容,Configuration 树值可以绑定到字符串 `String`和 `byte[]`类型。

Configuration tree values can be bound to both string String and byte[] types depending on the contents expected.

如果您有多个 config 树要从同一个父文件夹导入,可以使用通配符快捷方式。任何以 `/*/`结尾的 `configtree:`位置都将导入所有直接子级作为 config 树。与非通配符导入一样,每个 config 树下的文件夹和文件名称构成了属性名称。

If you have multiple config trees to import from the same parent folder you can use a wildcard shortcut. Any configtree: location that ends with /*/ will import all immediate children as config trees. As with a non-wildcard import, the names of the folders and files under each config tree form the property name.

例如,给定以下卷:

For example, given the following volume:

etc/
  config/
    dbconfig/
      db/
        username
        password
    mqconfig/
      mq/
        username
        password

您可以使用 `configtree:/etc/config/*/`作为导入位置:

You can use configtree:/etc/config/*/ as the import location:

spring:
  config:
    import: "optional:configtree:/etc/config/*/"

这将添加 db.usernamedb.password、`mq.username`和 `mq.password`属性。

This will add db.username, db.password, mq.username and mq.password properties.

使用通配符加载的目录按字母顺序排序。如果您需要不同的顺序,则应将每个位置列为单独的导入

Directories loaded using a wildcard are sorted alphabetically. If you need a different order, then you should list each location as a separate import

Configuration 树也可以用于 Docker 机密。当 Docker 群集服务被授予访问机密的权限时,机密会被装载到容器中。例如,如果在位置 `/run/secrets/`上装载了一个名为 `db.password`的机密,则可以使用以下内容使 `db.password`可用于 Spring 环境:

Configuration trees can also be used for Docker secrets. When a Docker swarm service is granted access to a secret, the secret gets mounted into the container. For example, if a secret named db.password is mounted at location /run/secrets/, you can make db.password available to the Spring environment using the following:

spring:
  config:
    import: "optional:configtree:/run/secrets/"

Property Placeholders

application.properties`和 `application.yaml`中的值在使用时将通过现有的 `Environment`进行过滤,因此您可以返回到先前定义的值(例如,来自系统属性或环境变量)。标准 `${name}`属性占位符语法可以在值中的任何位置使用。属性占位符还可以使用 `:`指定默认值,以将默认值与属性名称分开,例如 `${name:default}

The values in application.properties and application.yaml are filtered through the existing Environment when they are used, so you can refer back to previously defined values (for example, from System properties or environment variables). The standard ${name} property-placeholder syntax can be used anywhere within a value. Property placeholders can also specify a default value using a : to separate the default value from the property name, for example ${name:default}.

以下示例显示了带或不带默认值使用占位符的情况:

The use of placeholders with and without defaults is shown in the following example:

app:
  name: "MyApp"
  description: "${app.name} is a Spring Boot application written by ${username:Unknown}"

假设 username`属性尚未在其他地方设置,则 `app.description`将具有值 `MyApp is a Spring Boot application written by Unknown

Assuming that the username property has not been set elsewhere, app.description will have the value MyApp is a Spring Boot application written by Unknown.

您应该始终使用规范形式(仅使用小写字母的 kebab-case)在占位符中引用属性名称。这将允许 Spring Boot 使用与处理 relaxed binding`@ConfigurationProperties`时相同的逻辑。

You should always refer to property names in the placeholder using their canonical form (kebab-case using only lowercase letters). This will allow Spring Boot to use the same logic as it does when relaxed binding @ConfigurationProperties.

例如,${demo.item-price} 将从 application.properties 文件中选取 demo.item-pricedemo.itemPrice 表单,以及从系统环境中选取 DEMO_ITEMPRICE。如果使用 ${demo.itemPrice},将不会考虑 demo.item-priceDEMO_ITEMPRICE

For example, ${demo.item-price} will pick up demo.item-price and demo.itemPrice forms from the application.properties file, as well as DEMO_ITEMPRICE from the system environment. If you used ${demo.itemPrice} instead, demo.item-price and DEMO_ITEMPRICE would not be considered.

还可以使用这种技术创建现有 Spring Boot 属性的 “short” 变体。请参阅 Use '`Short’ Command Line Arguments 了解详情。

You can also use this technique to create “short” variants of existing Spring Boot properties. See the Use '`Short’ Command Line Arguments how-to for details.

Working With Multi-Document Files

Spring Boot 允许将一个物理文件拆分为多个独立添加的逻辑文档。按从上到下的顺序处理文档。后面的文档可以覆盖早期文档中定义的属性。

Spring Boot allows you to split a single physical file into multiple logical documents which are each added independently. Documents are processed in order, from top to bottom. Later documents can override the properties defined in earlier ones.

对于 application.yaml 文件,使用标准 YAML 多文档语法。三个连续连字符表示一个文档的结尾和下一个文档的开头。

For application.yaml files, the standard YAML multi-document syntax is used. Three consecutive hyphens represent the end of one document, and the start of the next.

例如,以下文件有两个逻辑文档:

For example, the following file has two logical documents:

spring:
  application:
    name: "MyApp"
---
spring:
  application:
    name: "MyCloudApp"
  config:
    activate:
      on-cloud-platform: "kubernetes"

对于 application.properties 文件,使用特殊的 #---!--- 注释来标记文档拆分:

For application.properties files a special #--- or !--- comment is used to mark the document splits:

spring.application.name=MyApp
#---
spring.application.name=MyCloudApp
spring.config.activate.on-cloud-platform=kubernetes

属性文件分隔符前面不能有任何空格,并且必须有恰好三个连字符。分隔符之前和之后的行不能相同注释前缀。

Property file separators must not have any leading whitespace and must have exactly three hyphen characters. The lines immediately before and after the separator must not be same comment prefix.

多文档属性文件通常与激活属性(如 spring.config.activate.on-profile)一起使用。请参阅 next section 了解详情。

Multi-document property files are often used in conjunction with activation properties such as spring.config.activate.on-profile. See the next section for details.

无法使用 @PropertySource@TestPropertySource 注释加载多文档属性文件。

Multi-document property files cannot be loaded by using the @PropertySource or @TestPropertySource annotations.

Activation Properties

有时仅在满足特定条件时激活给定的属性集是很有用的。例如,可以具备仅在特定配置文件处于活动状态时才相关的属性。

It is sometimes useful to only activate a given set of properties when certain conditions are met. For example, you might have properties that are only relevant when a specific profile is active.

可以使用 spring.config.activate.* 根据条件激活属性文档。

You can conditionally activate a properties document using spring.config.activate.*.

以下激活属性可用:

The following activation properties are available:

Table 1. activation properties
Property Note

on-profile

A profile expression that must match for the document to be active.

on-cloud-platform

The CloudPlatform that must be detected for the document to be active.

例如,以下指定第二个文档仅在 Kubernetes 上运行时处于活动状态,并且仅当 “prod” 或 “staging” 配置文件处于活动状态时:

For example, the following specifies that the second document is only active when running on Kubernetes, and only when either the “prod” or “staging” profiles are active:

myprop:
  "always-set"
---
spring:
  config:
    activate:
      on-cloud-platform: "kubernetes"
      on-profile: "prod | staging"
myotherprop: "sometimes-set"

Encrypting Properties

Spring Boot 不提供任何内置支持来加密属性值,但是,它确实提供了必要的挂钩点来修改包含在 Spring Environment 中的值。在应用程序启动之前,EnvironmentPostProcessor 接口允许操作 Environment。有关详细信息,请参阅 Customize the Environment or ApplicationContext Before It Starts

Spring Boot does not provide any built-in support for encrypting property values, however, it does provide the hook points necessary to modify values contained in the Spring Environment. The EnvironmentPostProcessor interface allows you to manipulate the Environment before the application starts. See Customize the Environment or ApplicationContext Before It Starts for details.

如果需要安全的方式来存储凭证和密码, Spring Cloud Vault 项目将提供将外部配置存储在 HashiCorp Vault 中的支持。

If you need a secure way to store credentials and passwords, the Spring Cloud Vault project provides support for storing externalized configuration in HashiCorp Vault.

Working With YAML

YAML 是 JSON 的超集,因此是用于指定层次配置数据的便捷格式。只要在类路径上拥有 SnakeYAML 库,SpringApplication 类便自动支持 YAML 作为属性的替代方案。

YAML is a superset of JSON and, as such, is a convenient format for specifying hierarchical configuration data. The SpringApplication class automatically supports YAML as an alternative to properties whenever you have the SnakeYAML library on your classpath.

如果您使用 “Starters”, spring-boot-starter 将自动提供 SnakeYAML。

If you use “Starters”, SnakeYAML is automatically provided by spring-boot-starter.

Mapping YAML to Properties

YAML 文档需要从其分层格式转换为可以用 Spring Environment 使用的平面结构。例如,考虑以下 YAML 文档:

YAML documents need to be converted from their hierarchical format to a flat structure that can be used with the Spring Environment. For example, consider the following YAML document:

environments:
  dev:
    url: "https://dev.example.com"
    name: "Developer Setup"
  prod:
    url: "https://another.example.com"
    name: "My Cool App"

为了从 Environment 访问这些属性,它们会被展平如下:

In order to access these properties from the Environment, they would be flattened as follows:

environments.dev.url=https://dev.example.com
environments.dev.name=Developer Setup
environments.prod.url=https://another.example.com
environments.prod.name=My Cool App

同样,YAML 列表也需要展平。它们表示为带有 [index] 解引用器的属性键。例如,考虑以下 YAML:

Likewise, YAML lists also need to be flattened. They are represented as property keys with [index] dereferencers. For example, consider the following YAML:

 my:
  servers:
  - "dev.example.com"
  - "another.example.com"

前面对例将被转换为以下属性:

The preceding example would be transformed into these properties:

my.servers[0]=dev.example.com
my.servers[1]=another.example.com

使用 [index] 表示法的属性可以使用 Spring Boot 的 Binder 类绑定到 Java ListSet 对象。有关更多详细信息,请参阅下面的 “Type-safe Configuration Properties” 部分。

Properties that use the [index] notation can be bound to Java List or Set objects using Spring Boot’s Binder class. For more details see the “Type-safe Configuration Properties” section below.

YAML 文件不能使用 @PropertySource@TestPropertySource 注释加载。因此,如果您需要以这种方式加载值,则需要使用属性文件。

YAML files cannot be loaded by using the @PropertySource or @TestPropertySource annotations. So, in the case that you need to load values that way, you need to use a properties file.

Directly Loading YAML

Spring Framework 提供了两个方便的类,可以用来加载 YAML 文档。YamlPropertiesFactoryBean 将 YAML 作为 Properties 加载,而 YamlMapFactoryBean 将 YAML 作为 Map 加载。

Spring Framework provides two convenient classes that can be used to load YAML documents. The YamlPropertiesFactoryBean loads YAML as Properties and the YamlMapFactoryBean loads YAML as a Map.

如果您想将 YAML 作为 Spring PropertySource 加载,您也可以使用 YamlPropertySourceLoader 类。

You can also use the YamlPropertySourceLoader class if you want to load YAML as a Spring PropertySource.

Configuring Random Values

RandomValuePropertySource 对于注入随机值(例如注入到机密或测试案例中)很有用。它可以生成整数、长整数、UUID 或字符串,如下例所示:

The RandomValuePropertySource is useful for injecting random values (for example, into secrets or test cases). It can produce integers, longs, uuids, or strings, as shown in the following example:

my:
  secret: "${random.value}"
  number: "${random.int}"
  bignumber: "${random.long}"
  uuid: "${random.uuid}"
  number-less-than-ten: "${random.int(10)}"
  number-in-range: "${random.int[1024,65536]}"

random.int* 语法是 OPEN value (,max) CLOSE,其中 OPEN,CLOSE 是任意字符, value,max 是整数。如果提供了 max,则 value 是最小值, max 是最大值(不包括)。

The random.int* syntax is OPEN value (,max) CLOSE where the OPEN,CLOSE are any character and value,max are integers. If max is provided, then value is the minimum value and max is the maximum value (exclusive).

Configuring System Environment Properties

Spring Boot 支持为环境属性设置前缀。如果系统环境由多个 Spring Boot 应用程序共享,并且这些应用程序具有不同的配置要求,此功能非常有用。系统环境属性的前缀可以在 SpringApplication 上直接设置。

Spring Boot supports setting a prefix for environment properties. This is useful if the system environment is shared by multiple Spring Boot applications with different configuration requirements. The prefix for system environment properties can be set directly on SpringApplication.

例如,如果您将前缀设置为 input,则诸如 remote.timeout 的属性也会在系统环境中解析为 input.remote.timeout

For example, if you set the prefix to input, a property such as remote.timeout will also be resolved as input.remote.timeout in the system environment.

Type-safe Configuration Properties

使用 @Value("${property}") 注释注入配置属性有时会很麻烦,尤其是在处理多属性或数据本质上是分层的情况下。Spring Boot 提供了一种处理属性的替代方法,该方法允许经过强类型处理的 Bean 管理和验证应用程序的配置。

Using the @Value("${property}") annotation to inject configuration properties can sometimes be cumbersome, especially if you are working with multiple properties or your data is hierarchical in nature. Spring Boot provides an alternative method of working with properties that lets strongly typed beans govern and validate the configuration of your application.

JavaBean Properties Binding

可以绑定一个声明标准 JavaBean 属性的 Bean,如下例所示:

It is possible to bind a bean declaring standard JavaBean properties as shown in the following example:

前述 POJO 定义了以下属性:

The preceding POJO defines the following properties:

  • my.service.enabled, with a value of false by default.

  • my.service.remote-address, with a type that can be coerced from String.

  • my.service.security.username, with a nested "security" object whose name is determined by the name of the property. In particular, the type is not used at all there and could have been SecurityProperties.

  • my.service.security.password.

  • my.service.security.roles, with a collection of String that defaults to USER.

映射到 Spring Boot 中可用的 s11 类的属性(通过属性文件、YAML 文件、环境变量和其他机制进行配置)是公开 API,但该类的访问器(getter/setter)本身不用于直接使用。

The properties that map to @ConfigurationProperties classes available in Spring Boot, which are configured through properties files, YAML files, environment variables, and other mechanisms, are public API but the accessors (getters/setters) of the class itself are not meant to be used directly.

这种安排依赖于默认的空构造函数,而 getter 和 setter 通常是强制性的,因为绑定是通过标准 Java Beans 属性描述符进行的,就像在 Spring MVC 中一样。在以下情况下可以省略 setter:

Such arrangement relies on a default empty constructor and getters and setters are usually mandatory, since binding is through standard Java Beans property descriptors, just like in Spring MVC. A setter may be omitted in the following cases:

  • Maps, as long as they are initialized, need a getter but not necessarily a setter, since they can be mutated by the binder.

  • Collections and arrays can be accessed either through an index (typically with YAML) or by using a single comma-separated value (properties). In the latter case, a setter is mandatory. We recommend to always add a setter for such types. If you initialize a collection, make sure it is not immutable (as in the preceding example).

  • If nested POJO properties are initialized (like the Security field in the preceding example), a setter is not required. If you want the binder to create the instance on the fly by using its default constructor, you need a setter.

有些人使用 Project Lombok 自动添加获取器和设置器。请确保 Lombok 不针对此类类型生成任何特定构造函数,因为容器会自动使用它实例化对象。

Some people use Project Lombok to add getters and setters automatically. Make sure that Lombok does not generate any particular constructor for such a type, as it is used automatically by the container to instantiate the object.

最后,只考虑标准 Java Bean 属性,并且不支持静态属性上的绑定。

Finally, only standard Java Bean properties are considered and binding on static properties is not supported.

Constructor Binding

前一节中的示例可以用不可变的方式改写,如下例所示:

The example in the previous section can be rewritten in an immutable fashion as shown in the following example:

在此设置中,存在一个单参数化构造函数暗示应使用构造函数绑定。这意味着绑定器将找到具有您希望绑定的参数的构造函数。如果您的类具有多个构造函数,则 @ConstructorBinding 注解可用于指定应针对构造函数绑定使用哪个构造函数。要选择不为具有单个参数化构造函数的类进行构造函数绑定,必须使用 @Autowired 注解构造函数。构造函数绑定可用于记录。除非记录有多个构造函数,否则无需使用 @ConstructorBinding

In this setup, the presence of a single parameterized constructor implies that constructor binding should be used. This means that the binder will find a constructor with the parameters that you wish to have bound. If your class has multiple constructors, the @ConstructorBinding annotation can be used to specify which constructor to use for constructor binding. To opt out of constructor binding for a class with a single parameterized constructor, the constructor must be annotated with @Autowired. Constructor binding can be used with records. Unless your record has multiple constructors, there is no need to use @ConstructorBinding.

构造函数绑定类的嵌套成员(如上述示例中的 Security)也将通过其构造函数进行绑定。

Nested members of a constructor bound class (such as Security in the example above) will also be bound through their constructor.

可以使用 @DefaultValue 在构造函数参数和记录组件上指定默认值。转换服务将应用于强制转换批注的 String 值为缺少属性的目标类型。

Default values can be specified using @DefaultValue on constructor parameters and record components. The conversion service will be applied to coerce the annotation’s String value to the target type of a missing property.

参考前一个示例,如果没有任何属性绑定到 Security,则 MyProperties 实例将包含 securitynull 值。为了使其包含一个非空 Security 实例,即使没有任何属性绑定到它(当使用 Kotlin 时,这要求 Securityusernamepassword 参数被声明为可为空的,因为它们没有默认值),请使用 @DefaultValue 空注解:

Referring to the previous example, if no properties are bound to Security, the MyProperties instance will contain a null value for security. To make it contain a non-null instance of Security even when no properties are bound to it (when using Kotlin, this will require the username and password parameters of Security to be declared as nullable as they do not have default values), use an empty @DefaultValue annotation:

要使用构造函数绑定,必须使用 @EnableConfigurationProperties 或配置属性扫描启用该类。您无法将构造函数绑定与由常规 Spring 机制创建的 bean 一起使用(例如 @Component bean、使用 @Bean 方法创建的 bean 或使用 @Import 加载的 bean)

To use constructor binding the class must be enabled using @EnableConfigurationProperties or configuration property scanning. You cannot use constructor binding with beans that are created by the regular Spring mechanisms (for example @Component beans, beans created by using @Bean methods or beans loaded by using @Import)

要在本机映像中使用构造函数绑定,必须使用 -parameters 编译该类。如果您使用 Spring Boot 的 Gradle 插件或使用 Maven 和 spring-boot-starter-parent,这将自动发生。

To use constructor binding in a native image the class must be compiled with -parameters. This will happen automatically if you use Spring Boot’s Gradle plugin or if you use Maven and spring-boot-starter-parent.

不建议将 java.util.Optional@ConfigurationProperties 一起使用,因为它主要是用作返回类型。因此,它不适合于配置属性注入。为了与其他类型的属性保持一致,如果您确实声明了 Optional 属性并且它没有值,则 null 而不是 Optional 将被绑定。

The use of java.util.Optional with @ConfigurationProperties is not recommended as it is primarily intended for use as a return type. As such, it is not well-suited to configuration property injection. For consistency with properties of other types, if you do declare an Optional property and it has no value, null rather than an empty Optional will be bound.

Enabling @ConfigurationProperties-annotated Types

Spring Boot 提供基础设施,用于绑定“@1”类型并将其注册为 bean。您可以逐个类启用配置属性,或启用与组件扫描工作方式类似的配置属性扫描。

Spring Boot provides infrastructure to bind @ConfigurationProperties types and register them as beans. You can either enable configuration properties on a class-by-class basis or enable configuration property scanning that works in a similar manner to component scanning.

有时,使用“@2”进行注释的类可能不适合扫描,例如,如果您正在开发自己的自动配置,或您希望有条件地启用它们。在这些情况下,请使用“@3”注释指定要使用该类型的列表。这可以在任何“@4”类上完成,如下例所示:

Sometimes, classes annotated with @ConfigurationProperties might not be suitable for scanning, for example, if you’re developing your own auto-configuration or you want to enable them conditionally. In these cases, specify the list of types to process using the @EnableConfigurationProperties annotation. This can be done on any @Configuration class, as shown in the following example:

要使用配置属性扫描,请向您的应用程序添加“@5”注释。通常,它被添加到使用“@6”进行注释的主应用程序类,但它可以被添加到任何“@7”类。默认情况下,将从声明注释的类的包中进行扫描。如果您希望定义要扫描的特定包,可以按照如下示例进行操作:

To use configuration property scanning, add the @ConfigurationPropertiesScan annotation to your application. Typically, it is added to the main application class that is annotated with @SpringBootApplication but it can be added to any @Configuration class. By default, scanning will occur from the package of the class that declares the annotation. If you want to define specific packages to scan, you can do so as shown in the following example:

当“@8”bean 使用配置属性扫描或通过“@9”注册时,bean 具有常规名称:“@10”,其中“@11”是在“@12”注释中指定的环境密钥前缀,“@13”是 bean 的完全限定名称。如果注释未提供任何前缀,则只使用 bean 的完全限定名称。

When the @ConfigurationProperties bean is registered using configuration property scanning or through @EnableConfigurationProperties, the bean has a conventional name: <prefix>-<fqn>, where <prefix> is the environment key prefix specified in the @ConfigurationProperties annotation and <fqn> is the fully qualified name of the bean. If the annotation does not provide any prefix, only the fully qualified name of the bean is used.

假设它在“@14”包中,则上面“@15”示例的 bean 名称为“@16”。

Assuming that it is in the com.example.app package, the bean name of the SomeProperties example above is some.properties-com.example.app.SomeProperties.

我们建议“@26”只处理环境,尤其是,不从上下文中注入其他 bean。对于特殊情况,可以使用 setter 注入或该框架提供的任何“@27”接口(例如,如果您需要访问“@29”,则可以使用“@28”)。如果您仍然希望使用构造函数注入其他 bean,则配置属性 bean 必须使用“@30”进行注释,并使用基于 JavaBean 的属性绑定。

We recommend that @ConfigurationProperties only deal with the environment and, in particular, does not inject other beans from the context. For corner cases, setter injection can be used or any of the *Aware interfaces provided by the framework (such as EnvironmentAware if you need access to the Environment). If you still want to inject other beans using the constructor, the configuration properties bean must be annotated with @Component and use JavaBean-based property binding.

Using @ConfigurationProperties-annotated Types

这种配置方式特别适合于“@31”外部 YAML 配置,如下例所示:

This style of configuration works particularly well with the SpringApplication external YAML configuration, as shown in the following example:

my:
  service:
    remote-address: 192.168.1.1
    security:
      username: "admin"
      roles:
      - "USER"
      - "ADMIN"

要使用“@32”bean,您可以像注入其他任何 bean 一样注入它们,如下例所示:

To work with @ConfigurationProperties beans, you can inject them in the same way as any other bean, as shown in the following example:

使用“@33”还允许您生成元数据文件,IDE 可使用这些文件为您的专属密钥提供自动完成功能。有关详细信息,请参见“@34”。

Using @ConfigurationProperties also lets you generate metadata files that can be used by IDEs to offer auto-completion for your own keys. See the appendix for details.

Third-party Configuration

除了使用“@35”对类进行注释外,您还可以在公有的“@36”方法上使用它。当您希望将属性绑定到不受您控制的第三方组件时,这样做特别有用。

As well as using @ConfigurationProperties to annotate a class, you can also use it on public @Bean methods. Doing so can be particularly useful when you want to bind properties to third-party components that are outside of your control.

要从“@37”属性配置 bean,请将其“@38”添加到其 bean 注册,如下例所示:

To configure a bean from the Environment properties, add @ConfigurationProperties to its bean registration, as shown in the following example:

任何使用“@39”前缀定义的 JavaBean 属性都以类似于前面“@41”示例的方式映射到该“@40”bean。

Any JavaBean property defined with the another prefix is mapped onto that AnotherComponent bean in manner similar to the preceding SomeProperties example.

Relaxed Binding

Spring Boot 使用一些宽松的规则将“@42”属性绑定到“@43”bean,因此“@44”属性名称和 bean 属性名称之间不必完全匹配。这方面有用的常见示例包括以破折号分隔的环境属性(例如,“@45”绑定到“@46”)和首字母大写的环境属性(例如,“@47”绑定到“@48”)。

Spring Boot uses some relaxed rules for binding Environment properties to @ConfigurationProperties beans, so there does not need to be an exact match between the Environment property name and the bean property name. Common examples where this is useful include dash-separated environment properties (for example, context-path binds to contextPath), and capitalized environment properties (for example, PORT binds to port).

例如,考虑以下“@49”类:

As an example, consider the following @ConfigurationProperties class:

使用前面代码,可以使用以下所有属性名称:

With the preceding code, the following properties names can all be used:

Table 2. relaxed binding
Property Note

my.main-project.person.first-name

Kebab case, which is recommended for use in .properties and YAML files.

my.main-project.person.firstName

Standard camel case syntax.

my.main-project.person.first_name

Underscore notation, which is an alternative format for use in .properties and YAML files.

MY_MAINPROJECT_PERSON_FIRSTNAME

Upper case format, which is recommended when using system environment variables.

注释 mustprefix 值应为连字符形式(小写并由 - 分隔,例如 my.main-project.person)。

The prefix value for the annotation must be in kebab case (lowercase and separated by -, such as my.main-project.person).

Table 3. relaxed binding rules per property source
Property Source Simple List

Properties Files

Camel case, kebab case, or underscore notation

Standard list syntax using [ ] or comma-separated values

YAML Files

Camel case, kebab case, or underscore notation

Standard YAML list syntax or comma-separated values

Environment Variables

Upper case format with underscore as the delimiter (see Binding From Environment Variables).

Numeric values surrounded by underscores (see Binding From Environment Variables)

System properties

Camel case, kebab case, or underscore notation

Standard list syntax using [ ] or comma-separated values

当可能时,我们建议按照小写的连字符形式存储属性,例如 my.person.first-name=Rod

We recommend that, when possible, properties are stored in lower-case kebab format, such as my.person.first-name=Rod.

Binding Maps

绑定到 Map 属性时,您可能需要使用特殊的花括号形式以便保留原始 key 值。如果密钥没有被 [] 所包围,则将移除任何非字母数字、-. 的字符。

When binding to Map properties you may need to use a special bracket notation so that the original key value is preserved. If the key is not surrounded by [], any characters that are not alpha-numeric, - or . are removed.

例如,考虑绑定下面的属性到一个 Map<String,String>

For example, consider binding the following properties to a Map<String,String>:

my:
  map:
    "[/key1]": "value1"
    "[/key2]": "value2"
    "/key3": "value3"

对于 YAML 文件,为了正确解析密钥,花括号需要被引号包围。

For YAML files, the brackets need to be surrounded by quotes for the keys to be parsed properly.

上面的属性将绑定到一个 Map,其密钥为映射中的 /key1/key2key3。已从 key3 中删除斜杠,因为它没有被方括号包围。

The properties above will bind to a Map with /key1, /key2 and key3 as the keys in the map. The slash has been removed from key3 because it was not surrounded by square brackets.

绑定到标量值时,其中包含 . 的密钥不需要被 [] 所包围。标量值包括枚举值以及 java.lang 包中的所有类型(Object 除外)。将 a.b=c 绑定到 Map<String, String> 将保留密钥中的 .,并返回一个包含条目 {"a.b"="c"} 的映射。对于任何其他类型,如果您的 key 包含一个 .,则您需要使用花括号形式。例如,将 a.b=c 绑定到 Map<String, Object> 将返回一个包含条目 {"a"={"b"="c"}} 的映射,而 [a.b]=c 将返回一个包含条目 {"a.b"="c"} 的映射。

When binding to scalar values, keys with . in them do not need to be surrounded by []. Scalar values include enums and all types in the java.lang package except for Object. Binding a.b=c to Map<String, String> will preserve the . in the key and return a Map with the entry {"a.b"="c"}. For any other types you need to use the bracket notation if your key contains a .. For example, binding a.b=c to Map<String, Object> will return a Map with the entry {"a"={"b"="c"}} whereas [a.b]=c will return a Map with the entry {"a.b"="c"}.

Binding From Environment Variables

大多数操作系统都针对可用于环境变量的名称制定了严格的规则。例如,Linux shell 变量只能包含字母(azAZ)、数字(09)或下划线字符 (_)。根据惯例,Unix shell 变量的名称还会采用大写。

Most operating systems impose strict rules around the names that can be used for environment variables. For example, Linux shell variables can contain only letters (a to z or A to Z), numbers (0 to 9) or the underscore character (_). By convention, Unix shell variables will also have their names in UPPERCASE.

Spring Boot 的宽松绑定规则最大限度地设计为与这些命名限制兼容。

Spring Boot’s relaxed binding rules are, as much as possible, designed to be compatible with these naming restrictions.

要将规范形式中的属性名称转换为环境变量名称,您可以遵循这些规则:

To convert a property name in the canonical-form to an environment variable name you can follow these rules:

  • Replace dots (.) with underscores (_).

  • Remove any dashes (-).

  • Convert to uppercase.

例如,配置属性 spring.main.log-startup-info 将是一个名为 SPRING_MAIN_LOGSTARTUPINFO 的环境变量。

For example, the configuration property spring.main.log-startup-info would be an environment variable named SPRING_MAIN_LOGSTARTUPINFO.

在绑定到对象列表时也可以使用环境变量。要绑定到 List,应使用下划线在变量名称中包围元素编号。

Environment variables can also be used when binding to object lists. To bind to a List, the element number should be surrounded with underscores in the variable name.

例如,配置属性 my.service[0].other 将使用名为 MY_SERVICE_0_OTHER 的环境变量。

For example, the configuration property my.service[0].other would use an environment variable named MY_SERVICE_0_OTHER.

Caching

宽松绑定使用缓存来提高性能。默认情况下,此缓存仅应用于不可变属性源。例如,要自定义此行为,例如启用可变属性源的缓存,请使用 ConfigurationPropertyCaching

Relaxed binding uses a cache to improve performance. By default, this caching is only applied to immutable property sources. To customize this behavior, for example to enable caching for mutable property sources, use ConfigurationPropertyCaching.

Merging Complex Types

当列表在多个地方配置时,覆盖通过替换整个列表起作用。

When lists are configured in more than one place, overriding works by replacing the entire list.

例如,假设一个 s12 对象具有 s13 和 s14 属性,它们在默认为 s15 的情况下更新。以下示例从 s17 揭示了 s16 对象的列表:

For example, assume a MyPojo object with name and description attributes that are null by default. The following example exposes a list of MyPojo objects from MyProperties:

考虑以下配置:

Consider the following configuration:

my:
  list:
  - name: "my name"
    description: "my description"
---
spring:
  config:
    activate:
      on-profile: "dev"
my:
  list:
  - name: "my another name"

如果 dev 配置文件未激活,则 MyProperties.list 包含一个 MyPojo 条目,如前所定义。但是,如果 dev 配置文件已启用,则 list still 仅包含一个条目(名称为 my another name,描述为 null)。此配置 does not 会将第二个 MyPojo 实例添加到列表,但不会合并项目。

If the dev profile is not active, MyProperties.list contains one MyPojo entry, as previously defined. If the dev profile is enabled, however, the list still contains only one entry (with a name of my another name and a description of null). This configuration does not add a second MyPojo instance to the list, and it does not merge the items.

当在多个配置文件中指定 List 时,会使用优先级最高的那个(并且仅使用该那个)。考虑以下示例:

When a List is specified in multiple profiles, the one with the highest priority (and only that one) is used. Consider the following example:

my:
  list:
  - name: "my name"
    description: "my description"
  - name: "another name"
    description: "another description"
---
spring:
  config:
    activate:
      on-profile: "dev"
my:
  list:
  - name: "my another name"

在上述示例中,如果 dev 配置文件处于活动状态,则 MyProperties.list 包含 one MyPojo 条目(名称为 my another name,描述为 null)。对于 YAML,可以用逗号分隔的列表和 YAML 列表来完全覆盖列表的内容。

In the preceding example, if the dev profile is active, MyProperties.list contains one MyPojo entry (with a name of my another name and a description of null). For YAML, both comma-separated lists and YAML lists can be used for completely overriding the contents of the list.

对于 Map 属性,您可以与从多个来源获取的属性值绑定。但是,对于多个来源中的同一属性,将使用优先级最高的那个。以下示例从 MyProperties 公开 Map<String, MyPojo>

For Map properties, you can bind with property values drawn from multiple sources. However, for the same property in multiple sources, the one with the highest priority is used. The following example exposes a Map<String, MyPojo> from MyProperties:

考虑以下配置:

Consider the following configuration:

my:
  map:
    key1:
      name: "my name 1"
      description: "my description 1"
---
spring:
  config:
    activate:
      on-profile: "dev"
my:
  map:
    key1:
      name: "dev name 1"
    key2:
      name: "dev name 2"
      description: "dev description 2"

如果 dev 配置文件未激活,则 MyProperties.map 包含一个键为 key1 的条目(名称为 my name 1,描述为 my description 1)。但是,如果 dev 配置文件已启用,则 map 包含两个键为 key1(名称为 dev name 1,描述为 my description 1)和 key2 (名称为 dev name 2,描述为 dev description 2)的条目。

If the dev profile is not active, MyProperties.map contains one entry with key key1 (with a name of my name 1 and a description of my description 1). If the dev profile is enabled, however, map contains two entries with keys key1 (with a name of dev name 1 and a description of my description 1) and key2 (with a name of dev name 2 and a description of dev description 2).

上述合并规则应用于所有属性来源的属性,而不仅仅是文件。

The preceding merging rules apply to properties from all property sources, and not just files.

Properties Conversion

Spring Boot 尝试在绑定到 @ConfigurationProperties Bean 时强制将外部应用程序属性转换为正确的类型。如果您需要自定义类型转换,可以提供一个 ConversionService Bean(Bean 名称 conversionService)或自定义属性编辑器(通过 CustomEditorConfigurer Bean)或自定义 Converters(带标注为 @ConfigurationPropertiesBinding 的 Bean 定义)。

Spring Boot attempts to coerce the external application properties to the right type when it binds to the @ConfigurationProperties beans. If you need custom type conversion, you can provide a ConversionService bean (with a bean named conversionService) or custom property editors (through a CustomEditorConfigurer bean) or custom Converters (with bean definitions annotated as @ConfigurationPropertiesBinding).

由于该 Bean 在应用程序生命周期的非常早阶段被请求,因此请确保限制 ConversionService 使用的依赖项。通常,任何您需要的依赖项在创建时可能未完全初始化。如果您不需要用于配置密钥强制转换,并且仅依赖于使用 @ConfigurationPropertiesBinding 限定符的自定义转换器,则可以重命名您的自定义 ConversionService

As this bean is requested very early during the application lifecycle, make sure to limit the dependencies that your ConversionService is using. Typically, any dependency that you require may not be fully initialized at creation time. You may want to rename your custom ConversionService if it is not required for configuration keys coercion and only rely on custom converters qualified with @ConfigurationPropertiesBinding.

Converting Durations

Spring Boot 专用于表达持续时间。如果您公开 java.time.Duration 属性,则应用程序属性中提供以下格式:

Spring Boot has dedicated support for expressing durations. If you expose a java.time.Duration property, the following formats in application properties are available:

  • A regular long representation (using milliseconds as the default unit unless a @DurationUnit has been specified)

  • The standard ISO-8601 format {apiref-openjdk}/java.base/java/time/Duration.html#parse(java.lang.CharSequence)[used by java.time.Duration]

  • A more readable format where the value and the unit are coupled (10s means 10 seconds)

请考虑以下示例:

Consider the following example:

要指定 30 秒的会话超时,30PT30S`和 `30s`都是等效的。以下任一形式都可以指定 500 毫秒的读取超时:`500PT0.5S`和 `500ms

To specify a session timeout of 30 seconds, 30, PT30S and 30s are all equivalent. A read timeout of 500ms can be specified in any of the following form: 500, PT0.5S and 500ms.

您还可以使用任何受支持的单位。它们是:

You can also use any of the supported units. These are:

  • ns for nanoseconds

  • us for microseconds

  • ms for milliseconds

  • s for seconds

  • m for minutes

  • h for hours

  • d for days

默认单位是毫秒,可以使用 `@DurationUnit`覆盖,如上例所示。

The default unit is milliseconds and can be overridden using @DurationUnit as illustrated in the sample above.

如果您更喜欢使用构造函数绑定,可以使用相同的属性,如下例所示:

If you prefer to use constructor binding, the same properties can be exposed, as shown in the following example:

如果您正在升级一个 Long`属性,请确保在它不是毫秒时定义单位(使用 `@DurationUnit)。这样做提供了透明的升级路径,同时支持更丰富的格式。

If you are upgrading a Long property, make sure to define the unit (using @DurationUnit) if it is not milliseconds. Doing so gives a transparent upgrade path while supporting a much richer format.

Converting Periods

除了持续时间之外,Spring Boot 还可以使用 `java.time.Period`类型。以下格式可用于应用程序属性:

In addition to durations, Spring Boot can also work with java.time.Period type. The following formats can be used in application properties:

  • An regular int representation (using days as the default unit unless a @PeriodUnit has been specified)

  • The standard ISO-8601 format {apiref-openjdk}/java.base/java/time/Period.html#parse(java.lang.CharSequence)[used by java.time.Period]

  • A simpler format where the value and the unit pairs are coupled (1y3d means 1 year and 3 days)

简单格式支持以下单位:

The following units are supported with the simple format:

  • y for years

  • m for months

  • w for weeks

  • d for days

`java.time.Period`类型实际上从未存储周数,它是一个表示 "`7 days`"的快捷方式。

The java.time.Period type never actually stores the number of weeks, it is a shortcut that means “7 days”.

Converting Data Sizes

Spring Framework 有一个 `DataSize`值类型,表示以字节为单位的大小。如果您公开了一个 `DataSize`属性,应用程序属性中提供了以下格式:

Spring Framework has a DataSize value type that expresses a size in bytes. If you expose a DataSize property, the following formats in application properties are available:

  • A regular long representation (using bytes as the default unit unless a @DataSizeUnit has been specified)

  • A more readable format where the value and the unit are coupled (10MB means 10 megabytes)

请考虑以下示例:

Consider the following example:

要指定 10 兆字节的缓冲区大小,10`和 `10MB`是等效的。可以将大小阈值指定为 256 字节,如下所示:`256`或 `256B

To specify a buffer size of 10 megabytes, 10 and 10MB are equivalent. A size threshold of 256 bytes can be specified as 256 or 256B.

您还可以使用任何受支持的单位。它们是:

You can also use any of the supported units. These are:

  • B for bytes

  • KB for kilobytes

  • MB for megabytes

  • GB for gigabytes

  • TB for terabytes

默认单位是字节,可以使用 `@DataSizeUnit`覆盖,如上例所示。

The default unit is bytes and can be overridden using @DataSizeUnit as illustrated in the sample above.

如果您更喜欢使用构造函数绑定,可以使用相同的属性,如下例所示:

If you prefer to use constructor binding, the same properties can be exposed, as shown in the following example:

升级 Long 属性时,请确保在非字节的情况下定义单位(使用 @DataSizeUnit)。这样做可以提供一条透明的升级路径,同时支持更丰富的格式。

If you are upgrading a Long property, make sure to define the unit (using @DataSizeUnit) if it is not bytes. Doing so gives a transparent upgrade path while supporting a much richer format.

@ConfigurationProperties Validation

Spring Boot 会尝试验证 @ConfigurationProperties 类,只要它们使用 Spring 的 @Validated 注解进行注释。您可以在配置类上直接使用 JSR-303 jakarta.validation 约束注解。为此,请确保您的类路径中存在兼容的 JSR-303 实现,然后将约束注解添加到字段中,如下例所示:

Spring Boot attempts to validate @ConfigurationProperties classes whenever they are annotated with Spring’s @Validated annotation. You can use JSR-303 jakarta.validation constraint annotations directly on your configuration class. To do so, ensure that a compliant JSR-303 implementation is on your classpath and then add constraint annotations to your fields, as shown in the following example:

您还可以通过使用 @Validated`注释创建配置属性的 `@Bean 方法来触发验证。

You can also trigger validation by annotating the @Bean method that creates the configuration properties with @Validated.

为了确保即使未找到属性也始终触发嵌套属性的验证,关联的字段必须使用 @Valid`进行注释。以下示例基于前面的 `MyProperties 示例:

To ensure that validation is always triggered for nested properties, even when no properties are found, the associated field must be annotated with @Valid. The following example builds on the preceding MyProperties example:

您还可以通过创建名为 configurationPropertiesValidator 的 Bean 定义来添加自定义 Spring Validator。应该将 @Bean 方法声明为 static。配置属性验证器在应用程序生命周期的早期创建,并将 @Bean 方法声明为静态允许在无需实例化 @Configuration 类的情况下创建 Bean。这样做避免了可能由早期实例化引起的任何问题。

You can also add a custom Spring Validator by creating a bean definition called configurationPropertiesValidator. The @Bean method should be declared static. The configuration properties validator is created very early in the application’s lifecycle, and declaring the @Bean method as static lets the bean be created without having to instantiate the @Configuration class. Doing so avoids any problems that may be caused by early instantiation.

spring-boot-actuator 模块包括一个端点,该端点公开所有 @ConfigurationProperties Bean。将您的 Web 浏览器指向 /actuator/configprops 或使用等效的 JMX 端点。“Production ready features” 部分提供了详细信息。

The spring-boot-actuator module includes an endpoint that exposes all @ConfigurationProperties beans. Point your web browser to /actuator/configprops or use the equivalent JMX endpoint. See the "Production ready features" section for details.

@ConfigurationProperties vs. @Value

@Value 注解是一个核心容器特性,它不提供与类型安全配置属性相同的功能。下表总结了 @ConfigurationProperties@Value 支持的功能:

The @Value annotation is a core container feature, and it does not provide the same features as type-safe configuration properties. The following table summarizes the features that are supported by @ConfigurationProperties and @Value:

Feature @ConfigurationProperties @Value

Relaxed binding

Yes

Limited (see note below)

Meta-data support

Yes

No

SpEL evaluation

No

Yes

如果您确实想要使用 @Value,我们建议您使用其规范形式引用属性名称(仅使用小写字母的连字符形式)。这将允许 Spring Boot 使用与使用 relaxed binding @ConfigurationProperties 相同的逻辑。

If you do want to use @Value, we recommend that you refer to property names using their canonical form (kebab-case using only lowercase letters). This will allow Spring Boot to use the same logic as it does when relaxed binding @ConfigurationProperties.

例如,@Value("${demo.item-price}") 将从 application.properties 文件中选取 demo.item-pricedemo.itemPrice 形式,以及从系统环境中选取 DEMO_ITEMPRICE。如果您改为使用 @Value("${demo.itemPrice}"),则不会考虑 demo.item-priceDEMO_ITEMPRICE

For example, @Value("${demo.item-price}") will pick up demo.item-price and demo.itemPrice forms from the application.properties file, as well as DEMO_ITEMPRICE from the system environment. If you used @Value("${demo.itemPrice}") instead, demo.item-price and DEMO_ITEMPRICE would not be considered.

如果您为自己的组件定义了一组配置键,我们建议您将它们分组到使用 @ConfigurationProperties 进行注释的 POJO 中。这样做将为您提供结构化的类型安全对象,您可以将其注入到您自己的 Bean 中。

If you define a set of configuration keys for your own components, we recommend you group them in a POJO annotated with @ConfigurationProperties. Doing so will provide you with structured, type-safe object that you can inject into your own beans.

application property files 中的 SpEL 表达式在解析这些文件并填充环境时不会被处理。但是,可以在 @Value 中编写 SpEL 表达式。如果来自应用程序属性文件的属性值是 SpEL 表达式,则在通过 @Value 使用它时对其进行评估。

SpEL expressions from application property files are not processed at time of parsing these files and populating the environment. However, it is possible to write a SpEL expression in @Value. If the value of a property from an application property file is a SpEL expression, it will be evaluated when consumed through @Value.