4.2 外部配置

优质
小牛编辑
137浏览
2023-12-01

Spring Boot允许您外部化配置,以便您可以在不同的环境中使用相同的应用程序代码。 您可以使用属性文件,YAML文件,环境变量和命令行参数来外部化配置。 可以使用@Value注释将属性值直接注入到bean中,通过Spring的Environment抽象访问,或者通过@ConfigurationProperties绑定到结构化对象。

Spring Boot使用一个非常特殊的PropertySource命令,旨在允许合理地覆盖值。 按以下顺序考虑属性:

  1. 在您的主目录上开发全局设置属性(当devtools处于活动状态时,〜/.spring-boot-devtools.properties)。
  2. @TestPropertySource测试注释。
  3. 测试中的properties属性。 可在@SpringBootTest上使用,以及用于测试应用程序特定片段的测试注释。
  4. 命令行参数。
  5. SPRING_APPLICATION_JSON中的属性(嵌入在环境变量或系统属性中的内联JSON)。
  6. ServletConfig初始化参数。
  7. ServletContext初始化参数。
  8. 来自java:comp/env的JNDI属性。
  9. Java系统属性(System.getProperties())。
  10. OS环境变量。
  11. RandomValuePropertySource,只具有random.*.属性。
  12. 特定于配置文件的应用程序属性在打包的jar之外(application-{profile}.properties和YAML变体)。
  13. 打包在jar中的特定于配置文件的应用程序属性(application-{profile}.properties和YAML变体)。
  14. 打包jar之外的应用程序属性(application.properties和YAML变体)。
  15. 打包在jar中的应用程序属性(application.properties和YAML变体)。
  16. @Configuration类上的@PropertySource注释。
  17. 默认属性(通过设置SpringApplication.setDefaultProperties指定)。

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

import org.springframework.stereotype.*;
import org.springframework.beans.factory.annotation.*;

@Component
public class MyBean {

    @Value("${name}")
    private String name;

    // ...

}

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

可以在命令行上使用环境变量提供SPRING_APPLICATION_JSON属性。 例如,您可以在UN * X shell中使用以下行:

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

在前面的示例中,您最终在Spring环境中使用了acme.name = test。您还可以在System属性中将JSON作为spring.application.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。

4.2.1 配置随机值

RandomValuePropertySource对于注入随机值非常有用(例如,注入密钥或测试用例)。 它可以生成整数,长整数,uuids或字符串,如以下示例所示:

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是任何字符和值,max是整数。 如果提供了max,则value是最小值,max是最大值(不包括)。

4.2.2 访问命令行属性

默认情况下,SpringApplication将任何命令行选项参数(即以 - 开头的参数,例如--server.port = 9000)转换为属性,并将它们添加到Spring环境中。 如前所述,命令行属性始终优先于其他属性源。

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

4.2.3 应用属性文件

SpringApplication从以下位置的application.properties文件加载属性,并将它们添加到Spring环境中:

  1. 一个当前目录的/config子目录
  2. 当前目录
  3. 一个classpath下的/config包
  4. classpath根目录

列表按优先级排序(在列表中较高位置定义的属性将覆盖在较低位置中定义的属性)。

您还可以使用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中指定的文件按原样使用,不支持特定于配置文件的变体,并且被任何特定于配置文件的属性覆盖。

以相反的顺序搜索配置位置。 默认情况下,配置的位置是classpath:/,classpath:/config/,file:./,file:./config/。 生成的搜索顺序如下:

  1. file:./config/
  2. file:./
  3. classpath:/config/
  4. classpath:/

使用spring.config.location配置自定义配置位置时,它们将替换默认位置。 例如,如果spring.config.location配置了值classpath:/custom-config/,file:./custom-config/,搜索顺序将变为以下内容:

  1. file:./custom-config/
  2. classpath:custom-config/

或者,当使用spring.config.additional-location配置自定义配置位置时,除默认位置外,还会使用它们。 在默认位置之前搜索其他位置。 例如,如果配置了classpath:/custom-config/,file:./custom-config/的其他位置,则搜索顺序将变为以下内容:

  1. file:./custom-config/
  2. classpath:custom-config/
  3. file:./config/
  4. file:./
  5. classpath:/config/
  6. classpath:/

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

如果使用环境变量而不是系统属性,则大多数操作系统都不允许使用句点分隔的键名,但您可以使用下划线(例如,使用SPRING_CONFIG_NAME而不是spring.config.name)。

