目录
阅读本文更有助于你使用springboot的特性
2. 外化配置
Spring Boot 允许您将配置外部化,以便您可以在不同环境中使用相同的应用程序代码。您可以使用各种外部配置源,包括 Java 属性文件、YAML 文件、环境变量和命令行参数。
属性值可以通过直接注射到你的bean@Value
注释,通过Spring的访问Environment
抽象,或者被绑定到结构化对象通过@ConfigurationProperties
。
Spring Boot 使用一个非常特殊的PropertySource
顺序,旨在允许合理地覆盖值。属性按以下顺序考虑(来自较低项目的值覆盖较早的项目):
-
默认属性(由设置指定
SpringApplication.setDefaultProperties
)。 -
@PropertySource你的
@Configuration
类的注释。请注意,Environment
在刷新应用程序上下文之前,不会将此类属性源添加到。现在配置某些属性(例如在刷新开始之前读取的logging.*
和)为时已晚spring.main.*
。 -
配置数据(如
application.properties
文件)。 -
一
RandomValuePropertySource
,只有在拥有性能random.*
。 -
操作系统环境变量。
-
Java 系统属性 (
System.getProperties()
)。 -
JNDI 属性来自
java:comp/env
. -
ServletContext
初始化参数。 -
ServletConfig
初始化参数。 -
来自
SPRING_APPLICATION_JSON
(嵌入在环境变量或系统属性中的内联 JSON)的属性。 -
命令行参数。
-
properties
属性在您的测试中。可用于测试应用程序的特定部分@SpringBootTest的测试注释。 -
@TestPropertySource 测试中的注释。
-
$HOME/.config/spring-boot
当 devtools 处于活动状态时,目录中的Devtools 全局设置属性。
配置数据文件按以下顺序考虑:
-
打包在 jar 中的应用程序属性(
application.properties
和 YAML 变体)。 -
打包在 jar 中的特定于配置文件的应用程序属性(
application-{profile}.properties
和 YAML 变体)。 -
打包 jar 之外的应用程序属性(
application.properties
和 YAML 变体)。 -
打包的 jar(
application-{profile}.properties
和 YAML 变体)之外的特定于配置文件的应用程序属性。
为了提供一个具体示例,假设您开发了一个@Component
使用name
属性的 ,如以下示例所示:
@Component
public class MyBean {
@Value("${name}")
private String name;
// ..
}
在您的应用程序类路径上(例如,在您的 jar 中),您可以拥有一个application.properties
文件,该文件为name
. 在新环境中运行时,application.properties
可以在 jar 之外提供一个覆盖name
. 对于一次性测试,您可以使用特定的命令行开关(例如,java -jar app.jar --name="Spring"
)启动。
2.1. 访问命令行属性
默认情况下,SpringApplication
将任何命令行选项参数(即以--
开头的参数,例如--server.port=9000
)转换为一个属性
并将它们添加到 Spring Environment
。如前所述,命令行属性始终优先于基于文件的属性源。
如果您不希望将命令行属性添加到 中Environment
,可以使用在启动类中禁用它们SpringApplication.setAddCommandLineProperties(false)
。
2.2. 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
在 Spring 中Environment
。
同样的 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
.
2.3. 外部应用程序属性
spring开机就会自动查找和加载application.properties和application.yaml文件,应用程序启动时得文件从以下位置加载:
1、classpath/root/config
2、当前目录
a.当前目录
b./config当前目录下得子目录
c.子目录下/config得子目录
该列表按优先级排序(较低项目的值覆盖较早的项目)。来自加载文件的文档被添加PropertySources
到 Spring Environment
。
如果你不喜欢application
作为配置文件名,你可以通过指定一个spring.config.name
环境属性来切换到另一个文件名。例如,要查找myproject.properties
和myproject.yaml
文件,您可以按如下方式运行您的应用程序:
$ java -jar myproject.jar --spring.config.name=myproject
您还可以使用spring.config.location
环境属性来引用显式位置。此属性接受一个或多个要检查的位置的逗号分隔列表。
以下示例显示了如何指定两个不同的文件:
$ java -jar myproject.jar --spring.config.location=\
optional:classpath:/default.properties,\
optional:classpath:/override.properties
如果spring.config.location
包含目录(而不是文件),它们应该以/
. 在运行时,它们将附加spring.config.name
在加载之前生成的名称。中指定的文件spring.config.location
直接导入。
在大多数情况下,spring.config.location
您添加的每个项目都将引用单个文件或目录。位置按照定义的顺序进行处理,后面的位置可以覆盖前面位置的值。
如果您有一个复杂的位置设置,并且您使用特定于配置文件的配置文件,您可能需要提供进一步的提示,以便 Spring Boot 知道它们应该如何分组。位置组是所有被视为同一级别的位置的集合。例如,您可能希望对所有类路径位置进行分组,然后对所有外部位置进行分组。位置组中的项目应以 分隔;
。有关更多详细信息,请参阅“配置文件特定文件”部分中的示例。
使用配置的位置spring.config.location
替换默认位置。例如,如果spring.config.location
配置了 value optional:classpath:/custom-config/,optional:file:./custom-config/
,则考虑的完整位置集是:
-
optional:classpath:custom-config/
-
optional:file:./custom-config/
如果您更喜欢添加其他位置而不是替换它们,您可以使用spring.config.additional-location
. 从其他位置加载的属性可以覆盖默认位置中的属性。例如,如果spring.config.additional-location
配置了 value 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
)。然后可以在运行时使用位于自定义位置之一的不同文件覆盖这些默认值。
2.3.1. 可选位置
默认情况下,当指定的配置数据位置不存在时,Spring Boot 将抛出 aConfigDataLocationNotFoundException
并且您的应用程序将不会启动。
如果要指定位置,但不介意它是否始终存在,则可以使用optional:
前缀。您可以将此前缀与spring.config.location
和spring.config.additional-location
属性以及spring.config.import声明一起使用。
例如,spring.config.import
值optional:file:./myconfig.properties
允许您的应用程序启动,即使myconfig.properties
文件丢失。
如果您想忽略所有ConfigDataLocationNotFoundExceptions
并始终继续启动您的应用程序,您可以使用该spring.config.on-not-found
属性。将值设置为ignore
usingSpringApplication.setDefaultProperties(…)
或 with 系统/环境变量。
2.3.2. 通配符位置
如果配置文件位置包含*
最后一个路径段的字符,则将其视为通配符位置。加载配置时会扩展通配符,以便还检查直接子目录。当有多个配置属性源时,通配符位置在 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
属性一起使用。
2.3.3. 配置文件特定文件
除了application
属性文件,Spring Boot 还将尝试使用命名约定加载特定于配置文件的文件application-{profile}
。例如,如果你的应用程序启动了一个名为轮廓prod
,并使用YAML文件,然后双方application.yml
并application-prod.yml
会予以考虑。
特定于配置文件的属性从与标准相同的位置加载application.properties
,特定于配置文件的文件始终覆盖非特定文件。如果指定了多个配置文件,则采用最后获胜的策略。例如,如果配置文件prod,live
由spring.profiles.active
属性指定,则 中的值application-prod.properties
可以被 中的值覆盖application-live.properties
2.3.4. 导入附加数据
应用程序属性可以使用该spring.config.import
属性从其他位置导入更多配置数据。进口在被发现时进行处理,并被视为附加文件,紧接在声明进口的文件之下。
例如,您的类路径application.properties
文件中可能包含以下内容:
spring.application.name=myapp
spring.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
键下指定多个位置。位置将按照定义的顺序进行处理,以后的导入优先。
2.3.5. 导入无扩展名文件
某些云平台无法为卷挂载文件添加文件扩展名。要导入这些无扩展名的文件,您需要给 Spring Boot 一个提示,以便它知道如何加载它们。您可以通过将扩展提示放在方括号中来做到这一点。
例如,假设您有一个/etc/config/myconfig
要作为 yaml 导入的文件。您可以application.properties
使用以下方法导入它:
spring.config.import=file:/etc/config/myconfig[.yaml]
2.3.6. 使用配置树
在云平台(例如 Kubernetes)上运行应用程序时,您通常需要读取平台提供的配置值。出于此类目的使用环境变量的情况并不少见,但这可能有缺点,尤其是在值应该保密的情况下。
作为环境变量的替代方案,许多云平台现在允许您将配置映射到安装的数据卷中。例如,Kubernetes 可以卷挂载ConfigMaps和Secrets.
可以使用两种常见的卷安装模式:
-
单个文件包含一组完整的属性(通常编写为 YAML)。
-
多个文件被写入目录树,文件名成为“键”,内容成为“值”。
对于第一种情况,你可以直接导入使用YAML或属性文件中spring.config.import
所描述的以上。对于第二种情况,您需要使用configtree:
前缀,以便 Spring Boot 知道它需要将所有文件公开为属性。
例如,让我们假设 Kubernetes 已经挂载了以下卷:
etc/
config/
myapp/
username
password
该username
文件的内容将是一个配置值,而 的内容password
将是一个秘密。
要导入这些属性,您可以将以下内容添加到您的application.properties
或application.yaml
文件中:
spring.config.import=optional:configtree:/etc/config/
然后,您可以以通常的方式访问或注入myapp.username
和myapp.password
属性Environment
。
如果您有多个配置树要从同一个父文件夹导入,您可以使用通配符快捷方式。configtree:
以 结尾的任何位置/*/
都会将所有直接子项导入为配置树。
例如,给定以下体积:
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
属性。
配置树也可用于 Docker 机密。当 Docker swarm 服务被授予访问机密的权限时,机密会被挂载到容器中。例如,如果db.password
在 location 挂载了一个名为的秘密,则/run/secrets/
可以db.password
使用以下命令将其提供给 Spring 环境:
spring.config.import=optional:configtree:/run/secrets/
2.3.7. 属性占位符
application.properties
和application.yml
中的值在Environment
使用时通过现有值进行过滤,因此您可以参考以前定义的值(例如,来自系统属性)。标准${name}
属性占位符语法可用于值内的任何地方。
例如,以下文件将设置app.description
为“MyApp is a Spring Boot application”:
app.name=MyApp
app.description=${app.name} is a Spring Boot application
2.3.8. 处理多文档文件
Spring Boot 允许您将单个物理文件拆分为多个独立添加的逻辑文档。文档按顺序处理,从上到下。后面的文档可以覆盖在前面的文档中定义的属性。
对于application.yml
文件,使用标准的 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
2.3.9. 激活属性
有时仅在满足某些条件时激活给定的属性 get 很有用。例如,您可能拥有仅在特定配置文件处于活动状态时才相关的属性。
您可以使用 有条件地激活属性文档spring.config.activate.*
。
以下激活属性可用:
财产 | 笔记 |
---|---|
| 必须匹配才能使文档处于活动状态的配置文件表达式。 |
| 在 |
例如,以下指定第二个文档仅在 Kubernetes 上运行时才处于活动状态,并且仅当“prod”或“staging”配置文件处于活动状态时:
myprop=always-set
#---
spring.config.activate.on-cloud-platform=kubernetes
spring.config.activate.on-profile=prod | staging
myotherprop=sometimes-set
2.4. 加密属性
Spring Boot 不提供任何对加密属性值的内置支持,但是,它提供了修改 Spring 中包含的值所需的挂钩点Environment
。该EnvironmentPostProcessor
界面允许您Environment
在应用程序启动之前进行操作
2.5. 使用 YAML
2.5.1. 将 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
为了从文件中访问这些属性,它们将被展平如下:
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 文件。因此,如果您需要以这种方式加载值,则需要使用.properties文件。
2.5.2. 直接加载 YAML
Spring Framework 提供了两个方便的类,可用于加载 YAML 文档。该YamlPropertiesFactoryBean
负载YAML作为Properties
和YamlMapFactoryBean
负载YAML作为Map
。
YamlPropertySourceLoader
如果要将 YAML 作为 Spring 加载,也可以使用该类PropertySource
。
2.6. 配置随机值
这RandomValuePropertySource
对于注入随机值很有用(例如,注入机密或测试用例)。它可以生成整数、长整数、uuid 或字符串,如以下示例所示:
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]}
该random.int*
语法是OPEN value (,max) CLOSE
其中的OPEN,CLOSE
任何字符和value,max
是整数。如果max
提供,则value
是最小值和max
最大值(不包括)。
2.7. 配置系统环境属性
Spring Boot 支持为环境属性设置前缀。如果系统环境由具有不同配置要求的多个 Spring Boot 应用程序共享,这将非常有用。系统环境属性的前缀可以直接设置在SpringApplication
.
例如,如果您将前缀设置为input
,则诸如在系统环境中的属性remote.timeout
也将被解析input.remote.timeout
。
2.8. 类型安全的配置属性
使用@Value("${property}")
注解注入配置属性有时会很麻烦,尤其是当您使用多个属性或您的数据本质上是分层的时。Spring Boot 提供了一种处理属性的替代方法,它让强类型 bean 管理和验证应用程序的配置
2.8.1. JavaBean 属性绑定
可以绑定声明标准 JavaBean 属性的 bean,如以下示例所示:
@ConfigurationProperties("my.service")
public class MyProperties {
private boolean enabled;
private InetAddress remoteAddress;
private final Security security = new Security();
// getters / setters...
public static class Security {
private String username;
private String password;
private List<String> roles = new ArrayList<>(Collections.singleton("USER"));
// getters / setters...
}
}
前面的 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
.
映射到@ConfigurationProperties
Spring Boot 中可用类的属性,通过属性文件、YAML 文件、环境变量和其他机制配置,是公共 API,但类本身的访问器(getter/setter)并不意味着直接使用.
这种安排依赖于默认的空构造函数,并且 getter 和 setter 通常是强制性的,因为绑定是通过标准的 Java Beans 属性描述符进行的,就像在 Spring MVC 中一样。在以下情况下可以省略 setter:
-
映射,只要它们被初始化,就需要一个 getter,但不一定是一个 setter,因为它们可以被绑定器改变。
-
可以通过索引(通常使用 YAML)或使用单个逗号分隔值(属性)来访问集合和数组。在后一种情况下,setter 是强制性的。我们建议始终为此类类型添加 setter。如果您初始化一个集合,请确保它不是不可变的(如前面的示例所示)。
-
如果初始化嵌套的 POJO 属性(如
Security
前面示例中的字段),则不需要设置器。如果您希望活页夹使用其默认构造函数动态创建实例,则需要一个 setter。
有些人使用 Project Lombok 自动添加 getter 和 setter。确保 Lombok 不会为此类类型生成任何特定的构造函数,因为容器会自动使用它来实例化对象。
最后,仅考虑标准 Java Bean 属性,不支持静态属性绑定。
2.8.2. 构造函数绑定
上一节中的示例可以以不可变的方式重写,如下例所示:
@ConstructorBinding
@ConfigurationProperties("my.service")
public class MyProperties {
// fields...
public MyProperties(boolean enabled, InetAddress remoteAddress, Security security) {
this.enabled = enabled;
this.remoteAddress = remoteAddress;
this.security = security;
}
// getters...
public static class Security {
// fields...
public Security(String username, String password, @DefaultValue("USER") List<String> roles) {
this.username = username;
this.password = password;
this.roles = roles;
}
// getters...
}
}
在此设置中,@ConstructorBinding
注释用于指示应使用构造函数绑定。这意味着绑定器将期望找到一个带有您希望绑定的参数的构造函数。如果您使用的是 Java 16 或更高版本,则构造函数绑定可以与记录一起使用。在这种情况下,除非您的记录有多个构造函数,否则不需要使用@ConstructorBinding
.
类的嵌套成员@ConstructorBinding
(例如Security
在上面的示例中)也将通过它们的构造函数绑定。
可以使用指定默认值,@DefaultValue
并且将应用相同的转换服务将String
值强制转换为缺失属性的目标类型。默认情况下,如果没有绑定到 的属性Security
,则MyProperties
实例将包含 的null
值security
。如果您希望Security
即使在没有属性绑定到它的情况下也返回一个非空实例,您可以使用空@DefaultValue
注释来执行此操作:
public MyProperties(boolean enabled, InetAddress remoteAddress, @DefaultValue Security security) {
this.enabled = enabled;
this.remoteAddress = remoteAddress;
this.security = security;
}
2.8.3. 启用@ConfigurationProperties 注释类型
Spring Boot 提供基础结构来绑定@ConfigurationProperties
类型并将它们注册为 bean。您可以在逐个类的基础上启用配置属性,也可以启用以与组件扫描类似的方式工作的配置属性扫描。
有时,带有注释的类@ConfigurationProperties
可能不适合扫描,例如,如果您正在开发自己的自动配置或者您想有条件地启用它们。在这些情况下,请使用@EnableConfigurationProperties
注释指定要处理的类型列表。这可以在任何@Configuration
类上完成,如以下示例所示:
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(SomeProperties.class)
public class MyConfiguration {
}
要使用配置属性扫描,请将@ConfigurationPropertiesScan
注释添加到您的应用程序。通常,它被添加到带有注释的主应用程序类中,@SpringBootApplication
但它可以添加到任何@Configuration
类中。默认情况下,将从声明注释的类的包中进行扫描。如果要定义要扫描的特定包,可以按照以下示例进行操作:
@SpringBootApplication
@ConfigurationPropertiesScan({ "com.example.app", "com.example.another" })
public class MyApplication {
}
当 上面示例中的 bean 名称是 |
我们建议@ConfigurationProperties
只处理环境,特别是不要从上下文中注入其他 bean。对于极端情况,可以使用 setter 注入或*Aware
框架提供的任何接口(例如,EnvironmentAware
如果您需要访问Environment
)。如果您仍想使用构造函数注入其他 bean,则必须@Component
使用基于 JavaBean 的属性绑定来注释和使用配置属性 bean
2.8.4. 使用@ConfigurationProperties 注释类型
这种配置风格特别适用于SpringApplication
外部 YAML 配置,如以下示例所示:
my:
service:
remote-address: 192.168.1.1
security:
username: admin
roles:
- USER
- ADMIN
要使用@ConfigurationProperties
bean,您可以以与任何其他 bean 相同的方式注入它们,如以下示例所示:
@Service
public class MyService {
private final SomeProperties properties;
public MyService(SomeProperties properties) {
this.properties = properties;
}
public void openConnection() {
Server server = new Server(this.properties.getRemoteAddress());
server.start();
// ...
}
// ...
}
2.8.5. 第三方配置
除了@ConfigurationProperties
用于注释类之外,您还可以在公共@Bean
方法上使用它。当您想要将属性绑定到您无法控制的第三方组件时,这样做会特别有用。
要从Environment
属性配置 bean ,请添加@ConfigurationProperties
到其 bean 注册中,如以下示例所示:
@Configuration(proxyBeanMethods = false)
public class ThirdPartyConfiguration {
@Bean
@ConfigurationProperties(prefix = "another")
public AnotherComponent anotherComponent() {
return new AnotherComponent();
}
}
使用another
前缀定义的任何 JavaBean 属性都AnotherComponent
以类似于前面SomeProperties
示例的方式映射到该bean 。
2.8.6. 松弛绑定
Spring Boot 使用一些宽松的规则将Environment
属性绑定到@ConfigurationProperties
bean,因此Environment
属性名称和 bean 属性名称之间不需要完全匹配。这很有用的常见示例包括以破折号分隔的环境属性(例如,context-path
绑定到contextPath
)和大写的环境属性(例如,PORT
绑定到port
)。
例如,考虑以下@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;
}
}
使用前面的代码,可以使用以下属性名称:
财产 | 笔记 |
---|---|
| 烤肉盒,推荐用于 |
| 标准的驼峰式语法。 |
| 下划线表示法,这是在 |
| 大写格式,在使用系统环境变量时推荐使用。 |
物业来源 | 简单的 | 列表 |
---|---|---|
属性文件 | Camel case、kebab case 或下划线符号 | 使用 |
YAML 文件 | Camel case、kebab case 或下划线符号 | 标准 YAML 列表语法或逗号分隔值 |
环境变量 | 下划线作为分隔符的大写格式(请参阅从环境变量绑定)。 | 由下划线包围的数值(请参阅从环境变量绑定) |
系统属性 | Camel case、kebab case 或下划线符号 | 使用 |
绑定map
绑定到Map
属性时,您可能需要使用特殊的括号表示法,以便key
保留原始值。如果键没有被 包围[]
,则任何非字母数字字符-
或被.
删除。
例如,考虑将以下属性绑定到 a Map<String,String>
:
my.map.[/key1]=value1
my.map.[/key2]=value2
my.map./key3=value3
上面的属性将绑定到Map
with /key1
, /key2
andkey3
作为地图中的键。斜线已被删除,key3
因为它没有被方括号包围。
如果您key
包含 a.
并且您绑定到非标量值,您可能偶尔也需要使用括号表示法。例如,绑定a.b=c
到Map<String, Object>
将返回带有条目的 Map{"a"={"b"="c"}}
而[a.b]=c
将返回带有条目的 Map {"a.b"="c"}
。
从环境变量绑定
大多数操作系统对可用于环境变量的名称施加了严格的规则。例如,Linux shell 变量只能包含字母(a
toz
或A
to Z
)、数字(0
to 9
)或下划线字符(_
)。按照惯例,Unix shell 变量的名称也为大写。
Spring Boot 宽松的绑定规则是为了兼容这些命名限制而设计的。
要将规范形式的属性名称转换为环境变量名称,您可以遵循以下规则:
-
将点 (
.
)替换为下划线 (_
)。 -
删除所有破折号 (
-
)。 -
转换为大写。
例如,配置属性spring.main.log-startup-info
将是一个名为 的环境变量SPRING_MAIN_LOGSTARTUPINFO
。
绑定到对象列表时也可以使用环境变量。要绑定到 a List
,元素编号应在变量名称中用下划线括起来。
例如,配置属性my.service[0].other
将使用名为 的环境变量MY_SERVICE_0_OTHER
。
2.8.7. 合并复杂类型
当列表在多个地方配置时,覆盖通过替换整个列表来工作。
例如,假设一个MyPojo
对象具有默认的name
和description
属性null
。以下示例公开了MyPojo
来自的对象列表MyProperties
:
@ConfigurationProperties("my")
public class MyProperties {
private final List<MyPojo> list = new ArrayList<>();
public List<MyPojo> getList() {
return this.list;
}
}
考虑以下配置:
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
如果dev
配置文件未激活,则MyProperties.list
包含一个MyPojo
条目,如先前定义的那样。dev
但是,如果配置文件已启用,则该配置文件list
仍仅包含一个条目(名称为my another name
和描述为null
)。此配置不会将第二个MyPojo
实例添加到列表中,也不会合并项目。
当List
在多个配置文件中指定了a 时,使用具有最高优先级(并且只有那个)的那个。考虑以下示例:
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
在前面的示例中,如果dev
配置文件处于活动状态,则MyProperties.list
包含一个 MyPojo
条目(名称为my another name
,描述为null
)。对于 YAML,逗号分隔列表和 YAML 列表均可用于完全覆盖列表的内容。
对于Map
属性,您可以绑定来自多个来源的属性值。但是,对于多个来源中的同一属性,使用优先级最高的那个。以下示例公开了Map<String, MyPojo>
from MyProperties
:
@ConfigurationProperties("my")
public class MyProperties {
private final Map<String, MyPojo> map = new LinkedHashMap<>();
public Map<String, MyPojo> getMap() {
return this.map;
}
}
考虑以下配置:
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
如果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
)。
2.8.8. 属性转换
Spring Boot 在绑定到@ConfigurationProperties
bean时尝试将外部应用程序属性强制为正确的类型。如果您需要自定义类型转换,您可以提供一个ConversionService
bean(带有一个名为 的 bean conversionService
)或自定义属性编辑器(通过一个CustomEditorConfigurer
bean)或自定义Converters
(带有注释为 的 bean 定义@ConfigurationPropertiesBinding
)。
由于在应用程序生命周期的早期请求此 bean,因此请确保限制您ConversionService
正在使用的依赖项。通常,您需要的任何依赖项在创建时可能未完全初始化。您可能需要重命名您的自定义ConversionService
如果不需要配置键强制它只有依靠合格的自定义转换器@ConfigurationPropertiesBinding
。
转换持续时间
Spring Boot 专门支持表达持续时间。如果公开java.time.Duration
属性,则应用程序属性中的以下格式可用:
-
常规
long
表示(使用毫秒作为默认单位,除非@DurationUnit
指定了 a) -
标准的ISO-8601格式使用java.time.Duration
-
一种更易读的格式,其中值和单位耦合(
10s
表示 10 秒)
考虑以下示例:
@ConfigurationProperties("my")
public class MyProperties {
@DurationUnit(ChronoUnit.SECONDS)
private Duration sessionTimeout = Duration.ofSeconds(30);
private Duration readTimeout = Duration.ofMillis(1000);
// getters / setters...
}
要将会话超时指定为 30 秒30
,PT30S
和30s
都是等效的。500ms 的读取超时可以指定为以下任何形式:500
,PT0.5S
和500ms
。
您还可以使用任何受支持的单位。这些是:
-
ns
纳秒 -
us
微秒 -
ms
毫秒 -
s
几秒钟 -
m
几分钟 -
h
用了几个小时 -
d
持续数天
默认单位是毫秒,可以使用@DurationUnit
上面示例中所示的方法覆盖。
如果您更喜欢使用构造函数绑定,则可以公开相同的属性,如以下示例所示:
@ConfigurationProperties("my")
@ConstructorBinding
public class MyProperties {
// fields...
public MyProperties(@DurationUnit(ChronoUnit.SECONDS) @DefaultValue("30s") Duration sessionTimeout,
@DefaultValue("1000ms") Duration readTimeout) {
this.sessionTimeout = sessionTimeout;
this.readTimeout = readTimeout;
}
// getters...
}
转换期
除了持续时间之外,Spring Boot 还可以使用java.time.Period
类型。可以在应用程序属性中使用以下格式:
-
常规
int
表示(使用天作为默认单位,除非@PeriodUnit
指定了 a) -
标准的ISO-8601格式使用java.time.Period
-
一种更简单的格式,其中值和单位对耦合(
1y3d
表示 1 年零 3 天)
简单格式支持以下单位:
-
y
多年 -
m
几个月 -
w
数周 -
d
持续数天
转换数据大小
Spring Framework 具有DataSize
以字节为单位表示大小的值类型。如果公开DataSize
属性,则应用程序属性中的以下格式可用:
-
常规
long
表示(使用字节作为默认单位,除非@DataSizeUnit
指定了 a) -
一种更易读的格式,其中值和单位耦合(
10MB
表示 10 兆字节)
考虑以下示例:
@ConfigurationProperties("my")
public class MyProperties {
@DataSizeUnit(DataUnit.MEGABYTES)
private DataSize bufferSize = DataSize.ofMegabytes(2);
private DataSize sizeThreshold = DataSize.ofBytes(512);
// getters/setters...
}
指定缓冲区大小为 10 兆字节,10
并且10MB
是等效的。256 字节的大小阈值可以指定为256
或256B
。
您还可以使用任何受支持的单位。这些是:
-
B
对于字节 -
KB
千字节 -
MB
兆字节 -
GB
千兆字节 -
TB
TB 级
默认单位是字节,可以使用@DataSizeUnit
如上例所示覆盖。
如果您更喜欢使用构造函数绑定,则可以公开相同的属性,如以下示例所示:
@ConfigurationProperties("my")
@ConstructorBinding
public class MyProperties {
// fields...
public MyProperties(@DataSizeUnit(DataUnit.MEGABYTES) @DefaultValue("2MB") DataSize bufferSize,
@DefaultValue("512B") DataSize sizeThreshold) {
this.bufferSize = bufferSize;
this.sizeThreshold = sizeThreshold;
}
// getters...
}
2.8.9. @ConfigurationProperties 验证
@ConfigurationProperties
每当使用 Spring 的@Validated
注解进行注解时,Spring Boot 都会尝试验证类。您可以javax.validation
直接在配置类上使用 JSR-303约束注释。为此,请确保您的类路径上有一个兼容的 JSR-303 实现,然后向您的字段添加约束注释,如以下示例所示:
@ConfigurationProperties("my.service")
@Validated
public class MyProperties {
@NotNull
private InetAddress remoteAddress;
// getters/setters...
}
为确保始终为嵌套属性触发验证,即使未找到任何属性,关联字段也必须使用@Valid
. 以下示例建立在前面的MyProperties
示例之上:
@ConfigurationProperties("my.service")
@Validated
public class MyProperties {
@NotNull
private InetAddress remoteAddress;
@Valid
private final Security security = new Security();
// getters/setters...
public static class Security {
@NotEmpty
private String username;
// getters/setters...
}
}
您还可以Validator
通过创建一个名为 的 bean 定义来添加自定义 Spring configurationPropertiesValidator
。该@Bean
方法应该被声明static
。配置属性验证器是在应用程序生命周期的早期创建的,将@Bean
方法声明为静态方法可以创建 bean,而无需实例化@Configuration
类。这样做可以避免早期实例化可能导致的任何问题。
2.8.10. @ConfigurationProperties 与 @Value
的@Value
注释是核心容器的功能,和它不提供相同的功能,类型安全配置属性。下表总结了@ConfigurationProperties
和支持的功能@Value
:
特征 | @ConfigurationProperties | @Value |
---|---|---|
Relaxed binding(松弛绑定) | 支持 | Limited (see note below) |
元数据支持 | 支持 | No |
| 支持 | Yes |
如果您为自己的组件定义了一组配置键,我们建议您将它们分组到一个用@ConfigurationProperties
. 这样做将为您提供结构化、类型安全的对象,您可以将其注入到您自己的 bean 中。
SpEL
在解析这些文件和填充环境时,不会处理来自应用程序属性文件的表达式。但是,可以在 中编写SpEL
表达式@Value
。如果应用程序属性文件中的属性值是一个SpEL
表达式,则在通过@Value
.