Externalized Configuration
Spring Boot 允许你外部化配置,以便可以在不同的环境中使用相同的应用程序代码。你可以使用各种外部配置源,包括 Java 属性文件、YAML 文件、环境变量和命令行参数。
可以使用 @Value
批注将属性值直接注入到 Bean 中,通过 Spring 的 Environment
抽象访问,或通过 @ConfigurationProperties
的 bound to structured objects。
Spring Boot 使用了一个非常特殊的 PropertySource
顺序,该顺序旨在允许合理地覆盖值。后面的属性源可以覆盖前面定义的值。源按以下顺序考虑:
-
默认属性(通过设置
SpringApplication.setDefaultProperties
指定)。 -
你
@Configuration
类上的 {url-spring-framework-javadoc}/org/springframework/context/annotation/PropertySource.html[@PropertySource
] 批注。请注意,这些属性源在刷新应用程序上下文之前不会添加到Environment
中。对于某些属性(例如logging.
andspring.main.
),这是在刷新开始之前读取的,所以为时已晚。 -
配置数据(例如
application.properties
文件)。 -
RandomValuePropertySource
只有在random.*
中才有属性。 -
OS environment variables.
-
Java System properties (
System.getProperties()
). -
JNDI attributes from
java:comp/env
. -
ServletContext
init parameters. -
ServletConfig
init parameters. -
SPRING_APPLICATION_JSON
中的属性(嵌入在环境变量或系统属性中的内联 JSON)。 -
Command line arguments.
-
测试上的
properties
属性。可在@SpringBootTest
和 test annotations for testing a particular slice of your application 上使用。 -
在测试中使用 {url-spring-framework-javadoc}/org/springframework/test/context/DynamicPropertySource.html[
@DynamicPropertySource
] 注释。 -
在测试中使用 {url-spring-framework-javadoc}/org/springframework/test/context/TestPropertySource.html[
@TestPropertySource
] 注释。 -
当 devtools 处于活动状态时,在
$HOME/.config/spring-boot
目录中的 Devtools global settings properties。
配置数据文件按以下顺序考虑:
-
打包在 jar 中的 Application properties (`application.properties`和 YAML 变体)。
-
打包在 jar 中的 Profile-specific application properties (`application-{profile}.properties`和 YAML 变体)。
-
打包在 jar 外部的 Application properties (`application.properties`和 YAML 变体)。
-
打包在 jar 外部的 Profile-specific application properties (`application-{profile}.properties`和 YAML 变体)。
建议在整个应用程序中使用一种格式。如果您在同一位置含有 `.properties`和 YAML 格式的配置文件,则 `.properties`优先。 |
如果您使用环境变量而不是系统属性,则大多数操作系统不允许使用以句点分隔的键名,不过您可以改用下划线(例如,configprop:spring.config.name[format=envvar] 而不是 configprop:spring.config.name[])。有关详细信息,请参见 Binding From Environment Variables。 |
如果您的应用程序在 servlet 容器或应用程序服务器中运行,则 JNDI 属性(在 `java:comp/env`中)或 servlet 上下文初始化参数可用于代替环境变量或系统属性,或者与它们一起使用。 |
为了提供一个具体的示例,假设您开发一个 @Component
,该 @Component`使用一个 `name`属性,如下例所示:
include-code::MyBean[]
在应用程序类路径中(例如,在 jar 内部),您可以有一个 `application.properties`文件,该文件为 `name`提供明智的默认属性值。在新的环境中运行时,可以在 jar 外部提供一个 `application.properties`文件,该文件覆盖 `name
。对于一次性测试,您可以使用特定命令行开关启动(例如,java -jar app.jar --name="Spring"
)。
`env`和 `configprops`端点可用于确定属性具有特定值的原因。您可以使用这两个端点来诊断意外的属性值。有关详细信息,请参见“Production ready features”部分。 |
Accessing Command Line Properties
默认情况下,SpringApplication`将任何命令行选项参数(即以 `--`开头的参数,例如 `--server.port=9000
)转换为一个 property
,然后将它们添加到 Spring Environment
。如前所述,命令行属性始终优先于基于文件的属性源。
如果您不希望命令行属性添加到 Environment
,则可以使用 `SpringApplication.setAddCommandLineProperties(false)`禁用它们。
JSON Application Properties
环境变量和系统属性通常有受限,这意味着无法使用某些属性名称。为了解决此问题,Spring Boot 允许您将属性块编码到一个 JSON 结构中。
当您的应用程序启动时,所有 spring.application.json`或 `SPRING_APPLICATION_JSON`属性都将被解析并添加到 `Environment
。
例如,`SPRING_APPLICATION_JSON`属性可在 UN*X shell 中作为环境变量在命令行上提供:
$ SPRING_APPLICATION_JSON='{"my":{"name":"test"}}' java -jar myapp.jar
在下例中,最终得到 Spring 中的 my.name=test
。
同样,JSON 也可以作为一个系统属性提供:
$ java -Dspring.application.json='{"my":{"name":"test"}}' -jar myapp.jar
或者可以使用命令行参数提供 JSON:
$ java -jar myapp.jar --spring.application.json='{"my":{"name":"test"}}'
如果要部署到经典应用程序服务器,也可以使用名为 java:comp/env/spring.application.json
的 JNDI 变量。
尽管 JSON 中的 |
External Application Properties
应用程序启动时,Spring Boot 将自动查找并加载以下位置中的 application.properties
和 application.yaml
文件:
-
From the classpath[style="loweralpha"]
-
The classpath root
-
The classpath
/config
package
-
-
From the current directory[style="loweralpha"]
-
The current directory
-
当前目录中的
config/
子目录 -
config/
子目录的直接子目录
-
该列表按优先级排序(较低项中的值覆盖较早项)。加载的文件中的文档以 PropertySources
形式添加到 Spring Environment
中。
如果不希望将 application
作为配置文件的名称,可以通过指定 configprop:spring.config.name[] 环境属性切换到其他文件名。例如,要查找 myproject.properties
和 myproject.yaml
文件,可以按如下方式运行应用程序:
$ java -jar myproject.jar --spring.config.name=myproject
还可以通过使用 configprop:spring.config.location[] 环境属性引用显式位置。该属性接受一个或多个要检查位置的逗号分隔列表。
以下示例显示如何指定两份不同的文件:
$ java -jar myproject.jar --spring.config.location=\
optional:classpath:/default.properties,\
optional:classpath:/override.properties
如果存在 locations are optional ,可以使用前缀 |
非常早地使用 spring.config.name
、spring.config.location
和 spring.config.additional-location
来确定要加载哪些文件。必须将它们定义为环境属性(通常是操作系统环境变量、系统属性或命令行参数)。
如果 spring.config.location
包含目录(而不是文件),它们应以 /
结尾。在加载之前,将在运行时将它们追加到从 spring.config.name
生成的名称。spring.config.location
中指定的文件会被直接导入。
目录和文件位置值都会被展开以检查 profile-specific files 。例如,如果 |
在大多数情况下,添加的每个 configprop:spring.config.location[] 项都会引用单个文件或目录。位置按指定的顺序进行处理,后面的位置可以覆盖前面的位置。
如果有复杂的位置设置,并且使用特定于配置文件,则可能需要提供更多提示,以便 Spring Boot 知道应该如何将它们分组。位置组是同一级别所有位置的集合。例如,可能希望对所有类路径位置进行分组,然后对所有外部位置进行分组。位置组中的项应以 ;
分隔。有关更多详细信息,请参阅 “Profile Specific Files” 部分中的示例。
使用 spring.config.location
配置的位置会替换默认位置。例如,如果将 spring.config.location
配置为值 optional:classpath:/custom-config/,optional:file:./custom-config/
,那么考虑的位置的完整集合是:
-
optional:classpath:custom-config/
-
optional:file:./custom-config/
如果你希望添加其他位置,而不是替换它们,则可以使用 spring.config.additional-location
。从其他位置加载的属性可以覆盖默认位置中的属性。例如,如果配置的 spring.config.additional-location
值为 optional:classpath:/custom-config/,optional:file:./custom-config/
,考虑的位置的完整集合为:
-
optional:classpath:/;optional:classpath:/config/
-
optional:file:./;optional:file:./config/;optional:file:./config/*/
-
optional:classpath:custom-config/
-
optional:file:./custom-config/
此搜索顺序允许你在一个配置文件中指定默认值,然后在另一个配置文件中选择性重写这些值。你可以在默认位置之一中(或使用 spring.config.name
选择的任何其他基本名称)的 application.properties
(或使用 spring.config.name
选择的任何其他基本名称)中为你的应用程序提供默认值。然后可以使用位于自定义位置之一中的不同文件在运行时覆盖这些默认值。
Optional Locations
默认情况下,当指定的配置数据位置不存在时,Spring Boot 将抛出一个 ConfigDataLocationNotFoundException
,并且你的应用程序将不会启动。
如果你想指定一个位置,但你不介意它是否一直存在,则可以使用 optional:
前缀。你可以在 spring.config.location
和 spring.config.additional-location
属性以及 spring.config.import
声明中使用此前缀。
例如,即使不存在 myconfig.properties
文件,spring.config.import
值为 optional:file:./myconfig.properties
也可以允许你的应用程序启动。
如果你想要忽略所有 ConfigDataLocationNotFoundExceptions
并始终继续启动你的应用程序,你可以使用 spring.config.on-not-found
属性。使用 SpringApplication.setDefaultProperties(…)
或通过系统/环境变量将值设置为 ignore
。
Wildcard Locations
如果配置文件位置包含最后一个路径段的 *
字符,它会被视为通配符位置。通配符会在加载配置时展开,以便也检查立即子目录。当存在多种配置属性源时,诸如 Kubernetes 之类的环境中会特别有用通配符位置。
例如,如果你有一些 Redis 配置和一些 MySQL 配置,你可能想要将这两部分配置分开,同时要求两者都存在于 application.properties
文件中。这可能会导致两个单独的 application.properties
文件挂载在不同的位置,例如 /config/redis/application.properties
和 /config/mysql/application.properties
。在这种情况下,拥有 config/*/
的通配符位置将导致处理这两个文件。
默认情况下,Spring Boot 在默认搜索位置中包括 config/*/
。这意味着将搜索 jar 外部 /config
目录的所有子目录。
你可以自己使用 spring.config.location
和 spring.config.additional-location
属性使用通配符位置。
通配符位置对于作为目录的搜索位置只包含一个 |
通配符位置仅适用于外部目录。你不能在 |
Profile Specific Files
除了 application
属性文件之外,Spring Boot 还会尝试使用命名约定 application-{profile}
加载特定于概要的文件。例如,如果你的应用程序激活了名为 prod
的概要并使用了 YAML 文件,那么 application.yaml
和 application-prod.yaml
都将被考虑。
特定于概要的属性从与标准 application.properties
相同的位置加载,其中特定于概要的文件始终覆盖非特定于概要的文件。如果指定了多个概要,则应用“最近者优先”策略。例如,如果通过 configprop:spring.profiles.active[] 属性指定了概要 prod,live
,则 application-prod.properties
中的值可以被 application-live.properties
中的值覆盖。
“最近者优先”策略在 location group 级别应用。 /cfg application-live.properties /ext application-live.properties application-prod.properties 当我们有 configprop:spring.config.location[] 时,在所有
当我们反而有
|
如果未设置任何活动概要,Environment
有一组默认概要(默认情况下为 [default]
)。换言之,如果没有明确激活任何概要,则会考虑 application-default
中的属性。
属性文件只会加载一次。如果你已经直接 imported 了特定于概要的属性文件,则不会再次导入它。 |
Importing Additional Data
应用程序属性可以使用 spring.config.import
属性从其他位置导入更多配置数据。导入在被发现时处理,并被视为立即在声明导入的位置下方插入的附加文档。
例如,你可能在 classpath application.properties
文件中拥有以下内容:
spring: application: name: "myapp" config: import: "optional:file:./dev.properties"
这将触发从当前目录中导入一个 dev.properties
文件(如果存在此文件)。导入的 dev.properties
的值将优先于触发导入的文件。在上面的示例中,dev.properties
可以将 spring.application.name
重新定义为一个不同的值。
无论声明次数如何,导入只导入一次。导入在一个文档内部的 properties/yaml 文件中的定义顺序无关紧要。例如,下面的两个示例生成相同的结果:
spring: config: import: "my.properties" my: property: "value"
my: property: "value" spring: config: import: "my.properties"
在上面的两个示例中,my.properties
文件中的值将优先于触发其导入的文件。
多个位置可以指定在一个 spring.config.import
键下。位置将按照它们定义的顺序处理,其中后面的导入优先。
在适当的时候,Profile-specific variants 也考虑进行导入。上面的示例将导入 |
Spring Boot 包括可插入 API,该 API 支持各种不同的位置地址。默认情况下,您可以导入 Java 属性、YAML 和 “configuration trees”。
第三方 jar 可以为额外的技术提供支持(文件不必是本地的,没有此项要求)。例如,您可以想象外部存储(例如 Consul、Apache ZooKeeper 或 Netflix Archaius)中的配置数据。
如果您想支持您自己的位置,请查看 |
Importing Extensionless Files
一些云平台无法为已装载的文件添加文件扩展名。要导入这些没有扩展名的文件,你需要向 Spring Boot 提供一个提示,以便它知道如何加载它们。你可以通过在方括号中放置扩展名提示来执行此操作。
例如,假设你有希望导入为 yaml 的 s0 文件。你可以使用以下命令从 s1 导入它:
spring: config: import: "file:/etc/config/myconfig[.yaml]"
Using Configuration Trees
在云平台(例如 Kubernetes)上运行应用程序时,你通常需要读取平台提供的配置值。为此目的使用环境变量很常见,但这可能存在缺陷,尤其是在该值应保密时。
作为环境变量的替代方案,许多云平台现在允许你将配置映射到已装载的数据卷。例如,Kubernetes 可以卷装载 s4 和 s5。
可以使用两种常见的卷装载模式:
-
一个文件包含一组完整属性(通常写为 YAML)。
-
在目录树中写入多个文件,文件名变为“键”,内容变为“值”。
对于第一个案例,您可以直接使用 `spring.config.import`导入 YAML 或 Properties 文件,如 above中所述。对于第二个案例,您需要使用 `configtree:`前缀,以便 Spring Boot 知道它需要公开所有文件作为属性。
例如,让我们想象一下 Kubernetes 挂载了以下卷:
etc/
config/
myapp/
username
password
`username`文件的内容将是 config 值,而 `password`的内容将是机密。
要导入这些属性,您可以将以下内容添加到您的 `application.properties`或 `application.yaml`文件中:
spring: config: import: "optional:configtree:/etc/config/"
然后,您可以通过 `Environment`以通常的方式访问或注入 `myapp.username`和 `myapp.password`属性。
config 树下的文件夹和文件名称构成了属性名称。在上面的示例中,要以 |
带点表示法的文件名也正确地映射了。例如,在上面的示例中,`/etc/config`中的名为 `myapp.username`的文件将在 `Environment`中产生一个 `myapp.username`属性。 |
根据预期的内容,Configuration 树值可以绑定到字符串 `String`和 `byte[]`类型。 |
如果您有多个 config 树要从同一个父文件夹导入,可以使用通配符快捷方式。任何以 `/*/`结尾的 `configtree:`位置都将导入所有直接子级作为 config 树。与非通配符导入一样,每个 config 树下的文件夹和文件名称构成了属性名称。
例如,给定以下卷:
etc/
config/
dbconfig/
db/
username
password
mqconfig/
mq/
username
password
您可以使用 `configtree:/etc/config/*/`作为导入位置:
spring: config: import: "optional:configtree:/etc/config/*/"
这将添加 db.username
、db.password
、`mq.username`和 `mq.password`属性。
使用通配符加载的目录按字母顺序排序。如果您需要不同的顺序,则应将每个位置列为单独的导入 |
Configuration 树也可以用于 Docker 机密。当 Docker 群集服务被授予访问机密的权限时,机密会被装载到容器中。例如,如果在位置 `/run/secrets/`上装载了一个名为 `db.password`的机密,则可以使用以下内容使 `db.password`可用于 Spring 环境:
spring: config: import: "optional:configtree:/run/secrets/"
Property Placeholders
application.properties`和 `application.yaml`中的值在使用时将通过现有的 `Environment`进行过滤,因此您可以返回到先前定义的值(例如,来自系统属性或环境变量)。标准 `${name}`属性占位符语法可以在值中的任何位置使用。属性占位符还可以使用 `:`指定默认值,以将默认值与属性名称分开,例如 `${name:default}
。
以下示例显示了带或不带默认值使用占位符的情况:
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
。
您应该始终使用规范形式(仅使用小写字母的 kebab-case)在占位符中引用属性名称。这将允许 Spring Boot 使用与处理 relaxed binding |
还可以使用这种技术创建现有 Spring Boot 属性的 “short” 变体。请参阅 Use '`Short’ Command Line Arguments 了解详情。 |
Working With Multi-Document Files
Spring Boot 允许将一个物理文件拆分为多个独立添加的逻辑文档。按从上到下的顺序处理文档。后面的文档可以覆盖早期文档中定义的属性。
对于 application.yaml
文件,使用标准 YAML 多文档语法。三个连续连字符表示一个文档的结尾和下一个文档的开头。
例如,以下文件有两个逻辑文档:
spring:
application:
name: "MyApp"
---
spring:
application:
name: "MyCloudApp"
config:
activate:
on-cloud-platform: "kubernetes"
对于 application.properties
文件,使用特殊的 #---
或 !---
注释来标记文档拆分:
spring.application.name=MyApp
#---
spring.application.name=MyCloudApp
spring.config.activate.on-cloud-platform=kubernetes
属性文件分隔符前面不能有任何空格,并且必须有恰好三个连字符。分隔符之前和之后的行不能相同注释前缀。 |
多文档属性文件通常与激活属性(如 |
无法使用 @PropertySource
或 @TestPropertySource
注释加载多文档属性文件。
Activation Properties
有时仅在满足特定条件时激活给定的属性集是很有用的。例如,可以具备仅在特定配置文件处于活动状态时才相关的属性。
可以使用 spring.config.activate.*
根据条件激活属性文档。
以下激活属性可用:
Property | Note |
---|---|
|
文档处于活动状态必须匹配的配置文件表达式。 |
|
文档处于活动状态必须检测到的 |
例如,以下指定第二个文档仅在 Kubernetes 上运行时处于活动状态,并且仅当 “prod” 或 “staging” 配置文件处于活动状态时:
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 Cloud Vault 项目将提供将外部配置存储在 HashiCorp Vault 中的支持。
Working With YAML
如果您使用 “Starters”, |
Mapping YAML to Properties
YAML 文档需要从其分层格式转换为可以用 Spring Environment
使用的平面结构。例如,考虑以下 YAML 文档:
environments:
dev:
url: "https://dev.example.com"
name: "Developer Setup"
prod:
url: "https://another.example.com"
name: "My Cool App"
为了从 Environment
访问这些属性,它们会被展平如下:
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:
my:
servers:
- "dev.example.com"
- "another.example.com"
前面对例将被转换为以下属性:
my.servers[0]=dev.example.com
my.servers[1]=another.example.com
使用 |
YAML 文件不能使用 @PropertySource
或 @TestPropertySource
注释加载。因此,如果您需要以这种方式加载值,则需要使用属性文件。
Configuring Random Values
RandomValuePropertySource
对于注入随机值(例如注入到机密或测试案例中)很有用。它可以生成整数、长整数、UUID 或字符串,如下例所示:
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
是最大值(不包括)。
Configuring System Environment Properties
Spring Boot 支持为环境属性设置前缀。如果系统环境由多个 Spring Boot 应用程序共享,并且这些应用程序具有不同的配置要求,此功能非常有用。系统环境属性的前缀可以在 SpringApplication
上直接设置。
例如,如果您将前缀设置为 input
,则诸如 remote.timeout
的属性也会在系统环境中解析为 input.remote.timeout
。
Type-safe Configuration Properties
使用 @Value("${property}")
注释注入配置属性有时会很麻烦,尤其是在处理多属性或数据本质上是分层的情况下。Spring Boot 提供了一种处理属性的替代方法,该方法允许经过强类型处理的 Bean 管理和验证应用程序的配置。
JavaBean Properties Binding
可以绑定一个声明标准 JavaBean 属性的 Bean,如下例所示:
前述 POJO 定义了以下属性:
-
my.service.enabled
,默认值为false
。 -
my.service.remote-address
,类型可以从String
强制转换。 -
s6 ,其中嵌套的“安全性”对象由属性名称确定。特别是,该类型在那里根本没有使用,可能已被 s7 替代。
-
my.service.security.password
. -
s8,其中 s9 的集合默认为 s10。
映射到 Spring Boot 中可用的 s11 类的属性(通过属性文件、YAML 文件、环境变量和其他机制进行配置)是公开 API,但该类的访问器(getter/setter)本身不用于直接使用。 |
这种安排依赖于默认的空构造函数,而 getter 和 setter 通常是强制性的,因为绑定是通过标准 Java Beans 属性描述符进行的,就像在 Spring MVC 中一样。在以下情况下可以省略 setter:
有些人使用 Project Lombok 自动添加获取器和设置器。请确保 Lombok 不针对此类类型生成任何特定构造函数,因为容器会自动使用它实例化对象。 最后,只考虑标准 Java Bean 属性,并且不支持静态属性上的绑定。 |
Constructor Binding
前一节中的示例可以用不可变的方式改写,如下例所示:
在此设置中,存在一个单参数化构造函数暗示应使用构造函数绑定。这意味着绑定器将找到具有您希望绑定的参数的构造函数。如果您的类具有多个构造函数,则 @ConstructorBinding
注解可用于指定应针对构造函数绑定使用哪个构造函数。要选择不为具有单个参数化构造函数的类进行构造函数绑定,必须使用 @Autowired
注解构造函数。构造函数绑定可用于记录。除非记录有多个构造函数,否则无需使用 @ConstructorBinding
。
构造函数绑定类的嵌套成员(如上述示例中的 Security
)也将通过其构造函数进行绑定。
可以使用 @DefaultValue
在构造函数参数和记录组件上指定默认值。转换服务将应用于强制转换批注的 String
值为缺少属性的目标类型。
参考前一个示例,如果没有任何属性绑定到 Security
,则 MyProperties
实例将包含 security
的 null
值。为了使其包含一个非空 Security
实例,即使没有任何属性绑定到它(当使用 Kotlin 时,这要求 Security
的 username
和 password
参数被声明为可为空的,因为它们没有默认值),请使用 @DefaultValue
空注解:
要使用构造函数绑定,必须使用 |
要在本机映像中使用构造函数绑定,必须使用 |
不建议将 |
Enabling @ConfigurationProperties-annotated Types
Spring Boot 提供基础设施,用于绑定“@1”类型并将其注册为 bean。您可以逐个类启用配置属性,或启用与组件扫描工作方式类似的配置属性扫描。
有时,使用“@2”进行注释的类可能不适合扫描,例如,如果您正在开发自己的自动配置,或您希望有条件地启用它们。在这些情况下,请使用“@3”注释指定要使用该类型的列表。这可以在任何“@4”类上完成,如下例所示:
要使用配置属性扫描,请向您的应用程序添加“@5”注释。通常,它被添加到使用“@6”进行注释的主应用程序类,但它可以被添加到任何“@7”类。默认情况下,将从声明注释的类的包中进行扫描。如果您希望定义要扫描的特定包,可以按照如下示例进行操作:
当“@8”bean 使用配置属性扫描或通过“@9”注册时,bean 具有常规名称:“@10”,其中“@11”是在“@12”注释中指定的环境密钥前缀,“@13”是 bean 的完全限定名称。如果注释未提供任何前缀,则只使用 bean 的完全限定名称。 假设它在“@14”包中,则上面“@15”示例的 bean 名称为“@16”。 |
我们建议“@26”只处理环境,尤其是,不从上下文中注入其他 bean。对于特殊情况,可以使用 setter 注入或该框架提供的任何“@27”接口(例如,如果您需要访问“@29”,则可以使用“@28”)。如果您仍然希望使用构造函数注入其他 bean,则配置属性 bean 必须使用“@30”进行注释,并使用基于 JavaBean 的属性绑定。
Using @ConfigurationProperties-annotated Types
这种配置方式特别适合于“@31”外部 YAML 配置,如下例所示:
my:
service:
remote-address: 192.168.1.1
security:
username: "admin"
roles:
- "USER"
- "ADMIN"
要使用“@32”bean,您可以像注入其他任何 bean 一样注入它们,如下例所示:
使用“@33”还允许您生成元数据文件,IDE 可使用这些文件为您的专属密钥提供自动完成功能。有关详细信息,请参见“@34”。 |
Third-party Configuration
除了使用“@35”对类进行注释外,您还可以在公有的“@36”方法上使用它。当您希望将属性绑定到不受您控制的第三方组件时,这样做特别有用。
要从“@37”属性配置 bean,请将其“@38”添加到其 bean 注册,如下例所示:
任何使用“@39”前缀定义的 JavaBean 属性都以类似于前面“@41”示例的方式映射到该“@40”bean。
Relaxed Binding
Spring Boot 使用一些宽松的规则将“@42”属性绑定到“@43”bean,因此“@44”属性名称和 bean 属性名称之间不必完全匹配。这方面有用的常见示例包括以破折号分隔的环境属性(例如,“@45”绑定到“@46”)和首字母大写的环境属性(例如,“@47”绑定到“@48”)。
例如,考虑以下“@49”类:
使用前面代码,可以使用以下所有属性名称:
Property | Note |
---|---|
|
连字符形式,建议用于 |
|
Standard camel case syntax. |
|
下划线形式,作为替代格式使用在 |
|
大写形式,使用系统环境变量时建议。 |
注释 must 的 |
Property Source | Simple | List |
---|---|---|
Properties Files |
驼峰形式、连字符形式或下划线形式 |
使用 |
YAML Files |
驼峰形式、连字符形式或下划线形式 |
标准 YAML 列表语法或逗号分隔值 |
Environment Variables |
大写形式,下划线作为分隔符(参见 Binding From Environment Variables)。 |
由下划线包围的数字值(参见 Binding From Environment Variables) |
System properties |
驼峰形式、连字符形式或下划线形式 |
使用 |
当可能时,我们建议按照小写的连字符形式存储属性,例如 |
Binding Maps
绑定到 Map
属性时,您可能需要使用特殊的花括号形式以便保留原始 key
值。如果密钥没有被 []
所包围,则将移除任何非字母数字、-
或 .
的字符。
例如,考虑绑定下面的属性到一个 Map<String,String>
:
my: map: "[/key1]": "value1" "[/key2]": "value2" "/key3": "value3"
对于 YAML 文件,为了正确解析密钥,花括号需要被引号包围。 |
上面的属性将绑定到一个 Map
,其密钥为映射中的 /key1
、/key2
和 key3
。已从 key3
中删除斜杠,因为它没有被方括号包围。
绑定到标量值时,其中包含 .
的密钥不需要被 []
所包围。标量值包括枚举值以及 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"}
的映射。
Binding From Environment Variables
大多数操作系统都针对可用于环境变量的名称制定了严格的规则。例如,Linux shell 变量只能包含字母(a
到 z
或 A
到 Z
)、数字(0
到 9
)或下划线字符 (_
)。根据惯例,Unix shell 变量的名称还会采用大写。
Spring Boot 的宽松绑定规则最大限度地设计为与这些命名限制兼容。
要将规范形式中的属性名称转换为环境变量名称,您可以遵循这些规则:
-
将点 (
.
) 替换为下划线 (_
)。 -
Remove any dashes (
-
). -
Convert to uppercase.
例如,配置属性 spring.main.log-startup-info
将是一个名为 SPRING_MAIN_LOGSTARTUPINFO
的环境变量。
在绑定到对象列表时也可以使用环境变量。要绑定到 List
,应使用下划线在变量名称中包围元素编号。
例如,配置属性 my.service[0].other
将使用名为 MY_SERVICE_0_OTHER
的环境变量。
Merging Complex Types
当列表在多个地方配置时,覆盖通过替换整个列表起作用。
例如,假设一个 s12 对象具有 s13 和 s14 属性,它们在默认为 s15 的情况下更新。以下示例从 s17 揭示了 s16 对象的列表:
考虑以下配置:
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
实例添加到列表,但不会合并项目。
当在多个配置文件中指定 List
时,会使用优先级最高的那个(并且仅使用该那个)。考虑以下示例:
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 列表来完全覆盖列表的内容。
对于 Map
属性,您可以与从多个来源获取的属性值绑定。但是,对于多个来源中的同一属性,将使用优先级最高的那个。以下示例从 MyProperties
公开 Map<String, MyPojo>
:
考虑以下配置:
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
)的条目。
上述合并规则应用于所有属性来源的属性,而不仅仅是文件。 |
Properties Conversion
Spring Boot 尝试在绑定到 @ConfigurationProperties
Bean 时强制将外部应用程序属性转换为正确的类型。如果您需要自定义类型转换,可以提供一个 ConversionService
Bean(Bean 名称 conversionService
)或自定义属性编辑器(通过 CustomEditorConfigurer
Bean)或自定义 Converters
(带标注为 @ConfigurationPropertiesBinding
的 Bean 定义)。
由于该 Bean 在应用程序生命周期的非常早阶段被请求,因此请确保限制 |
Converting Durations
Spring Boot 专用于表达持续时间。如果您公开 java.time.Duration
属性,则应用程序属性中提供以下格式:
-
常规
long
表示(使用毫秒作为默认单位,除非已指定@DurationUnit
) -
标准的 ISO-8601 格式 {apiref-openjdk}/java.base/java/time/Duration.html#parse(java.lang.CharSequence)[
java.time.Duration
使用的格式] -
一种更可读的格式,其中值和单位配对(`10s`表示 10 秒)。
请考虑以下示例:
要指定 30 秒的会话超时,30
、PT30S`和 `30s`都是等效的。以下任一形式都可以指定 500 毫秒的读取超时:`500
、PT0.5S`和 `500ms
。
您还可以使用任何受支持的单位。它们是:
-
ns
for nanoseconds -
us
for microseconds -
ms
for milliseconds -
s
for seconds -
m
for minutes -
h
for hours -
d
for days
默认单位是毫秒,可以使用 `@DurationUnit`覆盖,如上例所示。
如果您更喜欢使用构造函数绑定,可以使用相同的属性,如下例所示:
如果您正在升级一个 |
Converting Periods
除了持续时间之外,Spring Boot 还可以使用 `java.time.Period`类型。以下格式可用于应用程序属性:
-
一个常规的
int`表示(使用天数作为默认单位,除非指定了 `@PeriodUnit
) -
标准的 ISO-8601 格式 {apiref-openjdk}/java.base/java/time/Period.html#parse(java.lang.CharSequence)[`java.time.Period`使用]
-
一种更简单的格式,其中值和单位配对(`1y3d`表示 1 年和 3 天)
简单格式支持以下单位:
-
y
for years -
m
for months -
w
for weeks -
d
for days
`java.time.Period`类型实际上从未存储周数,它是一个表示 "`7 days`"的快捷方式。 |
Converting Data Sizes
Spring Framework 有一个 `DataSize`值类型,表示以字节为单位的大小。如果您公开了一个 `DataSize`属性,应用程序属性中提供了以下格式:
-
一个常规的
long`表示(使用字节作为默认单位,除非指定了 `@DataSizeUnit
) -
一种更可读的格式,其中值和单位配对(`10MB`表示 10 兆字节)
请考虑以下示例:
要指定 10 兆字节的缓冲区大小,10`和 `10MB`是等效的。可以将大小阈值指定为 256 字节,如下所示:`256`或 `256B
。
您还可以使用任何受支持的单位。它们是:
-
B
for bytes -
KB
for kilobytes -
MB
for megabytes -
GB
for gigabytes -
TB
for terabytes
默认单位是字节,可以使用 `@DataSizeUnit`覆盖,如上例所示。
如果您更喜欢使用构造函数绑定,可以使用相同的属性,如下例所示:
升级 |
@ConfigurationProperties Validation
Spring Boot 会尝试验证 @ConfigurationProperties
类,只要它们使用 Spring 的 @Validated
注解进行注释。您可以在配置类上直接使用 JSR-303 jakarta.validation
约束注解。为此,请确保您的类路径中存在兼容的 JSR-303 实现,然后将约束注解添加到字段中,如下例所示:
您还可以通过使用 |
为了确保即使未找到属性也始终触发嵌套属性的验证,关联的字段必须使用 @Valid`进行注释。以下示例基于前面的 `MyProperties
示例:
您还可以通过创建名为 configurationPropertiesValidator
的 Bean 定义来添加自定义 Spring Validator
。应该将 @Bean
方法声明为 static
。配置属性验证器在应用程序生命周期的早期创建,并将 @Bean
方法声明为静态允许在无需实例化 @Configuration
类的情况下创建 Bean。这样做避免了可能由早期实例化引起的任何问题。
|
@ConfigurationProperties vs. @Value
@Value
注解是一个核心容器特性,它不提供与类型安全配置属性相同的功能。下表总结了 @ConfigurationProperties
和 @Value
支持的功能:
Feature | @ConfigurationProperties |
@Value |
---|---|---|
Yes |
Limited (see note below) |
|
Yes |
No |
|
|
No |
Yes |
如果您确实想要使用 |
如果您为自己的组件定义了一组配置键,我们建议您将它们分组到使用 @ConfigurationProperties
进行注释的 POJO 中。这样做将为您提供结构化的类型安全对象,您可以将其注入到您自己的 Bean 中。
application property files 中的 SpEL
表达式在解析这些文件并填充环境时不会被处理。但是,可以在 @Value
中编写 SpEL
表达式。如果来自应用程序属性文件的属性值是 SpEL
表达式,则在通过 @Value
使用它时对其进行评估。