对于最新的稳定版本,请使用 Spring Boot 3.5.5! |
外部化配置
Spring Boot 允许您将配置外部化,以便您可以在不同的环境中使用相同的应用程序代码。 您可以使用各种外部配置源,包括 Java 属性文件、YAML 文件、环境变量和命令行参数。
属性值可以通过使用@Value
注释,通过 Spring 的Environment
抽象,或者通过@ConfigurationProperties
.
Spring Boot 使用非常特殊的PropertySource
order 的命令,旨在允许合理地覆盖值。
较高的属性源可以覆盖较早的属性源中定义的值。
按以下顺序考虑来源:
-
默认属性(通过设置
SpringApplication.setDefaultProperties(Map)
). -
@PropertySource
注释@Configuration
类。 请注意,此类属性源不会添加到Environment
直到刷新应用程序上下文。 这为时已晚,无法配置某些属性,例如logging.*
和spring.main.*
在刷新开始之前读取。 -
配置数据(例如
application.properties
文件)。 -
一个
RandomValuePropertySource
仅在random.*
. -
作系统环境变量。
-
Java 系统属性 (
System.getProperties()
). -
JNDI 属性
java:comp/env
. -
ServletContext
init 参数。 -
ServletConfig
init 参数。 -
属性来自
SPRING_APPLICATION_JSON
(嵌入在环境变量或系统属性中的内联 JSON)。 -
命令行参数。
-
properties
属性。 适用于@SpringBootTest
以及用于测试应用程序特定切片的测试注释。 -
@DynamicPropertySource
测试中的注释。 -
@TestPropertySource
测试上的注释。 -
Devtools 全局设置属性中的
$HOME/.config/spring-boot
目录。
配置文件按以下顺序考虑:
-
打包在 jar 中的应用程序属性 (
application.properties
和 YAML 变体)。 -
打包在jar中的特定于配置文件的应用程序属性(
application-{profile}.properties
和 YAML 变体)。 -
打包 jar 外部的应用程序属性 (
application.properties
和 YAML 变体)。 -
打包的 jar 之外的特定于配置文件的应用程序属性 (
application-{profile}.properties
和 YAML 变体)。
建议对整个应用程序坚持使用一种格式。
如果您有包含两者的配置文件.properties 和 YAML 格式在同一位置,.properties 优先。 |
如果使用环境变量而不是系统属性,则大多数作系统不允许使用以句点分隔的键名,但可以改用下划线(例如,SPRING_CONFIG_NAME 而不是spring.config.name ).
有关详细信息,请参阅从环境变量绑定。 |
如果您的应用程序在 Servlet 容器或应用程序服务器中运行,那么 JNDI 属性(在java:comp/env ) 或 servlet 上下文初始化参数可以代替环境变量或系统属性,或者与环境变量或系统属性一起使用。 |
为了提供一个具体的例子,假设您开发了一个@Component
使用name
属性,如以下示例所示:
-
Java
-
Kotlin
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class MyBean {
@Value("${name}")
private String name;
// ...
}
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Component
@Component
class MyBean {
@Value("\${name}")
private val name: String? = null
// ...
}
在您的应用程序类路径上(例如,在 jar 中),您可以有一个application.properties
文件,该文件为name
.
在新环境中运行时,application.properties
可以在 jar 外部提供文件,以覆盖name
.
对于一次性测试,您可以使用特定的命令行开关(例如java -jar app.jar --name="Spring"
).
这env 和configprops 终结点可用于确定属性具有特定值的原因。
可以使用这两个终结点来诊断意外的属性值。
有关详细信息,请参阅生产就绪功能部分。 |
访问命令行属性
默认情况下,SpringApplication
转换任何命令行选项参数(即以 开头的参数,例如--
--server.port=9000
) 设置为property
并将它们添加到 SpringEnvironment
.
如前所述,命令行属性始终优先于基于文件的属性源。
如果您不希望将命令行属性添加到Environment
,您可以使用以下命令禁用它们SpringApplication.setAddCommandLineProperties(false)
.
JSON 应用程序属性
环境变量和系统属性通常具有限制,这意味着某些属性名称无法使用。 为了帮助解决这个问题,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
在前面的示例中,您最终会遇到my.name=test
在SpringEnvironment
.
也可以将相同的 JSON 作为系统属性提供:
$ java -Dspring.application.json='{"my":{"name":"test"}}' -jar myapp.jar
或者,您可以使用命令行参数提供 JSON:
$ java -jar myapp.jar --spring.application.json='{"my":{"name":"test"}}'
如果您要部署到经典的 Application Server,您还可以使用名为java:comp/env/spring.application.json
.
虽然null JSON 中的值将添加到生成的属性源中,PropertySourcesPropertyResolver 对待null 属性作为缺失值。这意味着 JSON 无法使用null 价值。 |
外部应用程序属性
Spring Boot 将自动查找并加载application.properties
和application.yaml
应用程序启动时从以下位置发送的文件:
-
从类路径
-
类路径根
-
类路径
/config
包
-
-
从当前目录
-
当前目录
-
这
config/
子目录 -
的直接子目录
config/
子目录
-
该列表按优先级排序(较低项的值覆盖较早的项)。
加载文件中的文档将添加为PropertySource
实例到 SpringEnvironment
.
如果你不喜欢application
作为配置文件名,您可以通过指定spring.config.name
environment 属性。
例如,要查找myproject.properties
和myproject.yaml
文件,您可以按如下方式运行您的应用程序:
$ java -jar myproject.jar --spring.config.name=myproject
您还可以使用spring.config.location
environment 属性。
此属性接受一个或多个要检查的位置的逗号分隔列表。
以下示例演示如何指定两个不同的文件:
$ java -jar myproject.jar --spring.config.location=\
optional:classpath:/default.properties,\
optional:classpath:/override.properties
使用前缀optional: 如果位置是可选的,并且您不介意它们是否存在。 |
spring.config.name ,spring.config.location 和spring.config.additional-location 很早就用于确定必须加载哪些文件。
它们必须定义为环境属性(通常是作系统环境变量、系统属性或命令行参数)。 |
如果spring.config.location
包含目录(与文件相反),它们应该以 结尾。
在运行时,它们将附加从/
spring.config.name
在加载之前。
中指定的文件spring.config.location
直接导入。
目录和文件位置值也会展开,以检查特定于配置文件的文件。
例如,如果您有spring.config.location 之classpath:myconfig.properties ,您还会发现合适的classpath:myconfig-<profile>.properties 文件已加载。 |
在大多数情况下,每个spring.config.location
您添加的项将引用单个文件或目录。
位置按定义的顺序进行处理,后面的位置可以覆盖前面位置的值。
如果您有复杂的位置设置,并且使用特定于配置文件的配置文件,则可能需要提供进一步的提示,以便 Spring Boot 知道应该如何对它们进行分组。
位置组是在同一级别考虑的所有位置的集合。
例如,您可能希望对所有类路径位置进行分组,然后对所有外部位置进行分组。
位置组中的项目应用 分隔。
有关更多详细信息,请参阅“配置文件特定文件”部分中的示例。;
使用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/
通过此搜索顺序,您可以在一个配置文件中指定默认值,然后有选择地覆盖另一个配置文件中的这些值。您可以在application.properties
(或您选择的任何其他基本名称spring.config.name
) 在默认位置之一。然后,可以在运行时使用位于其中一个自定义位置的不同文件覆盖这些默认值。
可选地点
默认情况下,当指定的配置数据位置不存在时,Spring Boot 将抛出一个ConfigDataLocationNotFoundException
并且您的应用程序将不会启动。
如果您想指定一个位置,但您不介意它是否总是存在,您可以使用optional:
前缀。 您可以将此前缀与spring.config.location
和spring.config.additional-location
属性,以及spring.config.import
声明。
例如,一个spring.config.import
值optional:file:./myconfig.properties
允许您的应用程序启动,即使myconfig.properties
文件丢失。
如果您想忽略所有ConfigDataLocationNotFoundException
错误并始终继续启动您的应用程序,您可以使用spring.config.on-not-found
财产。 将值设置为ignore
用SpringApplication.setDefaultProperties(…)
或使用系统/环境变量。
通配符位置
如果配置文件位置包含最后一个路径段的字符,则该位置被视为通配符位置。加载配置时,通配符会展开,以便同时检查直接子目录。当配置属性有多个来源时,通配符位置在 Kubernetes 等环境中特别有用。*
例如,如果你有一些 Redis 配置和一些 MySQL 配置,你可能希望将这两部分配置分开,同时要求这两部分都存在于application.properties
文件。
这可能会导致两个单独的application.properties
挂载在不同位置的文件,例如/config/redis/application.properties
和/config/mysql/application.properties
.
在这种情况下,通配符位置为config/*/
,将导致两个文件都被处理。
默认情况下,Spring Boot 包括config/*/
在默认搜索位置中。
这意味着/config
将搜索 jar 外部的目录。
您可以自己使用通配符位置,并使用spring.config.location
和spring.config.additional-location
性能。
通配符位置必须仅包含一个并以 结尾的搜索位置,即目录或* */ */<filename> 用于文件搜索位置。
带有通配符的位置根据文件名的绝对路径按字母顺序排序。 |
通配符位置仅适用于外部目录。不能在classpath: 位置。 |
配置文件特定文件
以及application
属性文件,Spring Boot 还将尝试使用命名约定加载特定于配置文件的文件application-{profile}
.
例如,如果您的应用程序激活名为prod
并使用 YAML 文件,则同时使用application.yaml
和application-prod.yaml
将被考虑。
特定于配置文件的属性从与标准相同的位置加载application.properties
,特定于配置文件的文件始终覆盖非特定文件。如果指定了多个配置文件,则应用后赢策略。例如,如果配置文件prod,live
由spring.profiles.active
属性,值application-prod.properties
可以被那些application-live.properties
.
后赢策略适用于位置组级别。 一个 例如,继续我们的 /cfg application-live.properties /ext application-live.properties application-prod.properties 当我们有一个
当我们有
|
这Environment
具有一组默认配置文件(默认情况下,[default]
),如果未设置活动配置文件,则使用该配置文件。换句话说,如果没有显式激活配置文件,则属性application-default
被考虑。
属性文件只加载一次。如果您已经直接导入了配置文件特定的属性文件,则不会再次导入该文件。 |
导入其他数据
应用程序属性可以使用spring.config.import
财产。 导入在发现时进行处理,并被视为插入紧邻声明导入的文档下方的附加文档。
例如,您的类路径中可能有以下内容application.properties
文件:
-
Properties
-
YAML
spring.application.name=myapp
spring.config.import=optional:file:./dev.properties
spring:
application:
name: "myapp"
config:
import: "optional:file:./dev.properties"
这将触发导入dev.properties
当前目录中的文件(如果存在此类文件)。
导入的dev.properties
将优先于触发导入的文件。
在上面的示例中,dev.properties
可以重新定义spring.application.name
到不同的值。
无论声明多少次,导入都只会导入一次。
使用“固定”和“导入相对”位置
导入可以指定为固定或导入相对位置。
固定位置始终解析为相同的底层资源,无论spring.config.import
属性被声明。
导入相对位置相对于声明spring.config.import
财产。
以正斜杠 () 或 URL 样式前缀 (/
file:
,classpath:
等)被认为是固定的。
所有其他位置都被视为进口相对位置。
optional: 在确定位置是固定位置还是导入相对位置时,不考虑前缀。 |
例如,假设我们有一个/demo
包含我们的application.jar
文件。
我们可能会添加一个/demo/application.properties
文件,内容如下:
spring.config.import=optional:core/core.properties
这是一个导入相对位置,因此将尝试加载文件/demo/core/core.properties
如果存在的话。
如果/demo/core/core.properties
内容如下:
spring.config.import=optional:extra/extra.properties
它将尝试加载/demo/core/extra/extra.properties
.
这optional:extra/extra.properties
相对于/demo/core/core.properties
所以完整目录是/demo/core/
+ extra/extra.properties
.
属性排序
在 properties/yaml 文件中的单个文档中定义导入的顺序无关紧要。 例如,下面的两个示例产生相同的结果:
-
Properties
-
YAML
spring.config.import=my.properties
my.property=value
spring:
config:
import: "my.properties"
my:
property: "value"
-
Properties
-
YAML
my.property=value
spring.config.import=my.properties
my:
property: "value"
spring:
config:
import: "my.properties"
在上述两个示例中,来自my.properties
文件将优先于触发其导入的文件。
可以在单个spring.config.import
钥匙。
位置将按照定义的顺序进行处理,以后导入优先。
在适当的情况下,还会考虑导入特定于配置文件的变体。
上面的示例将导入my.properties 以及任何my-<profile>.properties 变种。 |
Spring Boot 包括可插拔的 API,允许支持各种不同的位置地址。 默认情况下,您可以导入 Java 属性、YAML 和配置树。 第三方 jar 可以提供对其他技术的支持(不需要文件是本地的)。 例如,您可以想象配置数据来自外部存储,例如 Consul、Apache ZooKeeper 或 Netflix Archaius。 如果您想支持自己的位置,请参阅 |
导入无扩展名文件
某些云平台无法向卷挂载文件添加文件扩展名。 要导入这些无扩展名文件,您需要给 Spring Boot 一个提示,以便它知道如何加载它们。 您可以通过将扩展提示放在方括号中来做到这一点。
例如,假设您有一个/etc/config/myconfig
您希望作为 yaml 导入的文件。
您可以从application.properties
使用以下内容:
-
Properties
-
YAML
spring.config.import=file:/etc/config/myconfig[.yaml]
spring:
config:
import: "file:/etc/config/myconfig[.yaml]"
使用配置树
在云平台(如 Kubernetes)上运行应用程序时,通常需要读取平台提供的配置值。 出于此类目的使用环境变量并不少见,但这可能有缺点,特别是如果该值应该保密。
作为环境变量的替代方法,许多云平台现在允许您将配置映射到已挂载的数据卷中。
例如,Kubernetes 可以同时卷挂载ConfigMaps
和Secrets
.
可以使用两种常见的卷挂载模式:
-
单个文件包含一组完整的属性(通常写为 YAML)。
-
多个文件被写入目录树,文件名成为“键”,内容成为“值”。
对于第一种情况,您可以使用spring.config.import
如上所述。
对于第二种情况,您需要使用configtree:
前缀,以便 Spring Boot 知道它需要将所有文件公开为属性。
例如,假设 Kubernetes 已挂载以下卷:
etc/
config/
myapp/
username
password
的内容username
file 将是一个配置值,而password
将是一个秘密。
要导入这些属性,您可以将以下内容添加到application.properties
或application.yaml
文件:
-
Properties
-
YAML
spring.config.import=optional:configtree:/etc/config/
spring:
config:
import: "optional:configtree:/etc/config/"
然后,您可以访问或注入myapp.username
和myapp.password
属性Environment
以通常的方式。
配置树下的文件夹和文件的名称构成属性名称。在上面的示例中,要访问属性username 和password ,您可以设置spring.config.import 自optional:configtree:/etc/config/myapp . |
带有点表示法的文件名也会被正确映射。例如,在上面的示例中,名为myapp.username 在/etc/config 将导致myapp.username 属性中的Environment . |
配置树值可以绑定到两个字符串String 和byte[] 类型取决于预期的内容。 |
如果要从同一父文件夹导入多个配置树,则可以使用通配符快捷方式。
任何configtree:
location 结尾为 将所有直接子项导入为配置树。
与非通配符导入一样,每个配置树下的文件夹和文件的名称构成属性名称。/*/
例如,给定以下卷:
etc/
config/
dbconfig/
db/
username
password
mqconfig/
mq/
username
password
您可以使用configtree:/etc/config/*/
作为导入位置:
-
Properties
-
YAML
spring.config.import=optional:configtree:/etc/config/*/
spring:
config:
import: "optional:configtree:/etc/config/*/"
这将添加db.username
,db.password
,mq.username
和mq.password
性能。
使用通配符加载的目录按字母顺序排序。 如果您需要不同的订单,则应将每个位置列为单独的导入 |
配置树也可用于 Docker 密钥。
当 Docker swarm 服务被授予对机密的访问权限时,该机密将装载到容器中。
例如,如果名为db.password
安装在位置/run/secrets/
,您可以制作db.password
使用以下命令提供给 Spring 环境:
-
Properties
-
YAML
spring.config.import=optional:configtree:/run/secrets/
spring:
config:
import: "optional:configtree:/run/secrets/"
属性占位符
中的值application.properties
和application.yaml
通过现有的Environment
使用它们时,您可以返回以前定义的值(例如,从系统属性或环境变量)。
标准${name}
属性占位符语法可以在值内的任何位置使用。
属性占位符还可以使用:
将默认值与属性名称分开,例如${name:default}
.
以下示例显示了带默认值和不带默认值的占位符的使用:
-
Properties
-
YAML
app.name=MyApp
app.description=${app.name} is a Spring Boot application written by ${username:Unknown}
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
.
您应该始终使用占位符中的规范形式(仅使用小写字母的烤肉串大小写)来引用占位符中的属性名称。
这将允许 Spring Boot 使用与松绑定时相同的逻辑 例如 |
您还可以使用此技术创建现有 Spring Boot 属性的“短”变体。 有关详细信息,请参阅“作指南”中的“使用”短“命令行参数部分。 |
使用多文档文件
Spring Boot 允许您将单个物理文件拆分为多个逻辑文档,每个文档都是独立添加的。 文档按从上到下的顺序处理。 较后的文档可以覆盖较早的文档中定义的属性。
为application.yaml
文件中,使用标准的 YAML 多文档语法。
三个连续的连字符表示一个文档的结束,以及下一个文档的开始。
例如,以下文件有两个逻辑文档:
spring:
application:
name: "MyApp"
---
spring:
application:
name: "MyCloudApp"
config:
activate:
on-cloud-platform: "kubernetes"
为application.properties
提交特殊或#---
!---
comment 用于标记文档拆分:
spring.application.name=MyApp
#---
spring.application.name=MyCloudApp
spring.config.activate.on-cloud-platform=kubernetes
属性文件分隔符不得有任何前导空格,并且必须恰好具有三个连字符。 分隔符前后的行不得是相同的注释前缀。 |
多文档属性文件通常与激活属性(例如spring.config.activate.on-profile .
有关详细信息,请参阅下一节。 |
激活属性
有时,仅在满足某些条件时激活一组给定的属性很有用。 例如,您可能具有仅在特定配置文件处于活动状态时才相关的属性。
您可以使用spring.config.activate.*
.
以下激活属性可用:
属性 | 注意 |
---|---|
|
必须匹配才能使文档处于活动状态的配置文件表达式,或必须至少匹配一个配置文件表达式的列表才能使文档处于活动状态。 |
|
这 |
例如,以下内容指定第二个文档仅在 Kubernetes 上运行时处于活动状态,并且仅当“prod”或“staging”配置文件处于活动状态时才处于活动状态:
-
Properties
-
YAML
myprop=always-set
#---
spring.config.activate.on-cloud-platform=kubernetes
spring.config.activate.on-profile=prod | staging
myotherprop=sometimes-set
myprop:
"always-set"
---
spring:
config:
activate:
on-cloud-platform: "kubernetes"
on-profile: "prod | staging"
myotherprop: "sometimes-set"
加密属性
Spring Boot 不提供任何对加密属性值的内置支持,但是,它确实提供了修改 Spring 中包含的值所需的钩子点Environment
.
这EnvironmentPostProcessor
接口允许您作Environment
在应用程序启动之前。有关详细信息,请参阅在启动之前自定义环境或 ApplicationContext。
如果您需要一种安全的方式来存储凭据和密码,Spring Cloud Vault 项目支持在 HashiCorp Vault 中存储外部化配置。
使用 YAML
YAML 是 JSON 的超集,因此是指定分层配置数据的便捷格式。 这SpringApplication
每当你的类路径上有 SnakeYAML 库时,class 就会自动支持 YAML 作为属性的替代方案。
如果您使用Starters,则 SnakeYAML 由spring-boot-starter . |
将 YAML 映射到属性
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
无法使用@PropertySource 或@TestPropertySource 附注。
因此,如果您需要以这种方式加载值,则需要使用属性文件。 |
直接加载 YAML
Spring Framework 提供了两个方便的类,可用于加载 YAML 文档。
这YamlPropertiesFactoryBean
将 YAML 加载为Properties
和YamlMapFactoryBean
将 YAML 加载为Map
.
您还可以使用YamlPropertySourceLoader
类,如果要将 YAML 加载为 SpringPropertySource
.
配置随机值
这RandomValuePropertySource
对于注入随机值(例如,注入机密或测试用例)很有用。
它可以生成整数、long、uuid 或字符串,如以下示例所示:
-
Properties
-
YAML
my.secret=${random.value}
my.number=${random.int}
my.bignumber=${random.long}
my.uuid=${random.uuid}
my.number-less-than-ten=${random.int(10)}
my.number-in-range=${random.int[1024,65536]}
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
是最大值(不包括)。
配置系统环境属性
Spring Boot 支持为环境属性设置前缀。
如果系统环境由具有不同配置要求的多个 Spring Boot 应用程序共享,这将很有用。
系统环境属性的前缀可以直接在SpringApplication
通过调用setEnvironmentPrefix(…)
方法。
例如,如果将前缀设置为input
,属性,例如remote.timeout
将解析为INPUT_REMOTE_TIMEOUT
在系统环境中。
前缀仅适用于系统环境属性。
上面的示例将继续使用remote.timeout 从其他来源读取属性时。 |
类型安全配置属性
使用@Value("${property}")
注入配置属性的注释有时可能很麻烦,尤其是在您使用多个属性或数据本质上是分层的时。
Spring Boot 提供了一种使用属性的替代方法,允许强类型 Bean 管理和验证应用程序的配置。
JavaBean 属性绑定
可以绑定声明标准 JavaBean 属性的 bean,如以下示例所示:
-
Java
-
Kotlin
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("my.service")
public class MyProperties {
private boolean enabled;
private InetAddress remoteAddress;
private final Security security = new Security();
// getters / setters...
public boolean isEnabled() {
return this.enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public InetAddress getRemoteAddress() {
return this.remoteAddress;
}
public void setRemoteAddress(InetAddress remoteAddress) {
this.remoteAddress = remoteAddress;
}
public Security getSecurity() {
return this.security;
}
public static class Security {
private String username;
private String password;
private List<String> roles = new ArrayList<>(Collections.singleton("USER"));
// getters / setters...
public String getUsername() {
return this.username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
public List<String> getRoles() {
return this.roles;
}
public void setRoles(List<String> roles) {
this.roles = roles;
}
}
}
import org.springframework.boot.context.properties.ConfigurationProperties
import java.net.InetAddress
@ConfigurationProperties("my.service")
class MyProperties {
var isEnabled = false
var remoteAddress: InetAddress? = null
val security = Security()
class Security {
var username: String? = null
var password: String? = null
var roles: List<String> = ArrayList(setOf("USER"))
}
}
前面的 POJO 定义了以下属性:
-
my.service.enabled
,值为false
默认情况下。 -
my.service.remote-address
,具有可以强制的类型String
. -
my.service.security.username
,具有嵌套的“安全”对象,其名称由属性名称决定。 特别是,该类型在那里根本没有使用,而且可能是SecurityProperties
. -
my.service.security.password
. -
my.service.security.roles
,并收集String
默认为USER
.
在属性名称中使用保留关键字,例如my.service.import ,使用@Name 属性字段上的注释。 |
映射到@ConfigurationProperties Spring Boot 中可用的类是公共 API,但类本身的访问器(getter/setter)并不意味着直接使用。 |
这种排列依赖于默认的空构造函数,并且 getter 和 setter 通常是强制性的,因为绑定是通过标准 Java Beans 属性描述符进行的,就像在 Spring MVC 中一样。 在以下情况下,可以省略 setter:
有些人使用 Project Lombok 自动添加 getter 和 setter。 确保 Lombok 不会为此类类型生成任何特定的构造函数,因为它会被容器自动用于实例化对象。 最后,仅考虑标准的 Java Bean 属性,不支持绑定静态属性。 |
构造函数绑定
上一节中的示例可以以不可变的方式重写,如以下示例所示:
-
Java
-
Kotlin
import java.net.InetAddress;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.bind.DefaultValue;
@ConfigurationProperties("my.service")
public class MyProperties {
// fields...
private final boolean enabled;
private final InetAddress remoteAddress;
private final Security security;
public MyProperties(boolean enabled, InetAddress remoteAddress, Security security) {
this.enabled = enabled;
this.remoteAddress = remoteAddress;
this.security = security;
}
// getters...
public boolean isEnabled() {
return this.enabled;
}
public InetAddress getRemoteAddress() {
return this.remoteAddress;
}
public Security getSecurity() {
return this.security;
}
public static class Security {
// fields...
private final String username;
private final String password;
private final List<String> roles;
public Security(String username, String password, @DefaultValue("USER") List<String> roles) {
this.username = username;
this.password = password;
this.roles = roles;
}
// getters...
public String getUsername() {
return this.username;
}
public String getPassword() {
return this.password;
}
public List<String> getRoles() {
return this.roles;
}
}
}
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.context.properties.bind.DefaultValue
import java.net.InetAddress
@ConfigurationProperties("my.service")
class MyProperties(val enabled: Boolean, val remoteAddress: InetAddress,
val security: Security) {
class Security(val username: String, val password: String,
@param:DefaultValue("USER") val roles: List<String>)
}
在此设置中,单个参数化构造函数的存在意味着应使用构造函数绑定。这意味着绑定器将找到一个构造函数,其中包含您希望绑定的参数。如果您的类有多个构造函数,则@ConstructorBinding
注释可用于指定要用于构造函数绑定的构造函数。
要选择退出类的构造函数绑定,必须使用@Autowired
或制作private
. Kotlin 开发人员可以使用空的主构造函数来选择退出构造函数绑定。
例如:
-
Java
-
Kotlin
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("my")
public class MyProperties {
// fields...
final MyBean myBean;
private String name;
@Autowired
public MyProperties(MyBean myBean) {
this.myBean = myBean;
}
// getters / setters...
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
import org.springframework.boot.context.properties.ConfigurationProperties
@ConfigurationProperties("my")
class MyProperties() {
constructor(name: String) : this() {
this.name = name
}
// vars...
var name: String? = null
}
构造函数绑定可以与记录一起使用。
除非您的记录有多个构造函数,否则无需使用@ConstructorBinding
.
构造函数绑定类的嵌套成员(例如Security
在上面的示例中)也将通过其构造函数进行绑定。
可以使用以下命令指定默认值@DefaultValue
在构造函数参数和记录组件上。
转换服务将应用于强制注释的String
value 设置为缺失属性的目标类型。
参考前面的例子,如果没有属性绑定到Security
这MyProperties
实例将包含一个null
值security
.
要使其包含Security
即使没有属性绑定到它(使用 Kotlin 时,这也需要username
和password
参数Security
声明为可为 null,因为它们没有默认值),请使用空的@DefaultValue
注解:
-
Java
-
Kotlin
public MyProperties(boolean enabled, InetAddress remoteAddress, @DefaultValue Security security) {
this.enabled = enabled;
this.remoteAddress = remoteAddress;
this.security = security;
}
class MyProperties(val enabled: Boolean, val remoteAddress: InetAddress,
@DefaultValue val security: Security) {
class Security(val username: String?, val password: String?,
@param:DefaultValue("USER") val roles: List<String>)
}
要使用构造函数绑定,必须使用@EnableConfigurationProperties 或配置属性扫描。您不能将构造函数绑定与由常规 Spring 机制创建的 bean(例如@Component beans,使用@Bean 方法或使用@Import )
|
要使用构造函数绑定,必须使用-parameters . 如果您使用 Spring Boot 的 Gradle 插件或使用 Maven 和spring-boot-starter-parent . |
使用Optional 跟@ConfigurationProperties 不推荐,因为它主要用作返回类型。因此,它不太适合配置属性注入。为了与其他类型的属性保持一致,如果您确实声明了Optional 属性,它没有价值,null 而不是空的Optional 将被绑定。 |
在属性名称中使用保留关键字,例如my.service.import ,使用@Name 构造函数参数上的注释。 |
启用@ConfigurationProperties注释类型
Spring Boot 提供了绑定的基础设施@ConfigurationProperties
类型并将它们注册为 bean。您可以逐类启用配置属性,也可以启用配置属性扫描,其工作方式与组件扫描类似。
有时,用@ConfigurationProperties
可能不适合扫描,例如,如果您正在开发自己的自动配置或想要有条件地启用它们。在这些情况下,请使用@EnableConfigurationProperties
注解。
这可以在任何@Configuration
类,如以下示例所示:
-
Java
-
Kotlin
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(SomeProperties.class)
public class MyConfiguration {
}
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Configuration
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(SomeProperties::class)
class MyConfiguration
-
Java
-
Kotlin
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("some.properties")
public class SomeProperties {
}
import org.springframework.boot.context.properties.ConfigurationProperties
@ConfigurationProperties("some.properties")
class SomeProperties
要使用配置属性扫描,请将@ConfigurationPropertiesScan
注释到您的应用程序。
通常,它被添加到标注为@SpringBootApplication
但它可以添加到任何@Configuration
类。
默认情况下,将从声明注释的类的包进行扫描。
如果要定义要扫描的特定包,可以按照以下示例所示进行作:
-
Java
-
Kotlin
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
@SpringBootApplication
@ConfigurationPropertiesScan({ "com.example.app", "com.example.another" })
public class MyApplication {
}
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.context.properties.ConfigurationPropertiesScan
@SpringBootApplication
@ConfigurationPropertiesScan("com.example.app", "com.example.another")
class MyApplication
当 假设它在 |
我们建议@ConfigurationProperties
只处理环境,特别是不从上下文中注入其他 bean。
对于极端情况,可以使用setter注入或任何*Aware
框架提供的接口(例如EnvironmentAware
如果您需要访问Environment
).
如果您仍然想使用构造函数注入其他 bean,则必须使用@Component
并使用基于 JavaBean 的属性绑定。
使用@ConfigurationProperties注释类型
这种配置风格特别适用于SpringApplication
外部 YAML 配置,如以下示例所示:
my:
service:
remote-address: 192.168.1.1
security:
username: "admin"
roles:
- "USER"
- "ADMIN"
与@ConfigurationProperties
bean,您可以像任何其他 bean 一样注入它们,如以下示例所示:
-
Java
-
Kotlin
import org.springframework.stereotype.Service;
@Service
public class MyService {
private final MyProperties properties;
public MyService(MyProperties properties) {
this.properties = properties;
}
public void openConnection() {
Server server = new Server(this.properties.getRemoteAddress());
server.start();
// ...
}
// ...
}
import org.springframework.stereotype.Service
@Service
class MyService(val properties: MyProperties) {
fun openConnection() {
val server = Server(properties.remoteAddress)
server.start()
// ...
}
// ...
}
用@ConfigurationProperties 还允许您生成元数据文件,IDE 可以使用这些文件为您自己的键提供自动完成功能。
有关详细信息,请参阅附录。 |
第三方配置
以及使用@ConfigurationProperties
要注释类,您也可以在公共上使用它@Bean
方法。
当您想要将属性绑定到您无法控制的第三方组件时,这样做可能特别有用。
要从Environment
属性, 添加@ConfigurationProperties
到其 bean 注册,如以下示例所示:
-
Java
-
Kotlin
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
public class ThirdPartyConfiguration {
@Bean
@ConfigurationProperties(prefix = "another")
public AnotherComponent anotherComponent() {
return new AnotherComponent();
}
}
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
@Configuration(proxyBeanMethods = false)
class ThirdPartyConfiguration {
@Bean
@ConfigurationProperties(prefix = "another")
fun anotherComponent(): AnotherComponent = AnotherComponent()
}
使用another
前缀映射到该AnotherComponent
bean 的方式与前面类似SomeProperties
例。
松绑
Spring Boot 使用一些宽松的绑定规则Environment
属性设置为@ConfigurationProperties
bean,因此不需要Environment
属性名称和 bean 属性名称。这有用的常见示例包括破折号分隔的环境属性(例如,context-path
绑定到contextPath
)和大写的环境属性(例如PORT
绑定到port
).
例如,请考虑以下内容@ConfigurationProperties
类:
-
Java
-
Kotlin
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "my.main-project.person")
public class MyPersonProperties {
private String firstName;
public String getFirstName() {
return this.firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
}
import org.springframework.boot.context.properties.ConfigurationProperties
@ConfigurationProperties(prefix = "my.main-project.person")
class MyPersonProperties {
var firstName: String? = null
}
使用上述代码,可以使用以下属性名称:
属性 | 注意 |
---|---|
|
烤肉盒,推荐用于 |
|
标准驼峰命名法语法。 |
|
下划线表示法,这是用于 |
|
大写格式,使用系统环境变量时建议使用。 |
这prefix 注释的值必须采用 kebab 大小写(小写并以 分隔,例如- my.main-project.person ). |
属性来源 | 简单 | 列表 |
---|---|---|
属性文件 |
驼峰式大小写、烤肉串大小写或下划线表示法 |
使用或逗号分隔值的标准列表语法 |
YAML 文件 |
驼峰式大小写、烤肉串大小写或下划线表示法 |
标准 YAML 列表语法或逗号分隔值 |
环境变量 |
大写格式,下划线作为分隔符(请参阅从环境变量绑定)。 |
用下划线括起来的数值(请参阅从环境变量绑定) |
系统属性 |
驼峰式大小写、烤肉串大小写或下划线表示法 |
使用或逗号分隔值的标准列表语法 |
我们建议,如果可能,将属性存储为小写烤肉串格式,例如my.person.first-name=Rod . |
绑定贴图
绑定到Map
属性,您可能需要使用特殊的括号表示法,以便原始的key
价值被保留。
如果键不被 、任何非字母数字字符包围,或[]
-
.
被删除。
例如,考虑将以下属性绑定到Map<String,String>
:
-
Properties
-
YAML
my.map[/key1]=value1
my.map[/key2]=value2
my.map./key3=value3
my:
map:
"[/key1]": "value1"
"[/key2]": "value2"
"/key3": "value3"
对于 YAML 文件,需要用引号括起来才能正确解析键。 |
上述属性将绑定到Map
跟/key1
,/key2
和key3
作为地图中的按键。
斜杠已从key3
因为它没有被方括号包围。
绑定到标量值时,键.
在它们中不需要被 包围。
标量值包括枚举和[]
java.lang
包,除了Object
.
捆绑a.b=c
自Map<String, String>
将保留.
并返回带有条目的 Map{"a.b"="c"}
.
对于任何其他类型,如果您key
包含一个.
.
例如,绑定a.b=c
自Map<String, Object>
将返回一个带有条目的地图{"a"={"b"="c"}}
而[a.b]=c
将返回一个带有条目的地图{"a.b"="c"}
.
从环境变量绑定
大多数作系统对可用于环境变量的名称施加了严格的规则。例如,Linux shell 变量只能包含字母 (a
自z
或A
自Z
)、数字 (0
自9
) 或下划线字符 ()。按照惯例,Unix shell 变量的名称也将以大写形式命名。_
Spring Boot 的宽松绑定规则尽可能地设计为与这些命名限制兼容。
要将规范表单中的属性名称转换为环境变量名称,您可以遵循以下规则:
-
替换点 (
.
) 带有下划线 ()。_
-
删除所有破折号 ()。
-
-
转换为大写。
例如,配置属性spring.main.log-startup-info
将是一个名为SPRING_MAIN_LOGSTARTUPINFO
.
绑定到对象列表时也可以使用环境变量。要绑定到List
,则变量名称中的元素编号应用下划线括起来。
例如,配置属性my.service[0].other
将使用名为MY_SERVICE_0_OTHER
.
对环境变量绑定的支持应用于systemEnvironment
属性源,以及名称以-systemEnvironment
.
从环境变量绑定映射
当 Spring Boot 将环境变量绑定到属性类时,它会在绑定之前将环境变量名称小写。大多数时候,这个细节并不重要,除非绑定到Map
性能。
中的键Map
始终为小写,如以下示例所示:
-
Java
-
Kotlin
import java.util.HashMap;
import java.util.Map;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "my.props")
public class MyMapsProperties {
private final Map<String, String> values = new HashMap<>();
public Map<String, String> getValues() {
return this.values;
}
}
import org.springframework.boot.context.properties.ConfigurationProperties
@ConfigurationProperties(prefix = "my.props")
class MyMapsProperties {
val values: Map<String, String> = HashMap()
}
设置MY_PROPS_VALUES_KEY=value
这values
Map
包含一个{"key"="value"}
进入。
只有环境变量名称是小写的,而不是值。
设置MY_PROPS_VALUES_KEY=VALUE
这values
Map
包含一个{"key"="VALUE"}
进入。
缓存
宽松绑定使用缓存来提高性能。默认情况下,此缓存仅应用于不可变属性源。
若要自定义此行为,例如,若要为可变属性源启用缓存,请使用ConfigurationPropertyCaching
.
合并复杂类型
当列表配置在多个位置时,覆盖的工作原理是替换整个列表。
例如,假设MyPojo
对象替换为name
和description
属性null
默认情况下。
以下示例公开了MyPojo
对象来自MyProperties
:
-
Java
-
Kotlin
import java.util.ArrayList;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("my")
public class MyProperties {
private final List<MyPojo> list = new ArrayList<>();
public List<MyPojo> getList() {
return this.list;
}
}
import org.springframework.boot.context.properties.ConfigurationProperties
@ConfigurationProperties("my")
class MyProperties {
val list: List<MyPojo> = ArrayList()
}
请考虑以下配置:
-
Properties
-
YAML
my.list[0].name=my name
my.list[0].description=my description
#---
spring.config.activate.on-profile=dev
my.list[0].name=my another name
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
仍然只包含一个条目(名称为my another name
以及null
).
此配置不会添加第二个MyPojo
实例添加到列表中,并且它不会合并项目。
当List
在多个配置文件中指定,则使用优先级最高的配置文件(并且仅使用该配置文件)。
请考虑以下示例:
-
Properties
-
YAML
my.list[0].name=my name
my.list[0].description=my description
my.list[1].name=another name
my.list[1].description=another description
#---
spring.config.activate.on-profile=dev
my.list[0].name=my another name
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
包含一个 MyPojo
条目(名称为my another name
以及null
).
对于 YAML,逗号分隔的列表和 YAML 列表都可用于完全覆盖列表的内容。
为Map
属性,您可以与从多个源提取的属性值绑定。
但是,对于多个源中的同一属性,将使用优先级最高的属性。
以下示例公开了Map<String, MyPojo>
从MyProperties
:
-
Java
-
Kotlin
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("my")
public class MyProperties {
private final Map<String, MyPojo> map = new LinkedHashMap<>();
public Map<String, MyPojo> getMap() {
return this.map;
}
}
import org.springframework.boot.context.properties.ConfigurationProperties
@ConfigurationProperties("my")
class MyProperties {
val map: Map<String, MyPojo> = LinkedHashMap()
}
请考虑以下配置:
-
Properties
-
YAML
my.map.key1.name=my name 1
my.map.key1.description=my description 1
#---
spring.config.activate.on-profile=dev
my.map.key1.name=dev name 1
my.map.key2.name=dev name 2
my.map.key2.description=dev description 2
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
).
上述合并规则适用于所有属性源中的属性,而不仅仅是文件。 |
属性转换
Spring Boot 在绑定到@ConfigurationProperties
豆。
如果您需要自定义类型转换,您可以提供ConversionService
bean(一个名为conversionService
)或自定义属性编辑器(通过CustomEditorConfigurer
bean)或自定义转换器(bean 定义注释为@ConfigurationPropertiesBinding
).
用于属性转换的 Bean 在应用程序生命周期的早期就被请求,因此请确保限制您的依赖项 |
您可能想要重命名您的自定义ConversionService 如果配置密钥强制不需要它,并且仅依赖于符合@ConfigurationPropertiesBinding .
当对@Bean 方法@ConfigurationPropertiesBinding ,方法应该是static 以避免“Bean 不符合所有 BeanPostProcessors 处理的条件”警告。 |
转换持续时间
Spring Boot 专门支持表达持续时间。
如果将Duration
属性,则应用程序属性中的以下格式可用:
-
一个常客
long
表示(使用毫秒作为默认单位,除非@DurationUnit
已指定) -
一种更易读的格式,其中值和单位耦合 (
10s
表示 10 秒)
请考虑以下示例:
-
Java
-
Kotlin
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.convert.DurationUnit;
@ConfigurationProperties("my")
public class MyProperties {
@DurationUnit(ChronoUnit.SECONDS)
private Duration sessionTimeout = Duration.ofSeconds(30);
private Duration readTimeout = Duration.ofMillis(1000);
// getters / setters...
public Duration getSessionTimeout() {
return this.sessionTimeout;
}
public void setSessionTimeout(Duration sessionTimeout) {
this.sessionTimeout = sessionTimeout;
}
public Duration getReadTimeout() {
return this.readTimeout;
}
public void setReadTimeout(Duration readTimeout) {
this.readTimeout = readTimeout;
}
}
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.convert.DurationUnit
import java.time.Duration
import java.time.temporal.ChronoUnit
@ConfigurationProperties("my")
class MyProperties {
@DurationUnit(ChronoUnit.SECONDS)
var sessionTimeout = Duration.ofSeconds(30)
var readTimeout = Duration.ofMillis(1000)
}
要将会话超时指定为 30 秒,30
,PT30S
和30s
都是等价的。
500毫秒的读取超时可以用以下任何一种形式指定:500
,PT0.5S
和500ms
.
您还可以使用任何受支持的单元。 这些都是:
-
ns
纳秒级 -
us
微秒 -
ms
毫秒 -
s
几秒钟 -
m
几分钟 -
h
数小时 -
d
几天
默认单位为毫秒,可以使用@DurationUnit
如上面的示例所示。
如果更喜欢使用构造函数绑定,则可以公开相同的属性,如以下示例所示:
-
Java
-
Kotlin
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.bind.DefaultValue;
import org.springframework.boot.convert.DurationUnit;
@ConfigurationProperties("my")
public class MyProperties {
// fields...
private final Duration sessionTimeout;
private final Duration readTimeout;
public MyProperties(@DurationUnit(ChronoUnit.SECONDS) @DefaultValue("30s") Duration sessionTimeout,
@DefaultValue("1000ms") Duration readTimeout) {
this.sessionTimeout = sessionTimeout;
this.readTimeout = readTimeout;
}
// getters...
public Duration getSessionTimeout() {
return this.sessionTimeout;
}
public Duration getReadTimeout() {
return this.readTimeout;
}
}
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.context.properties.bind.DefaultValue
import org.springframework.boot.convert.DurationUnit
import java.time.Duration
import java.time.temporal.ChronoUnit
@ConfigurationProperties("my")
class MyProperties(@param:DurationUnit(ChronoUnit.SECONDS) @param:DefaultValue("30s") val sessionTimeout: Duration,
@param:DefaultValue("1000ms") val readTimeout: Duration)
如果您要升级Long 属性,请确保定义单位(使用@DurationUnit ),如果不是毫秒。
这样做可以提供透明的升级路径,同时支持更丰富的格式。 |
转换期间
除了持续时间之外,Spring Boot 还可以使用Period
类型。
应用程序属性中可以使用以下格式:
-
一个常规的
int
表示(使用天数作为默认单位,除非@PeriodUnit
已指定) -
一种更简单的格式,其中值和单位对耦合(
1y3d
表示 1 年零 3 天)
简单格式支持以下单位:
-
y
多年来 -
m
几个月 -
w
数周 -
d
几天
这Period type 实际上从未存储周数,它是一个快捷方式,意思是“7 天”。 |
转换数据大小
-
一个常客
long
表示(使用字节作为默认单位,除非@DataSizeUnit
已指定) -
一种更易读的格式,其中值和单位耦合 (
10MB
表示 10 兆字节)
请考虑以下示例:
-
Java
-
Kotlin
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.convert.DataSizeUnit;
import org.springframework.util.unit.DataSize;
import org.springframework.util.unit.DataUnit;
@ConfigurationProperties("my")
public class MyProperties {
@DataSizeUnit(DataUnit.MEGABYTES)
private DataSize bufferSize = DataSize.ofMegabytes(2);
private DataSize sizeThreshold = DataSize.ofBytes(512);
// getters/setters...
public DataSize getBufferSize() {
return this.bufferSize;
}
public void setBufferSize(DataSize bufferSize) {
this.bufferSize = bufferSize;
}
public DataSize getSizeThreshold() {
return this.sizeThreshold;
}
public void setSizeThreshold(DataSize sizeThreshold) {
this.sizeThreshold = sizeThreshold;
}
}
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.convert.DataSizeUnit
import org.springframework.util.unit.DataSize
import org.springframework.util.unit.DataUnit
@ConfigurationProperties("my")
class MyProperties {
@DataSizeUnit(DataUnit.MEGABYTES)
var bufferSize = DataSize.ofMegabytes(2)
var sizeThreshold = DataSize.ofBytes(512)
}
要指定 10 兆字节的缓冲区大小,10
和10MB
是等效的。256 字节的大小阈值可以指定为256
或256B
.
您还可以使用任何受支持的单元。 这些都是:
-
B
对于字节 -
KB
对于千字节 -
MB
对于兆字节 -
GB
千兆字节 -
TB
对于 TB
默认单位是字节,可以使用@DataSizeUnit
如上面的示例所示。
如果更喜欢使用构造函数绑定,则可以公开相同的属性,如以下示例所示:
-
Java
-
Kotlin
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.bind.DefaultValue;
import org.springframework.boot.convert.DataSizeUnit;
import org.springframework.util.unit.DataSize;
import org.springframework.util.unit.DataUnit;
@ConfigurationProperties("my")
public class MyProperties {
// fields...
private final DataSize bufferSize;
private final DataSize sizeThreshold;
public MyProperties(@DataSizeUnit(DataUnit.MEGABYTES) @DefaultValue("2MB") DataSize bufferSize,
@DefaultValue("512B") DataSize sizeThreshold) {
this.bufferSize = bufferSize;
this.sizeThreshold = sizeThreshold;
}
// getters...
public DataSize getBufferSize() {
return this.bufferSize;
}
public DataSize getSizeThreshold() {
return this.sizeThreshold;
}
}
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.context.properties.bind.DefaultValue
import org.springframework.boot.convert.DataSizeUnit
import org.springframework.util.unit.DataSize
import org.springframework.util.unit.DataUnit
@ConfigurationProperties("my")
class MyProperties(@param:DataSizeUnit(DataUnit.MEGABYTES) @param:DefaultValue("2MB") val bufferSize: DataSize,
@param:DefaultValue("512B") val sizeThreshold: DataSize)
如果您要升级Long 属性,请确保定义单位(使用@DataSizeUnit ),如果不是字节。
这样做可以提供透明的升级路径,同时支持更丰富的格式。 |
@ConfigurationProperties验证
Spring Boot 尝试验证@ConfigurationProperties
类,每当它们使用 Spring 的@Validated
注解。
您可以使用 JSR-303jakarta.validation
约束注释。
为此,请确保您的类路径上有一个合规的 JSR-303 实现,然后向字段添加约束注释,如以下示例所示:
-
Java
-
Kotlin
import java.net.InetAddress;
import jakarta.validation.constraints.NotNull;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;
@ConfigurationProperties("my.service")
@Validated
public class MyProperties {
@NotNull
private InetAddress remoteAddress;
// getters/setters...
public InetAddress getRemoteAddress() {
return this.remoteAddress;
}
public void setRemoteAddress(InetAddress remoteAddress) {
this.remoteAddress = remoteAddress;
}
}
import jakarta.validation.constraints.NotNull
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.validation.annotation.Validated
import java.net.InetAddress
@ConfigurationProperties("my.service")
@Validated
class MyProperties {
var remoteAddress: @NotNull InetAddress? = null
}
您还可以通过注释@Bean 使用@Validated . |
要将验证级联到嵌套属性,必须使用@Valid
.
以下示例基于前面的内容构建MyProperties
例:
-
Java
-
Kotlin
import java.net.InetAddress;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;
@ConfigurationProperties("my.service")
@Validated
public class MyProperties {
@NotNull
private InetAddress remoteAddress;
@Valid
private final Security security = new Security();
// getters/setters...
public InetAddress getRemoteAddress() {
return this.remoteAddress;
}
public void setRemoteAddress(InetAddress remoteAddress) {
this.remoteAddress = remoteAddress;
}
public Security getSecurity() {
return this.security;
}
public static class Security {
@NotEmpty
private String username;
// getters/setters...
public String getUsername() {
return this.username;
}
public void setUsername(String username) {
this.username = username;
}
}
}
import jakarta.validation.Valid
import jakarta.validation.constraints.NotEmpty
import jakarta.validation.constraints.NotNull
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.validation.annotation.Validated
import java.net.InetAddress
@ConfigurationProperties("my.service")
@Validated
class MyProperties {
var remoteAddress: @NotNull InetAddress? = null
@Valid
val security = Security()
class Security {
@NotEmpty
var username: String? = null
}
}
您还可以添加自定义 SpringValidator
通过创建一个名为configurationPropertiesValidator
.
这@Bean
方法应声明static
.
配置属性验证器是在应用程序生命周期的早期创建的,并声明@Bean
方法作为 static 可以创建 bean,而无需实例化@Configuration
类。
这样做可以避免早期实例化可能导致的任何问题。
这spring-boot-actuator 模块包含一个端点,该端点将所有@ConfigurationProperties 豆。
将 Web 浏览器指向/actuator/configprops 或使用等效的 JMX 端点。
有关详细信息,请参阅生产就绪功能部分。 |
@ConfigurationProperties与@Value
这@Value
注释是核心容器功能,它不提供与类型安全配置属性相同的功能。
下表汇总了@ConfigurationProperties
和@Value
:
特征 | @ConfigurationProperties |
@Value |
---|---|---|
是的 |
有限(见下面的注释) |
|
是的 |
不 |
|
|
不 |
是的 |
如果您确实想使用 例如 |
如果您为自己的组件定义了一组配置键,我们建议您将它们分组到一个 POJO 中,并用@ConfigurationProperties
.
这样做将为您提供结构化的、类型安全的对象,您可以将其注入到您自己的 bean 中。