如果应用程序在容器中运行,则可以使用JNDI属性(在java:comp/env中)或servlet上下文初始化参数来代替环境变量或系统属性。

4.2.4 特定于配置文件的属性

除application.properties文件外,还可以使用以下命名约定定义特定于配置文件的属性:application-{profile} .properties。 环境具有一组默认配置文件(默认情况下为[default]),如果未设置活动配置文件,则使用这些配置文件。 换句话说,如果未显式激活任何配置文件,则会加载application-default.properties中的属性。

特定于配置文件的属性从与标准application.properties相同的位置加载,特定于配置文件的文件始终覆盖非特定文件,无论特定于配置文件的文件是在打包的jar内部还是外部。

如果指定了多个配置文件,则应用最后获胜策略。 例如,spring.profiles.active属性指定的配置文件是在通过SpringApplication API配置的配置文件之后添加的,因此优先。

如果在spring.config.location中指定了任何文件,则不考虑这些文件的特定于配置文件的变体。 如果要使用特定于配置文件的属性,请使用spring.config.location中的目录。

4.2.5 属性中的占位符

application.properties中的值在使用时通过现有环境进行过滤,因此您可以返回先前定义的值(例如,系统属性)。

app.name=MyApp
app.description=${app.name} is a Spring Boot application

您还可以使用此技术创建现有Spring Boot属性的“简短”变体。 有关详细信息,请参见第9.3.4节“使用'短'命令行参数”操作方法。

4.2.6 加密属性

Spring Boot没有为加密属性值提供任何内置支持,但是,它确实提供了修改Spring环境中包含的值所必需的钩子点。 EnvironmentPostProcessor接口允许您在应用程序启动之前操作Environment。 有关详细信息,请参见第9.1.3节“在开始之前自定义环境或ApplicationContext”。

如果您正在寻找一种存储凭据和密码的安全方法,Spring Cloud Vault项目支持在HashiCorp Vault中存储外部化配置。

4.2.7 使用YAML而不是properties

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

如果使用“Starters”,则Spring-boot-starter会自动提供SnakeYAML。

4.2.7.1 读取YAML

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

例如,请考虑以下YAML文档:

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

前面的示例将转换为以下属性:

environments.dev.url=http://dev.example.com
environments.dev.name=Developer Setup
environments.prod.url=http://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实用程序(这是@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;
	}
}

4.2.7.2 在Spring环境中将YAML公开为属性

YamlPropertySourceLoader类可用于在Spring环境中将YAML公开为PropertySource。 这样做可以使用带占位符语法的@Value批注来访问YAML属性。

4.2.7.3 多个YAML文件

您可以使用spring.profiles键在单个文件中指定多个特定于配置文件的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

在前面的示例中,如果development文件处于活动状态,则server.address属性为127.0.0.1。 同样,如果production和eu-central配置文件处于活动状态,则server.address属性为192.168.1.120。 如果未启用development,production和eu-central配置文件,则该属性的值为192.168.1.100。

