2.外部化配置
Spring Boot使您可以外部化配置,以便可以在不同环境中使用相同的应用程序代码。 您可以使用属性文件,YAML文件,环境变量和命令行参数来外部化配置。属性值可以通过使用@Value注释直接注入到bean中,也可以通过Spring环境抽象访问,或者通过@ConfigurationProperties绑定到结构化对象。
Spring引导使用一个非常特殊的PropertySource顺序,该顺序设计用于允许合理地重写值。属性按以下顺序考虑
-
当devtools处于活动状态时,$ HOME / .config / spring-boot目录中的Devtools全局设置属性。
-
测试上的@TestPropertySource批注。
-
测试中的properties属性。 在@SpringBootTest和测试注释上可用,用于测试应用程序的特定部分。
-
命令行参数。
-
来自SPRING_APPLICATION_JSON的属性(嵌入在环境变量或系统属性中的内联JSON)。
-
ServletConfig的初始化参数。
-
ServletContext的初始化参数。
-
来自java:comp / env的JNDI属性。
-
Java系统属性(System.getProperties())。
-
操作系统环境变量。
-
一个RandomValuePropertySource,仅具有random。*属性。
-
打包的jar之外的特定于配置文件的应用程序属性(application- {profile} .properties和YAML变体)。
-
打包在jar中的特定于配置文件的应用程序属性(application- {profile} .properties和YAML变体)。
-
打包的jar之外的应用程序属性(application.properties和YAML变体)。
-
打包在jar中的应用程序属性(application.properties和YAML变体)。
-
@Configuration类上的@PropertySource批注。 请注意,在刷新应用程序上下文之前,不会将此类属性源添加到环境中。 现在配置某些属性(如logging.和spring.main.)为时已晚,这些属性在刷新开始之前就已读取。
-
默认属性(通过设置SpringApplication.setDefaultProperties指定)。
为了提供一个具体的示例,假设您开发了一个 @Component使用 name属性的,如以下示例所示:
import org.springframework.stereotype.*;
import org.springframework.beans.factory.annotation.*;
@Component
public class MyBean {
@Value("${name}")
private String name;
// ...
}
在您的应用程序类路径上(例如,在jar内),您可以拥有一个application.properties文件,该文件为名称提供合理的默认属性值。 在新环境中运行时,可以在jar外部提供一个覆盖该名称的application.properties文件。 对于一次性测试,可以使用特定的命令行开关启动(例如,java -jar app.jar --name =“ Spring”)。
加载配置文件时,Spring Boot还支持通配符位置。 默认情况下,jar外部支持通配符config / * /位置。 指定spring.config.additional-location和spring.config.location时,也支持通配符位置。
当配置属性有多个来源时,通配符位置在诸如Kubernetes之类的环境中特别有用。 例如,如果您具有一些Redis配置和某些MySQL配置,则可能需要将这两个配置分开,同时要求这两个配置都存在于该应用程序可以绑定到的application.properties中。 这可能会导致两个单独的application.properties文件安装在不同的位置,例如/config/redis/application.properties和/config/mysql/application.properties。 在这种情况下,通配符位置为config / * /将导致两个文件都被处理。
通配符位置必须仅包含一个, 并以 结尾 /目录 或 */的搜索位置 文件的搜索位置 。 带通配符的位置根据文件名的绝对路径按字母顺序排序。
这些 SPRING_APPLICATION_JSON属性可以在命令行中提供环境变量。 例如,您可以在UN * X shell中使用以下行:
$ SPRING_APPLICATION_JSON =’{“ acme”:{“ name”:“ test”}}}'java -jar myapp.jar
在前面的示例中,您在Spring环境中得到了acme.name=test。您还可以以spring.application的形式提供JSON。系统属性中的json,如下面的示例所示
$ java -Dspring.application.json =’{“ name”:“ test”}’-jar myapp.jar
您还可以使用命令行参数来提供JSON,如以下示例所示:
$ java -jar myapp.jar --spring.application.json =’{“ name”:“ test”}’
您还可以将JSON作为JNDI变量提供,如下所示:
java:comp/env/spring.application.json。
尽管 null来自JSON的值将添加到生成的属性源中,但是 PropertySourcesPropertyResolver将 null属性视为缺失值。 这意味着JSON无法使用 覆盖低阶属性源中的属性 null值 。
2.1。 配置随机值
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值(,max)CLOSE,其中OPEN,CLOSE是任何字符,value,max是整数。 如果提供了max,则value是最小值,而max是最大值(不包括)。
2.2。 访问命令行属性
默认情况下,SpringApplication将所有命令行选项参数(即以-开头的参数,例如–server.port = 9000)转换为属性,并将其添加到Spring Environment中。 如前所述,命令行属性始终优先于其他属性源。
如果您不希望将命令行属性添加到环境中,则可以使用SpringApplication.setAddCommandLineProperties(false)禁用它们。
2.3。Application Property Files
SpringApplication从位于以下位置的application.properties文件中加载属性,并将它们添加到Spring Environment中:
-
当前目录的/ config子目录
-
当前目录
-
类路径 /config包
-
类路径根
-
列表按优先级排序(在列表较高位置定义的属性将覆盖在较低位置定义的属性)。
您还可以 使用YAML(.yml)文件 来替代.properties。
如果您不喜欢application.properties作为配置文件名,则可以通过指定spring.config.name环境属性来切换到另一个文件名。 您还可以通过使用spring.config.location环境属性(目录位置或文件路径的逗号分隔列表)来引用显式位置。 下面的示例演示如何指定其他文件名:
$ java -jar myproject.jar --spring.config.name = myproject
下面的示例演示如何指定两个位置:
$ java -jar myproject.jar --spring.config.location = classpath:/default.properties,classpath:/override.properties
spring.config.name并且 spring.config.location很早就用于确定必须加载哪些文件。 必须将它们定义为环境属性(通常是OS环境变量,系统属性或命令行参数)。
如果spring.config.location包含目录(而不是文件),则它们应以/结尾(并且在运行时,应在加载之前附加从spring.config.name生成的名称,包括特定于配置文件的文件名)。 spring.config.location中指定的文件按原样使用,不支持特定于配置文件的变体,并且被任何特定于配置文件的属性覆盖。 无论是直接指定还是包含在目录中,配置文件都必须在名称中包含文件扩展名。 开箱即用的典型扩展名是.properties,.yaml和.yml。
配置位置以相反的顺序搜索。 默认情况下,配置的位置是classpath:/,classpath:/ config /,file:./,file:./ config / * /,file:./ config /。 结果搜索顺序如下:
-
file:./config/
-
file:./config/*/
-
file:./
-
classpath:/config/
-
classpath:/
使用spring.config.location配置自定义配置位置后,它们将替换默认位置。 例如,如果spring.config.location配置为值classpath:/ custom-config /,file:./ custom-config /,则搜索顺序如下:
-
file:./custom-config/
-
classpath:custom-config/
另外,当使用spring.config.additional-location配置自定义配置位置时,除默认位置外,还会使用它们。 在默认位置之前搜索其他位置。 例如,如果配置了classpath:/ custom-config /,file:./ custom-config /的其他位置,则搜索顺序如下:
-
file:./custom-config/
-
classpath:custom-config/
-
file:./config/
-
file:./config/*/
-
file:./
-
classpath:/config/
-
classpath:/
通过此搜索顺序,您可以在一个配置文件中指定默认值,然后在另一个配置文件中有选择地覆盖这些值。 您可以在默认位置之一的application.properties(或使用spring.config.name选择的其他任何基本名称)中为应用程序提供默认值。 然后,可以在运行时使用自定义位置之一中的其他文件覆盖这些默认值。
如果您使用环境变量而不是系统属性,则大多数操作系统都不允许使用句点分隔的键名,但是您可以使用下划线代替(例如, SPRING_CONFIG_NAME代替 spring.config.name)。 有关 请参见 从环境变量绑定 详细信息, 。
如果您的应用程序在容器中运行,则可以使用JNDI属性(中的 java:comp/env)或Servlet上下文初始化参数代替环境变量或系统属性,也可以使用它们。
2.4。Profile-specific Properties
除了application.properties文件之外,还可以使用以下命名约定来定义特定于配置文件的属性:application- {profile} .properties。 如果没有设置任何活动配置文件,则环境具有一组默认配置文件(默认为[默认])。 换句话说,如果未显式激活任何概要文件,那么将从application-default.properties中加载属性。
特定于配置文件的属性是从与标准application.properties相同的位置加载的,特定于配置文件的文件总是会覆盖非特定文件,无论特定于配置文件的文件是在打包jar的内部还是外部。
如果指定了多个配置文件,则采用后赢策略。 例如,将spring.profiles.active属性指定的配置文件添加到通过SpringApplication API配置的配置文件之后,因此具有优先权。
如果您在spring.config.location中指定了任何文件,则不考虑这些文件的特定于配置文件的变体。 如果您还想使用特定于配置文件的属性,请使用spring.config.location中的目录。
2.5。 属性中的占位符
使用application.properties中的值时,它们会通过现有的环境进行过滤,因此您可以引用以前定义的值(例如,从“系统”属性中)。
app.name=MyApp
app.description=${app.name} is a Spring Boot application
您还可以使用此技术来创建现有Spring Boot属性的“简短”变体。 有关 请参见 howto.html操作 详细信息, 方法。
2.6。 加密属性
Spring Boot不提供对加密属性值的任何内置支持,但是,它提供了修改Spring环境中包含的值所必需的挂钩点。 EnvironmentPostProcessor界面允许您在应用程序启动之前操纵环境。 有关详细信息,请参见howto.html。
如果您正在寻找一种安全的方式来存储凭据和密码,则Spring Cloud Vault项目提供了对在HashiCorp Vault中存储外部化配置的支持。
2.7。 使用YAML代替Properties
YAML是JSON的超集,因此,它是用于指定层次结构配置数据的便捷格式。 只要在类路径上具有SnakeYAML库,SpringApplication类就会自动支持YAML作为属性的替代方法。
2.7.1。 加载YAML
Spring Framework提供了两个用于加载YAML文档的方便类。YamlPropertiesFactoryBean将YAML加载为属性,而YamlMapFactoryBean将YAML加载为映射。例如,考虑下面的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
要使用Spring Boot的Binder utilities (@ConfigurationProperties所做的)绑定到类似的属性,您需要在类型为java.util.List(或Set)的目标bean中拥有一个属性,或者您需要提供一个setter 或使用可变值对其进行初始化。 例如,以下示例绑定到前面显示的属性:
@ConfigurationProperties(prefix="my")
public class Config {
private List<String> servers = new ArrayList<String>();
public List<String> getServers() {
return this.servers;
}
}
2.7.2。 在Spring环境中将YAML公开为属性
可以使用YamlPropertySourceLoader类在Spring环境中将YAML公开为PropertySource。这样就可以使用带有占位符语法的@Value注释来访问YAML属性。
2.7.3。 多配置文件的YAML文档
您可以使用spring在单个文件中指定多个特定于配置文件的YAML文档。配置文件键指示何时应用文档,如下面的示例所示
server:
address: 192.168.1.100
---
spring:
profiles: development
server:
address: 127.0.0.1
---
spring:
profiles: production & eu-central
server:
address: 192.168.1.120
在前面的示例中,如果开发配置文件处于活动状态,则server.address属性为127.0.0.1。 同样,如果生产和eu-central配置文件处于活动状态,则server.address属性为192.168.1.120。 如果未启用开发,生产和其他中心配置文件,则该属性的值为192.168.1.100。
因此spring.profiles可以包含一个配置文件名称(例如生产)或一个配置文件表达式。 配置文件表达式允许表达更复杂的配置文件逻辑,例如生产&(eu-central | eu-west)。 有关更多详细信息,请参阅参考指南。
如果在启动应用程序上下文时未明确激活任何活动,则会激活默认配置文件。 因此,在以下YAML中,我们为spring.security.user.password设置了一个值,该值仅在“默认”配置文件中可用:
server:
port: 8000
---
spring:
profiles: default
security:
user:
password: weak
然而,在下面的示例中,密码总是被设置的,因为它没有附加到任何配置文件,并且必须根据需要在所有其他配置文件中显式地重置它
server:
port: 8000
spring:
security:
user:
password: weak
使用spring.profiles元素指定的弹簧轮廓可以选择使用!字符来否定。如果为单个文档同时指定了否定的配置文件和否定的配置文件,则至少一个非否定的配置文件必须匹配,并且否定的配置文件不能匹配。
##### 2.7.4。 YAML的缺点
无法使用@PropertySource批注来加载YAML文件。 因此,在需要以这种方式加载值的情况下,需要使用properties文件。
在特定于配置文件的YAML文件中使用多YAML文档语法可能会导致意外行为。 例如,考虑文件中的以下配置:
application-dev.yml
server:
port: 8000
spring:
profiles: "!test"
security:
user:
password: "secret"
如果使用参数–spring.profiles.active = dev运行该应用程序,则可能希望将security.user.password设置为“ secret”,但事实并非如此。
嵌套的文档将被过滤,因为主文件名为application-dev.yml。它已经被认为是profile-specific,嵌套的文档将被忽略。
我们建议您不要混用profile-specificYAML文件和多个YAML文档。 坚持只使用其中之一。
2.8。 类型安全的Configuration Properties
使用@Value("${property}")注释注入配置属性有时会很麻烦,特别是在处理多个属性或数据本质上是分层的情况下。Spring Boot提供了另一种使用属性的方法,让强类型bean管理和验证应用程序的配置。
请参阅@Value和类型安全配置属性之间的区别。
2.8.1。 JavaBean属性绑定
可以绑定一个声明标准JavaBean属性的bean,如以下示例所示:
package com.example;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("acme")
public class AcmeProperties {
private boolean enabled;
private InetAddress remoteAddress;
private final Security security = new Security();
public boolean isEnabled() { ... }
public void setEnabled(boolean enabled) { ... }
public InetAddress getRemoteAddress() { ... }
public void setRemoteAddress(InetAddress remoteAddress) { ... }
public Security getSecurity() { ... }
public static class Security {
private String username;
private String password;
private List<String> roles = new ArrayList<>(Collections.singleton("USER"));
public String getUsername() { ... }
public void setUsername(String username) { ... }
public String getPassword() { ... }
public void setPassword(String password) { ... }
public List<String> getRoles() { ... }
public void setRoles(List<String> roles) { ... }
}
}
前面的POJO定义了以下属性:
-
acme.enabled, 值为 false默认 。
-
acme.remote-address,其类型可以从String强制转换。
-
acme.security.username,带有嵌套的“ security”对象,其名称由属性名称确定。 特别是,返回类型根本不使用,可能是SecurityProperties。
-
acme.security.password.
-
acme.security.roles,带有默认为USER的String集合。
映射到Spring Boot中可用的@ConfigurationProperties类的属性(通过属性文件,YAML文件,环境变量等进行配置)是公共API,但该类本身的访问器(获取器/设置器)不能直接使用。
这种安排依赖于默认的空构造函数,getter和setter通常是强制的,因为绑定是通过标准的Java bean属性描述符进行的,就像Spring MVC中一样。在下列情况下可以省略setter
映射,只要它们被初始化,就需要一个getter,但不一定是setter,因为它们可以被绑定器改变。
可以通过索引(通常使用YAML)或使用逗号分隔的值(属性)访问集合和数组。在后一种情况下,setter是必需的。我们建议始终为此类类型添加setter。如果初始化一个集合,请确保它不是不可变的(如前面的示例所示)。
如果初始化了嵌套的POJO属性(如前面示例中的安全字段),则不需要setter。如果希望绑定器使用其默认构造函数动态创建实例,则需要一个setter。
有些人使用Project Lombok自动添加getter和setter。请确保Lombok不会为这样的类型生成任何特定的构造函数,因为容器会自动使用它来实例化对象。
最后,仅考虑标准Java Bean属性,不支持对静态属性的绑定。
2.8.2。 构造函数绑定
上一节中的示例可以以不变的方式重写,如下例所示:
package com.example;
import java.net.InetAddress;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConstructorBinding;
import org.springframework.boot.context.properties.bind.DefaultValue;
@ConstructorBinding
@ConfigurationProperties("acme")
public class AcmeProperties {
private final boolean enabled;
private final InetAddress remoteAddress;
private final Security security;
public AcmeProperties(boolean enabled, InetAddress remoteAddress, Security security) {
this.enabled = enabled;
this.remoteAddress = remoteAddress;
this.security = security;
}
public boolean isEnabled() { ... }
public InetAddress getRemoteAddress() { ... }
public Security getSecurity() { ... }
public static class Security {
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;
}
public String getUsername() { ... }
public String getPassword() { ... }
public List<String> getRoles() { ... }
}
}
在这个设置中,@ConstructorBinding注释用于指示应该使用构造函数绑定。这意味着绑定器将期望找到具有您希望绑定的参数的构造器。
@ConstructorBinding类的嵌套成员(如上面示例中的Security)也将通过它们的构造函数绑定。
可以使用@DefaultValue指定默认值,并且将应用相同的转换服务将字符串值强制转换为缺失属性的目标类型。默认情况下,如果没有属性绑定到安全性,则AcmeProperties实例将包含用于安全性的空值。如果您希望在没有属性绑定到安全性的情况下返回一个非空实例,那么可以使用一个空的@DefaultValue注释来做到这一点
package com.example;
import java.net.InetAddress;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConstructorBinding;
import org.springframework.boot.context.properties.bind.DefaultValue;
@ConstructorBinding
@ConfigurationProperties("acme")
public class AcmeProperties {
private final boolean enabled;
private final InetAddress remoteAddress;
private final Security security;
public AcmeProperties(boolean enabled, InetAddress remoteAddress, @DefaultValue Security security) {
this.enabled = enabled;
this.remoteAddress = remoteAddress;
this.security = security;
}
}
要使用构造函数绑定,必须使用@EnableConfigurationProperties或配置属性扫描来启用该类。 您不能将构造函数绑定与常规Spring机制创建的bean一起使用(例如@Component bean,通过@Bean方法创建的bean或使用@Import加载的bean)
如果您的类具有多个构造函数,则还可以直接在应绑定的构造函数上使用@ConstructorBinding。
不建议将java.util.Optional与@ConfigurationProperties一起使用,因为它主要旨在用作返回类型。 因此,它不太适合配置属性注入。 为了与其他类型的属性保持一致,如果您声明了Optional属性并且没有任何值,则将绑定null而不是空的Optional。
2.8.3。 启用@ConfigurationProperties注释的类型
Spring Boot提供了绑定@ConfigurationProperties类型并将其注册为Bean的基础架构。 您可以逐级启用配置属性,也可以启用与组件扫描类似的方式进行配置属性扫描。
有时,用@ConfigurationProperties注释的类可能不适用于扫描,例如,如果您正在开发自己的自动配置,或者想要有条件地启用它们。 在这些情况下,请使用@EnableConfigurationProperties批注指定要处理的类型列表。 可以在任何@Configuration类上完成此操作,如以下示例所示:
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(AcmeProperties.class)
public class MyConfiguration {
}
要使用配置属性扫描,请将@ConfigurationPropertiesScan批注添加到您的应用程序。 通常,它被添加到使用@SpringBootApplication注释的主应用程序类中,但可以将其添加到任何@Configuration类中。 默认情况下,将从声明注释的类的包中进行扫描。 如果要定义要扫描的特定程序包,可以按照以下示例所示进行操作:
@SpringBootApplication
@ConfigurationPropertiesScan({ "com.example.app", "org.acme.another" })
public class MyApplication {
}
当@ConfigurationProperties bean注册使用配置属性扫描或通过@EnableConfigurationProperties bean有一个惯用名称:<前缀>——< fqn >, <前缀>是环境关键@ConfigurationProperties注释中指定的前缀和< fqn >是完全限定的bean的名称。如果注释不提供任何前缀,则只使用bean的完全限定名。上面示例中的bean名是acme-com.example.AcmeProperties。
我们建议@ConfigurationProperties仅处理环境,尤其不要从上下文中注入其他bean。 对于极端情况,可以使用setter注入,也可以使用框架提供的任何* Aware接口(例如,如果需要访问Environment,则可以使用EnvironmentAware)。 如果仍然想使用构造函数注入其他bean,则必须使用@Component注释配置属性bean,并使用基于JavaBean的属性绑定。
2.8.4。 使用@ConfigurationProperties注释的类型
这种配置样式特别适用于 SpringApplication外部YAML配置,如以下示例所示:
# application.yml
acme:
remote-address: 192.168.1.1
security:
username: admin
roles:
- USER
- ADMIN
# additional configuration as required
要使用@ConfigurationProperties Bean,可以像使用其他任何Bean一样注入它们,如以下示例所示:
@Service
public class MyService {
private final AcmeProperties properties;
@Autowired
public MyService(AcmeProperties properties) {
this.properties = properties;
}
//...
@PostConstruct
public void openConnection() {
Server server = new Server(this.properties.getRemoteAddress());
// ...
}
}
使用using @ConfigurationProperties还可以生成可由IDE使用的元数据文件,以为您自己的键提供自动完成功能。 有关 请参见 附录 详细信息, 。
2.8.5。 第三方配置
除了使用@ConfigurationProperties注释类之外,您还可以在公共@Bean方法上使用它。 当您要将属性绑定到控件之外的第三方组件时,这样做特别有用。
要从Environment属性配置Bean,请将@ConfigurationProperties添加到其Bean注册中,如以下示例所示:
@ConfigurationProperties(prefix = "another")
@Bean
public AnotherComponent anotherComponent() {
...
}
使用另一个前缀定义的任何JavaBean属性都映射到另一个组件bean上,方式类似于前面的AcmeProperties示例。
2.8.6。 轻松绑定
Spring Boot使用一些宽松的规则将Environment属性绑定到@ConfigurationProperties bean,因此Environment属性名称和bean属性名称之间不需要完全匹配。 有用的常见示例包括 - 分隔的环境属性(例如,上下文路径绑定到contextPath)和大写的环境属性(例如PORT绑定到端口)。
例如,请考虑以下@ConfigurationProperties类:
@ConfigurationProperties(prefix="acme.my-project.person")
public class OwnerProperties {
private String firstName;
public String getFirstName() {
return this.firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
}
使用上述代码,可以使用以下属性名称
注释的前缀值必须是kebab大小写(小写并以-分隔,如acme.my-project.person)。
我们建议,如果可能的话,将属性存储为小写的kebab格式,例如my.property-name=acme。
Binding Maps
绑定到Map属性时,如果键包含小写字母数字字符或-以外的任何其他字符,则需要使用方括号表示法,以便保留原始值。 如果键没有被[]包围,则所有非字母数字或-的字符都将被删除。 例如,考虑将以下属性绑定到Map:
acme:
map:
"[/key1]": value1
"[/key2]": value2
/key3: value3
上面的属性将以/ key1,/ key2和key3作为映射中的键绑定到Map。
对于YAML文件,方括号需要用引号引起来,以便正确解析密钥。
从环境变量绑定
大多数操作系统在可用于环境变量的名称周围施加严格的规则。 例如,Linux shell变量只能包含字母(a到z或A到Z),数字(0到9)或下划线字符(_)。 按照约定,Unix shell变量也将以大写字母命名。
Spring Boot的宽松绑定规则尽可能地与这些命名限制兼容。
要将规范形式的属性名称转换为环境变量名称,可以遵循以下规则:
-
用下划线(_)替换点(.)。
-
删除所有破折号(-)。
-
转换为大写。
例如,配置属性spring.main.log-startup-info将是一个名为SPRING_MAIN_LOGSTARTUPINFO的环境变量。
下划线不能用于替换属性名称中的破折号。 如果尝试 一起使用 SPRING_MAIN_LOG_STARTUP_INFO与上面的示例 ,则不会绑定任何值。
绑定到对象列表时也可以使用环境变量。 要绑定到 List,元素编号应在变量名称中用下划线括起来。
例如,配置属性 my.acme[0].other将使用名为的环境变量 MY_ACME_0_OTHER。
2.8.7。 合并复杂类型
如果在多个位置配置了列表,则通过替换整个列表来进行覆盖。
例如,假设MyPojo对象的名称和描述属性默认为空。 下面的示例从AcmeProperties公开MyPojo对象的列表:
@ConfigurationProperties("acme")
public class AcmeProperties {
private final List<MyPojo> list = new ArrayList<>();
public List<MyPojo> getList() {
return this.list;
}
}
考虑以下配置:
acme:
list:
- name: my name
description: my description
---
spring:
profiles: dev
acme:
list:
- name: my another name
如果dev配置文件不是活动的,请使用AcmeProperties。list包含一个MyPojo条目,如前所述。但是,如果dev配置文件是启用的,该列表仍然只包含一个条目(名称为my another name,描述为null)。此配置不会向列表添加第二个MyPojo实例,也不会合并项目。
在多个配置文件中指定列表时,将使用优先级最高的列表(并且仅使用那个列表)。 考虑以下示例:
acme:
list:
- name: my name
description: my description
- name: another name
description: another description
---
spring:
profiles: dev
acme:
list:
- name: my another name
在前面的示例中,如果 dev配置文件处于活动状态,则 AcmeProperties.list包含 一个 MyPojo条目(名称为 my another name,说明为 null)。 对于YAML,可以使用逗号分隔的列表和YAML列表来完全覆盖列表的内容。
对于 Map属性,可以绑定从多个来源绘制的属性值。 但是,对于多个源中的同一属性,将使用优先级最高的属性。
以下示例公开了 Map<String, MyPojo>from AcmeProperties:
@ConfigurationProperties("acme")
public class AcmeProperties {
private final Map<String, MyPojo> map = new HashMap<>();
public Map<String, MyPojo> getMap() {
return this.map;
}
}
考虑以下配置:
acme:
map:
key1:
name: my name 1
description: my description 1
---
spring:
profiles: dev
acme:
map:
key1:
name: dev name 1
key2:
name: dev name 2
description: dev description 2
如果dev配置文件不是活动的,请使用AcmeProperties。Map包含一个条目键key1(名字 my name 1和 my description 1。如果启用dev配置文件,那么Map包含两个条目key1( dev name 1)和key2 (dev name 2和dev description 2)。
2.8.8。 属性转换
当Spring Boot绑定到@ConfigurationProperties bean时,它尝试将外部应用程序属性强制为正确的类型。 如果需要自定义类型转换,则可以提供一个ConversionService bean(具有一个名为conversionService的bean)或自定义属性编辑器(通过CustomEditorConfigurer bean)或自定义Converters(具有定义为@ConfigurationPropertiesBinding的bean定义)。
由于在应用程序生命周期中非常早就请求了此bean,因此请确保限制您的ConversionService使用的依赖项。 通常,您需要的任何依赖项可能在创建时未完全初始化。 如果配置键强制不需要自定义的转换服务,而仅依赖于@ConfigurationPropertiesBinding限定的自定义转换器,则可能要重命名自定义的转换服务。
转换持续时间
Spring Boot为表达持续时间提供了专门的支持。 如果公开java.time.Duration属性,则应用程序属性中的以下格式可用:
-
常规 long表示形式(使用毫秒作为默认单位,除非 已指定@DurationUnit)
-
标准的ISO-8601格式 使用 java.time.Duration
-
值和单位耦合的更易读的格式(例如, 10s表示10秒)
考虑以下示例:
@ConfigurationProperties("app.system")
public class AppSystemProperties {
@DurationUnit(ChronoUnit.SECONDS)
private Duration sessionTimeout = Duration.ofSeconds(30);
private Duration readTimeout = Duration.ofMillis(1000);
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;
}
}
要指定30秒的会话超时,则30,PT30S和30s都是等效的。 可以使用以下任意形式指定500ms的读取超时:500,PT0.5S和500ms。
您也可以使用任何受支持的单位。 这些是:
ns十亿分之一秒
us微秒
ms毫秒
s几秒钟
m几分钟
h用了几个小时
d好几天
默认单元是毫秒,可以使用@DurationUnit覆盖,如上面的示例所示。注意,@DurationUnit只受使用getter和setter的javabean风格的属性绑定的支持。构造函数绑定不支持它。
如果要升级Long属性,请确保以毫秒为单位定义单位(使用@DurationUnit)。 这样做可以提供透明的升级路径,同时支持更丰富的格式。
除了持续时间,Spring Boot还可以使用 java.time.Periodtype。 可以在应用程序属性中使用以下格式:
-
常规 int表示形式(除非 否则使用天作为默认单位 @PeriodUnit指定, )
-
标准的ISO-8601格式 使用 java.time.Period
-
值和单位对耦合的更简单格式(例如, 1y3d表示1年零3天)
简单格式支持以下单位:
y多年
m几个月
w数周
d好几天
该 java.time.Period类型从不实际存储星期数,这是一个快捷方式,表示“ 7天”。
转换数据大小
Spring Framework的 DataSize值类型表示字节大小。 如果公开 DataSize属性,则应用程序属性中的以下格式可用:
-
常规的long表示形式(除非已指定@DataSizeUnit,否则使用字节作为默认单位)
-
值和单位耦合的更具可读性的格式(例如, 10MB意味着10兆字节)
考虑以下示例:
@ConfigurationProperties("app.io")
public class AppIoProperties {
@DataSizeUnit(DataUnit.MEGABYTES)
private DataSize bufferSize = DataSize.ofMegabytes(2);
private DataSize sizeThreshold = DataSize.ofBytes(512);
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;
}
}
指定10 MB的缓冲区大小, 10并且 10MB等效。 可以将256个字节的大小阈值指定为 256或 256B。
您也可以使用任何受支持的单位。 这些是:
B对于字节
KB千字节
MB兆字节
GB千兆字节
TB太字节
默认单元是字节,可以使用@DataSizeUnit覆盖,如上面示例所示。
如果要升级Long属性,请确保定义单位(如果不是字节)(使用@DataSizeUnit)。 这样做可以提供透明的升级路径,同时支持更丰富的格式。
2.8.9。 @ConfigurationProperties验证
每当使用Spring的@Validated注释对@ConfigurationProperties类进行注释时,Spring Boot就会尝试对其进行验证。 您可以在配置类上直接使用JSR-303 javax.validation约束注释。 为此,请确保在类路径上有兼容的JSR-303实现,然后将约束注释添加到字段中,如以下示例所示:
@ConfigurationProperties(prefix="acme")
@Validated
public class AcmeProperties {
@NotNull
private InetAddress remoteAddress;
// ... getters and setters
}
您还可以通过使用@Validated对创建配置属性的@Bean方法进行注释来触发验证。
为了确保始终为嵌套属性触发验证,即使未找到任何属性,也必须使用@Valid注释关联的字段。 以下示例以前面的AcmeProperties示例为基础:
@ConfigurationProperties(prefix="acme")
@Validated
public class AcmeProperties {
@NotNull
private InetAddress remoteAddress;
@Valid
private final Security security = new Security();
// ... getters and setters
public static class Security {
@NotEmpty
public String username;
// ... getters and setters
}
}
您还可以通过创建一个名为configurationPropertiesValidator的bean定义来添加自定义Spring Validator。 @Bean方法应声明为静态。 配置属性验证器是在应用程序生命周期的早期创建的,并且将@Bean方法声明为static可以使创建该Bean而不必实例化@Configuration类。 这样做可以避免因早期实例化而引起的任何问题。
spring-boot-actuator模块包括一个端点,该端点公开了所有@ConfigurationProperties Bean。 将您的Web浏览器指向/ actuator / configprops或使用等效的JMX端点。 有关详细信息,请参见“生产就绪功能”部分。
2.8.10。 @ConfigurationProperties与@Value
@Value批注是核心容器功能,它没有提供与类型安全的配置属性相同的功能。 下表总结了@ConfigurationProperties和@Value支持的功能:
如果您为自己的组件定义了一组配置键,我们建议您将它们组合在以@ConfigurationProperties注释的POJO中。 这样做将为您提供结构化的,类型安全的对象,您可以将其注入到自己的bean中。
如果确实要使用@Value,我们建议您使用规范形式引用属性名称(kebab-case仅使用小写字母)。 这将允许Spring Boot使用与轻松绑定@ConfigurationProperties时相同的逻辑。 例如,@Value(“ {demo.item-price}”)将从application.properties文件中选取demo.item-price和demo.itemPrice表格,并从系统环境中选取DEMO_ITEMPRICE。 如果改用@Value(“ {demo.itemPrice}”),则将不考虑demo.item-price和DEMO_ITEMPRICE。
最后,尽管您可以在@Value中编写SpEL表达式,但不会从application property files.中处理此类表达式。