因此,spring.profiles可以包含简单的配置文件名称(例如production)或配置文件表达式。 表达式允许表达更复杂的逻辑,例如production&(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元素指定的spring boot配置文件可以选择通过使用!字符。 如果为单个文档指定了否定和非否定的配置文件,则至少一个非否定的配置文件必须匹配,并且没有否定的配置文件可能匹配。

4.2.7.4 YAML缺点

无法使用@PropertySource批注加载YAML文件。 因此,如果您需要以这种方式加载值,则需要使用properties文件。

在特定于配置文件的YAML文件中使用多个YAML文档语法可能会导致意外行为。 例如,在名为application-dev.yml的文件中考虑以下配置,其中dev配置文件处于活动状态:

server:
  port: 8000
---
spring:
  profiles: !test
  security:
    user:
      password: weak

在上面的示例中,配置文件否定和配置文件表达式将不会按预期运行。 我们建议您不要将特定于配置文件的YAML文件和多个YAML文档组合在一起,并坚持只使用其中一个。

4.2.8 类型安全的配置属性

使用@Value("${property}")注释来注入配置属性有时会很麻烦,特别是如果您使用多个属性或者您的数据本质上是分层的。 Spring Boot提供了一种使用属性的替代方法,该方法允许强类型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,带有String集合。

getter和setter通常是必需的,因为绑定是通过标准的Java Beans属性描述符,就像在Spring MVC中一样。 在下列情况下可以省略setter:

  • Maps, 只要它们被初始化,就需要一个getter但不一定是setter,因为它们可以被绑定器转变。
  • 可以通过索引(通常使用YAML)或使用单个逗号分隔值(属性)访问集合和数组。 在后一种情况下,必须设置一个setter。 我们建议始终为这些类型添加setter。 如果初始化集合,请确保它不是不可变的(如上例所示)。
  • 如果初始化嵌套的POJO属性(如前面示例中的“Security”字段),则不需要setter。 如果您希望绑定器使用其默认构造函数动态创建实例,则需要一个setter。

有些人使用Project Lombok自动添加getter和setter。 确保Lombok不为此类型生成任何特定构造函数,因为容器会自动使用它来实例化对象。 最后,仅考虑标准Java Bean属性,并且不支持对静态属性的绑定。

另请参阅@Value和@ConfigurationProperties之间的差异。

您还需要列出要在@EnableConfigurationProperties注释中注册的属性类,如以下示例所示:

@Configuration
@EnableConfigurationProperties(AcmeProperties.class)
public class MyConfiguration {
}

当以这种方式注册@ConfigurationProperties bean时,bean具有常规名称: - ,其中是@ConfigurationProperties注释中指定的环境键前缀,是bean的完全限定名称。 如果注释未提供任何前缀,则仅使用bean的完全限定名称。 上例中的bean名称是acme-com.example.AcmeProperties。

即使前面的配置为AcmeProperties创建了一个常规bean,我们也建议@ConfigurationProperties只处理环境,特别是不从上下文中注入其他bean。 话虽如此,@EnableConfigurationProperties注释也会自动应用于您的项目,以便从Environment配置任何使用@ConfigurationProperties注释的现有bean。 您可以通过确保AcmeProperties已经是一个bean来快速创建MyConfiguration,如以下示例所示:

@Component
@ConfigurationProperties(prefix="acme")
public class AcmeProperties {

	// ... see the preceding example

}

这种配置样式在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());
		// ...
	}

}

使用@ConfigurationProperties还可以生成元数据文件,IDE可以使用这些文件为您自己的密钥提供自动完成功能。 有关详细信息,请参阅附录B,配置元数据附录。

4.2.8.1 第三方配置

除了使用@ConfigurationProperties注释类之外,您还可以在公共@Bean方法上使用它。 当您想要将属性绑定到控件之外的第三方组件时,这样做会特别有用。

要从Environment属性配置bean,请将@ConfigurationProperties添加到其bean注册中,如以下示例所示:

@ConfigurationProperties(prefix = "another")
@Bean
public AnotherComponent anotherComponent() {
	...
}

使用另一个前缀定义的任何属性都以与前面的AcmeProperties示例类似的方式映射到该AnotherComponent bean。

4.2.8.2 轻松绑定

Spring Boot使用一些宽松的规则将Environment属性绑定到@ConfigurationProperties bean,因此不需要在Environment属性名和bean属性名之间进行精确匹配。 这有用的常见示例包括破折号分隔的环境属性(例如,context-path绑定到contextPath)和大写环境属性(例如,PORT绑定到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;
	}

}

在前面的示例中,可以使用以下属性名称:

表24.1 宽松绑定

属性说明
acme.my-project.person.first-name短横线命名,推荐在.properties和.yml文件中使用。
acme.myProject.person.firstName标准驼峰式语法
acme.my_project.person.first_name下划线表示法,它是在.properties和.yml文件中使用的替代格式。
ACME_MYPROJECT_PERSON_FIRSTNAME大写格式,使用系统环境变量时建议使用。

注释的前缀值必须是短横线语法(小写并用 - 分隔,例如acme.my-project.person)。

表24.2 每个属性源宽松绑定规则

属性源SimpleList
Properties文件驼峰式、短横线式,下划线式使用[ ]或逗号分隔值的标准列表语法
YAML文件驼峰式、短横线式,下划线式标准YAML列表语法或逗号分隔值
环境变量大写格式,下划线作为分隔符。 _不应在属性名称中使用下划线包围的数字值,例如MY_ACME_1_OTHER = my.acme [1] .other
系统属性驼峰式、短横线式,下划线式使用[ ]或逗号分隔值的标准列表语法

我们建议,在可能的情况下,属性以小写的短横线命名存储,例如my.property-name = acme。

绑定到Map属性时,如果键包含除小写字母数字字符以外的任何内容或 - ,则需要使用括号表示法以保留原始值。 如果键未被[]包围,则删除任何非字母数字或字符的字符。 例如,考虑将以下属性绑定到Map:

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

上面的属性将绑定到带有/key1,/key2和key3的Map作为Map中的键。

4.2.8.3 合并复杂类型

当列表在多个位置配置时,覆盖通过替换整个列表来工作。

例如,假设具有name和description属性的MyPojo对象默认为null。 以下示例公开了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配置文件,则列表仍然只包含一个条目(name为my another name,并且描述为null)。 此配置不会向列表中添加第二个MyPojo实例,也不会合并项目。

在多个配置文件中指定List时,将使用具有最高优先级(并且只有该一个)的列表。 请考虑以下示例:

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条目(name为my another name,描述为null)。 对于YAML,逗号分隔列表和YAML列表都可用于完全覆盖列表的内容。

对于Map属性,您可以绑定从多个源中提取的属性值。 但是,对于多个源中的相同属性,使用具有最高优先级的属性。 以下示例从AcmeProperties公开Map <String,MyPojo>:

@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的条目(name为my name 1,description为my description 1)。 但是,如果启用了dev配置文件,则map包含两个条目,其中键key1(name为dev name 1和description为my description 1)和key2(name为dev name 2和description为dev description 2)。

前面的合并规则适用于所有属性源的属性,而不仅仅适用于YAML文件。

4.2.8.4 属性转换

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

由于在应用程序生命周期中很早就请求了此bean,因此请确保限制ConversionService正在使用的依赖项。 通常,您在创建时可能无法完全初始化所需的任何依赖项。 如果配置密钥强制不需要,您可能希望重命名自定义ConversionService,并且只依赖于使用@ConfigurationPropertiesBinding限定的自定义转换器。

1)转换durations

Spring Boot专门支持表达持续时间。 如果公开java.time.Duration属性,则可以使用应用程序属性中的以下格式:

  • 常规long表示(除非指定了@DurationUnit,否则使用毫秒作为默认单位)
  • java.util.Duration使用的标准ISO-8601格式
  • 一种更易读的格式,其中值和单位组合(例如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覆盖,如上面的示例所示。

如果要从仅使用Long表示持续时间的先前版本升级,如果它不是切换到的毫秒,请确保定义单位(使用@DurationUnit)。 这样做可以提供透明的升级路径,同时支持更丰富的格式。

2)转换数据大小

Spring Framework有一个DataSize值类型,允许以字节为单位表示大小。 如果公开DataSize属性,则可以使用应用程序属性中的以下格式:

  • 常规long表示(使用byte作为默认单位,除非指定了@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兆字节的缓冲区大小,10和10MB是等效的。 可以将256字节的大小阈值指定为256或256B。

您也可以使用任何支持的单位。 如下所示:

  • B
  • KB
  • MB
  • TB

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

如果要从仅使用Long表示大小的先前版本进行升级,如果它不是切换到DataSize字节,请确保定义单位(使用@DataSizeUnit)。 这样做可以提供透明的升级路径,同时支持更丰富的格式。

4.2.8.5 @ConfigurationProperties验证

只要使用Spring的@Validated注解注释,Spring Boot就会尝试验证@ConfigurationProperties类。 您可以直接在配置类上使用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方法声明为static。 配置属性验证器是在应用程序生命周期的早期创建的,并且将@Bean方法声明为static可以创建bean而无需实例化@Configuration类。 这样做可以避免早期实例化可能导致的任何问题。 有一个属性验证示例,显示如何设置。

spring-boot-actuator模块包括一个暴露所有@ConfigurationProperties bean的端点。 将Web浏览器指向/actuator/configprops或使用等效的JMX端点。 有关详细信息,请参阅“生产就绪功能”部分。

4.2.8.6 @ConfigurationProperties vs @Value

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

Feature@ConfigurationProperties@Value
宽松绑定YesNo
元数据支持YesNo
SpEL 表达式NoYes

如果为自己的组件定义一组配置键,我们建议您将它们分组到使用@ConfigurationProperties注释的POJO中。 您还应该知道,因为@Value不支持宽松绑定,所以如果您需要使用环境变量来提供值,则它不是一个好的候选者。

最后,虽然您可以在@Value中编写SpEL表达式,但不会从应用程序属性文件处理此类表达式。