从零开始学Spring Boot系列-外部化配置

打印 上一主题 下一主题

主题 919|帖子 919|积分 2757

Spring Boot 允许你将配置外部化,以便可以在不同的环境中使用雷同的应用步伐代码。可以使用属性文件、YAML文件、环境变量和命令行参数将配置外部化。属性值可以通过使用 @Value 注解直接注入 bean,可以通过 Spring 的 Environment 抽象访问,也可以通过 @ConfigurationProperties。
Spring Boot 使用一种非常特别的 PropertySource 次序,其设计目标是允许公道地覆盖值。属性按以下次序考虑:
  1. (1)主目录上的 Devtools 全局设置属性(Devtools 处于活动状态时 ~/.spring-boot-devtools.properties)。
  2. (2)测试中的 @TestPropertySource 注解。
  3. (3)测试中的 properties 属性。在 @SpringBootTest 和测试注解中提供,用于测试应用程序的特定部分。
  4. (4)命令行参数。
  5. (5)来自 SPRING_APPLICATION_JSON(内嵌在环境变量或系统属性中的 JSON)的属性。
  6. (6)ServletConfig 初始化参数。
  7. (7)ServletContext 初始化参数。
  8. (8)来自 java:comp/env 的 JNDI 属性。
  9. (9)Java 系统属性(System.getProperties())。
  10. (10)OS(操作系统)环境变量。
  11. (11)仅在 random.* 中具有属性的 RandomValuePropertySource。
  12. (12)打包的 jar 之外的特定配置的应用程序属性(application-{profile}.properties 和 YAML 变体)。
  13. (13)打包到 jar 内的特定配置的应用程序属性(application-{profile}.properties 和 YAML 变体)。
  14. (14)打包的 jar 之外的应用程序属性(application.properties 和 YAML 变体)。
  15. (15)打包到 jar 内的应用程序属性(application.properties 和 YAML 变体)。
  16. (16)@Configuration 类上的 @PropertySource 注解。
  17. (17)默认属性(通过设置 SpringApplication.setDefaultProperties 指定)。
复制代码
为了提供一个具体的示例,假设您开发了一个使用 name 属性的 @Component,如下面的示例所示:
  1.         import org.springframework.stereotype.*;
  2.         import org.springframework.beans.factory.annotation.*;
  3.         
  4.         @Component
  5.         public class MyBean {
  6.         
  7.             @Value("${name}")
  8.             private String name;
  9.         
  10.             // ...
  11.         
  12.         }
复制代码
在应用步伐类路径上(比方,在 jar 中)可以有一个 application.properties 文件,为 name 提供一个公道的默认属性值。在新环境中运行时,可以在 jar 外部提供 application.properties 文件,该文件覆盖 name。对于一次性测试,可以使用特定的命令行开关启动(比方,java -jar app.jar --name="Spring")。
提示:SPRING_APPLICATION_JSON 属性可以在带有环境变量的命令行上提供。比方,可以在 UN*X shell 中使用以下行:
  1.     SPRING_APPLICATION_JSON='{"acme":{"name":"test"}}' java -jar myapp.jar
复制代码
在前面的示例中,你在 Spring Environment 中使用 acme.name=test 末端。你还可以在体系属性中将 JSON 作为 spring.application.json 提供。
  1. $ java -Dspring.application.json='{"name":"test"}' -jar myapp.jar
复制代码
还可以使用命令行参数提供 JSON,如下面的示例所示:
  1. $ java -jar myapp.jar --spring.application.json='{"name":"test"}'
复制代码
还可以将 JSON 作为 JNDI 变量提供,如下所示:java:comp/env/spring.application.json 。
配置随机值

RandomValuePropertySource 用于注入随机值(比方,在机密或测试用例中)。它可以产生 integers、longs、uuids 或字符串,如下面示例所示:
  1. my.secret=${random.value}
  2. my.number=${random.int}
  3. my.bignumber=${random.long}
  4. my.uuid=${random.uuid}
  5. my.number.less.than.ten=${random.int(10)}
  6. my.number.in.range=${random.int[1024,65536]}
复制代码
random.int* 语法是:OPEN value(,max) CLOSE,此中 OPEN、CLOSE 是任何字符,value、max 是整数。假如提供 max,那么 value 是最小值,max 是最大值(不包含 max)。
访问命令行属性

默认情况下,SpringApplication 将任何命令行选项参数(即以 -- 开头的参数,比方:--server.port=9000)转换为一个 property,并将它们添加到 Spring Environment。如前所述,命令行属性始终优先于其他属性源。
假如不希望命令行属性添加到 Enviroment,则可以使用 SpringApplication.setAddCommandLineProperties(false) 禁用它们。
应用步伐属性文件

SpringApplication 从以下位置的 application.properties 文件加载属性,并将它们添加到 Spring Environment:
  1. (1)当前目录的 /config 子目录
  2. (2)当前目录
  3. (3)类路径的 /config 包
  4. (4)类路径的根目录
复制代码
列表按优先级排序(在列表中较高位置界说的属性覆盖在较低位置界说的属性)。
注释:你还可以使用 YAML('.yml') 文件作为“.properties”的替换。
假如你不喜好将 application.properties 作为配置文件名,则你可以通过指定 spring.config.name 环境属性切换到另一个文件名。还可以使用 spring.config.location 环境属性(目录位置或文件路径的逗号分隔列表)引用显示位置。下面的示例显示怎样指定不同的文件名。
  1. java -jar myproject.jar --spring.config.name=myproject
复制代码
下面的示例显示怎样指定两个位置:
  1. 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. (1)file:./config/
  2. (2)file:./
  3. (3)classpath:/config/
  4. (4)classpath:/
复制代码
当使用 spring.config.location 配置自界说配置位置时,它们将替换默认位置。比方,假如 spring.config.location 配置了值 classpath:/custom-config/,file:./custom-config/,则搜刮次序如下:
  1. (1)file:./custom-config/
  2. (2)classpath:custom-config/
复制代码
或者,当使用 spring.config.additional-location 配置自界说配置位置时,除了默认位置之外,还将使用它们。在默认位置之前搜刮其他位置。比方,假如配置了 classpath:/custom-config/,file:./custom-config/,则搜刮次序如下:
  1. (1)file:./custom-config/
  2. (2)classpath:custom-config/(3)file:./config/(4)file:./(5)classpath:/config/(6)classpath:/
复制代码
此搜刮次序允许你在一个配置文件中指定默认值,然后有选择地在另一个配置文件中重写这些值。你可以在默认位置的 application.properties 文件中为应用步伐提供默认值。你可以在此中一个默认位置的 application.properties(或使用 spring.config.name 选择的任何其他基名称)中为应用步伐提供默认值。然后,可以在运行时使用位于此中一个自界说位置的其他文件覆盖这些默认值。
注释:假如使用环境变量而不是体系属性,大多数操纵体系不允许使用句点分隔的键名,但是可以使用下划线(比方,使用 SPRING_CONFIG_NAME 而不是 spring.config.name)。
注释:假如你的应用步伐在容器中运行,那么可以使用 JNDI 属性(在java:comp/env中)或 servlet 上下文初始化参数,而不是环境变量或体系属性。
特定配置的属性

除了 application.properties 文件外,还可以使用以下定名约定界说特定配置的属性:application-{profile}.properties。Environment 有一组默认配置(默认情况下是 [default]),假如未设置运动配置,则使用这些配置。换句话说,假如没有显示激活配置文件,则加载 application-default.properties 中的属性。
特定配置的属性是从与标准 application.properties 雷同的位置加载的。岂论特定配置的文件是在打包的 jar 内部还是外部,特定配置的文件始终覆盖非特定的文件。
假如指定了多个配置文件,则应用“末了胜出”策略。比方,spring.profiles.active 属性指定的配置文件将添加到通过 SpringApplication API 配置的文件之后,因此具有优先权。
注释:假如在 spring.config.location 中指定了任何文件,则不考虑这些文件的特定配置的变体。假如还想使用特定配置的属性,请在 spring.config.location 中使用目录。
属性中的占位符

application.properties 中的值在使用时通过现有 Environment 进行筛选,因此可以引用以前界说的值(比方,来自体系属性的)。
  1. app.name=MyApp
  2. app.description=${app.name} is a Spring Boot application
复制代码
提示:你还可以使用此技术创建现有 Spring Boot 属性的“短”变体。
使用 YAML 代替 Properties

YAML 是 JSON 的超集,因此,它是一种用于指定分层配置数据的便捷格式。只要类路径上有 Snake YAML 库,SpringApplication 类就会自动支持 YAML 作为 properties 的替代者。
注释:假如你使用“Starters”,Snake YAML 将由 spring.boot.starter 自动提供。
加载 YAML

Spring Framework 提供了两个方便的类,可用于加载 YAML 文档。YamlPropertiesFactoryBean 将 YAML 加载为 Properties,YamlMapFactoryBean 将 YAML 加载为 Map。
比方,考虑下面的 YAML 文档:
  1. environments:
  2.     dev:
  3.         url: https://dev.example.com
  4.         name: Developer Setup
  5.     prod:
  6.         url: https://another.example.com
  7.         name: My Cool App
复制代码
前面的示例将转换为以下属性:
  1. environments.dev.url=https://dev.example.com
  2. environments.dev.name=Developer Setup
  3. environments.prod.url=https://another.example.com
  4. environments.prod.name=My Cool App
复制代码
YAML 列表用带有 [index] 取消引用(dereferencers)的属性键表示。比方,考虑以下 YAML:
  1. my:
  2. servers:
  3.     - dev.example.com
  4.     - another.example.com
复制代码
前面的示例将转换为这些属性:
  1. my.servers[0]=dev.example.com
  2. my.servers[1]=another.example.com
复制代码
要通过使用 Spring Boot 的 Binder 工具类(这就是 @ConfigurationProperties 所做的)绑定到雷同的属性,需要在目标 bean 中有一个 java.util.List(或 Set) 范例的属性,而且需要提供 setter 或使用可变值初始化它。比方,下面的示例绑定到前面显示的属性:
  1. @ConfigurationProperties(prefix="my")
  2. public class Config {
  3.     private List<String> servers = new ArrayList<String>();
  4.     public List<String> getServers() {
  5.         return this.servers;
  6.     }
  7. }
复制代码
在 Spring 环境中将 YAML 作为属性公开

YamlPropertySourceLoader 类可用于在 Spring Environment 中将 YAML 公开为 PropertySource。这样就可以使用带有占位符语法的 @Value 注解来访问 YAML 属性。
多配置的 YAML 文档

通过使用 spring.profiles 键指示文档何时应用,可以在单个文件中指定多个特定配置的 YAML 文档,如下面示例所示:
  1. server:
  2.     address: 192.168.1.100
  3. ---
  4. spring:
  5.     profiles: development
  6. server:
  7.     address: 127.0.0.1
  8. ---
  9. spring:
  10.     profiles: production & eu-central
  11. server:
  12.     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)或配置文件表达式。profile 表达式允许表达更复杂的 profile 逻辑,比方:production & (eu-central|eu-west)。
假如应用步伐上下文启动时没有显示激活配置文件,则将激活默认的。因此,在下面的 YAML 中,我们为 spring.security.user.password 设置一个值,它仅在“默认”配置文件中可用:
  1. server:
  2.   port: 8000
  3. ---
  4. spring:
  5.   profiles: default
  6.   security:
  7.     user:
  8.       password: weak
复制代码
但是,在下面的示例中,始终设置密码,因为它没有附加到任何配置文件,而且必须在所有其他配置文件中根据需要显式重置密码:
  1. server:
  2.   port: 8000
  3. spring:
  4.   security:
  5.     user:
  6.       password: weak
复制代码
通过使用 spring.profiles 元素指定的 Spring 配置文件可以通过使用“!”字符取反。假如为单个文档同时指定了否定配置文件和非否定配置文件,则必须至少有一个非否定配置文件匹配,而且不能有否定配置文件匹配。
YAML 的缺点

无法使用 @PropertySource 注解加载 YAML 文件。因此,假如需要以这种方式加载值,则需要使用属性文件。
在特定配置的 YAML 文件中使用多个 YAML 文档语法大概会导致不测活动。比方,在名为 application-dev.yml 的文件中考虑以下配置,此中 dev 配置文件处于运动状态:
  1. server:
  2.   port: 8000
  3. ---
  4. spring:
  5.   profiles: !test
  6.   security:
  7.     user:
  8.       password: weak
复制代码
在上面的例子中,profile 否定和 profile 表达式的活动将不符合预期。我们建议你不要将特定配置的 YAML 文件和多个 YAML 文档组合在一起,而只使用此中的一个。
范例安全的配置属性

使用 @Value(${property}) 注解注入配置属性有时会很麻烦,特别是在处理多个属性或数据本身是分层的情况下。Spring Boot 提供了另一种处理属性的方法,这种方法允许强范例 bean 控制和验证应用步伐的配置,如下面示例所示:
  1. package com.example;
  2. import java.net.InetAddress;
  3. import java.util.ArrayList;
  4. import java.util.Collections;
  5. import java.util.List;
  6. import org.springframework.boot.context.properties.ConfigurationProperties;
  7. @ConfigurationProperties("acme")
  8. public class AcmeProperties {
  9.     private boolean enabled;
  10.     private InetAddress remoteAddress;
  11.     private final Security security = new Security();
  12.     public boolean isEnabled() { ... }
  13.     public void setEnabled(boolean enabled) { ... }
  14.     public InetAddress getRemoteAddress() { ... }
  15.     public void setRemoteAddress(InetAddress remoteAddress) { ... }
  16.     public Security getSecurity() { ... }
  17.     public static class Security {
  18.         private String username;
  19.         private String password;
  20.         private List<String> roles = new ArrayList<>(Collections.singleton("USER"));
  21.         public String getUsername() { ... }
  22.         public void setUsername(String username) { ... }
  23.         public String getPassword() { ... }
  24.         public void setPassword(String password) { ... }
  25.         public List<String> getRoles() { ... }
  26.         public void setRoles(List<String> roles) { ... }
  27.     }
  28. }
复制代码
上面的 POJO 界说了以下属性:
  1. (1)acme.enabled,默认值为 false。
  2. (2)acme.remote-address,其类型可以从 String 转换过来。
  3. (3)acme.security.username,具有嵌套的“security”对象,其名称由属性的名称确定。特别是,返回类型根本没有使用,它可能是 SecurityProperties。
  4. (4)acme.security.password。
  5. (5)acme.security.roles,包含一个字符串集合。
复制代码
注释:getter 和 setter 通常是必需的,因为绑定是通过标准的 Java Beans 属性描述符进行的,就像 Spring MVC 一样。在下列情况下,可省略 setter:
  1. (1)Maps,只要它们被初始化,就需要一个 getter,但不一定需要 setter,因为绑定器可以对它们进行修改。
  2. (2)可以通过索引(通常使用 YAML)或使用单个逗号分隔值(属性)访问集合和数组。在后一种情况下,setter 是必需的。我们建议始终为这样的类型添加 setter。如果初始化集合,请确保它不是不可变的(如前一个示例所示)。
  3. (3)如果嵌套的 POJO 属性被初始化(就像前面例子中 Security 字段),则 setter 不是必须的。如果希望绑定器使用实例的默认构造函数动态创建它,则需要一个 setter。
复制代码
有些人使用 Project Lombok 自动添加 getter 和 setter。确保 Lombok 不会为这样的范例天生任何特定的构造函数,因为容器会自动使用它来实例化对象。
末了,只考虑标准的 Java Bean 属性,不支持绑定静态属性。
你还需要在 @EnableConfigurationProperties 注解中列出要注册的属性类,如下面的示例所示:
  1. @Configuration
  2. @EnableConfigurationProperties(AcmeProperties.class)
  3. public class MyConfiguration {
  4. }
复制代码
注释:当 @ConfigurationProperties bean 以这种方式注册时,bean 有一个通例名称:-,此中  是在 @ConfigurationProperties 注解中指定的环境键前缀, 是 bean 的完全限定名。假如该注解没有提供任何前缀,则只使用 bean 的全完限定名。
上面例子中的 bean 名称是 acme-com.example.AcmeProperties。
前面的配置为 AcmeProperties 创建一个通例 bean。我们建议 @ConfigurationProperties 只处理环境,特别是不要从上下文中注入其他 bean。请记住,@EnableConfigurationProperties 注解也会自动应用到你的项目中,以便从 Environment 配置任何带有 @ConfigurationProperties 注解的现有 bean。不是用 @EnableConfigurationProperties(AcmeProperties.class) 注解 MyConfiguration,你可以使 AcmeProperties 成为一个 bean,如下面的示例所示:
  1. @Component
  2. @ConfigurationProperties(prefix="acme")
  3. public class AcmeProperties {
  4.     // ... see the preceding example
  5. }
复制代码
这种配置方式与 SpringApplication 外部的 YAML 配置配合得特别好,如下面示例所示:
  1. # application.yml
  2. acme:
  3.     remote-address: 192.168.1.1
  4.     security:
  5.         username: admin
  6.         roles:
  7.           - USER
  8.           - ADMIN
  9. # additional configuration as required
复制代码
要使用 @ConfigurationProperties bean,可以用与任何其他 bean 雷同的方式注入它们,如下所示:
  1. @Service
  2. public class MyService {
  3.     private final AcmeProperties properties;
  4.     @Autowired
  5.     public MyService(AcmeProperties properties) {
  6.         this.properties = properties;
  7.     }
  8.     //...
  9.     @PostConstruct
  10.     public void openConnection() {
  11.         Server server = new Server(this.properties.getRemoteAddress());
  12.         // ...
  13.     }
  14. }
复制代码
提示:使用 @ConfigurationProperties 还可以天生元数据文件,IDE 可以使用这些文件为自己的 keys 提供自动完成功能。
第三方配置

除了使用 @ConfigurationProperties 注解类之外,还可以在公共 @Bean 方法上使用它。假如要将属性绑定到不在你控制范围内的第三方组件,那么这样做特别有用。
要从 Environment 属性配置 bean,请将 @ConfigurationProperties 添加到其 bean 注册中,如下所示:
  1. @ConfigurationProperties(prefix = "another")
  2. @Bean
  3. public AnotherComponent anotherComponent() {
  4.     ...
  5. }
复制代码
用 another 前缀界说的任何属性都映射到 AnotherComponent bean,其方式与前面的 AcmeProperties 示例雷同。
宽松的绑定

Spring Boot 使用一些宽松的规则将 Environment 属性绑定到 @ConfigurationProperties bean,因此 Environment 属性名和 bean 属性名之间不需要完全匹配。有用的常见示例包罗短划线分隔的环境属性(比方,context-path 绑定到 contextPath)和大写的环境属性(比方,PORT 绑定到 port)。
比方,考虑以下 @ConfigurationProperties 类:
  1. @ConfigurationProperties(prefix="acme.my-project.person")
  2. public class OwnerProperties {
  3.     private String firstName;
  4.     public String getFirstName() {
  5.         return this.firstName;
  6.     }
  7.     public void setFirstName(String firstName) {
  8.         this.firstName = firstName;
  9.     }
  10. }
复制代码
在上面的示例中,以下属性名都可以使用:
宽松绑定
属性注释acme.my-project.person.first-name烤串式,推荐在 .properties 和 .yml 文件中使用。acme.myProject.person.firstName标准的驼峰大小写语法。acme.my_project.person.first_name下划线表示法,这是在 .properties 和 .yml 文件中使用的另一种格式。ACME_MYPROJECT_PERSON_FIRSTNAME大写格式,建议在使用体系环境变量时使用。注释:该注解的 prefix 值必须是烤串式(小写并用“-”分隔,比方:acme.my-project.person)。
每个属性源的宽松绑定规则
属性源简朴的(Simple)列表(List)属性文件驼峰式、烤串式或下划线式使用“[]”的标准列表语法或逗号分隔值。YAML 文件驼峰式、烤串式或下划线式标准 YAML 列表语法或逗号分隔值。环境变量以下划线为分隔符的大写格式。“_”不应在属性名中使用。下划线围绕的数字值,比方:MY_ACME_1_OTHER = my.acme[1].other体系属性驼峰式、烤串式或下划线式使用“[]”的标准列表语法或逗号分隔值。提示:我们建议尽大概将属性存储为小写的烤串格式,比方:my.property-name=acme。
在绑定到 Map 属性时,假如 key 包含除小写字母-数字字符或“-”之外的任何内容,则需要使用方括号,以便保留原始值。假如没有用 [] 包围 key,则会删除不是字母数字或“-”的任何字符。比方,考虑将以下属性绑定到 Map:
  1. acme:
  2.   map:
  3.     "[/key1]": value1
  4.     "[/key2]": value2
  5.     /key3: value3
复制代码
上面的属性将绑定到以 /key1、/key2 和 key3 作为键的 Map。
合并复杂范例

当在多个位置配置列表时,重写通过替换整个列表来工作。
比方,假设一个 MyPojo 对象的 name 和 description 属性默认为空。下面的示例公开来自 AcmeProperties 的 MyPojo 对象列表:
  1. @ConfigurationProperties("acme")
  2. public class AcmeProperties {
  3.     private final List<MyPojo> list = new ArrayList<>();
  4.     public List<MyPojo> getList() {
  5.         return this.list;
  6.     }
  7. }
复制代码
考虑下面的配置:
  1.     acme:
  2.       list:
  3.         - name: my name
  4.           description: my description
  5.     ---
  6.     spring:
  7.       profiles: dev
  8.     acme:
  9.       list:
  10.         - name: my another name
复制代码
假如 dev profile 未激活,则 AcmeProperties.list 包含一个 MyPojo 实体,如前所界说。但是,假如启用了 dev profile,则 list 仍然只包含一个实体(name:my another name,description:null)。此配置不会向列表中添加第二个 MyPojo 实例,也不会集并实例。
在多个 profiles 中指定 List 时,将使用优先级最高的(且仅使用该 List)。请考虑以下示例:
  1.     acme:
  2.       list:
  3.         - name: my name
  4.           description: my description
  5.         - name: another name
  6.           description: another description
  7.     ---
  8.     spring:
  9.       profiles: dev
  10.     acme:
  11.       list:
  12.         - name: my another name
复制代码
在上面的示例中,假如 dev profile 已激活,则 AcmeProperties.list 包含一个 MyPojo 实体(name:my another name    ,description:null)。对于 YAML,可以使用逗号分隔的列表和 YAML 列表来完全覆盖列表的内容。
对于 Map 属性,你可以绑定来自多个源的属性值。但是,对于多个源中的同一属性,将使用优先级最高的属性。以下示例公开来自 AcmeProperties 的 Map:
  1. @ConfigurationProperties("acme")
  2. public class AcmeProperties {
  3.     private final Map<String, MyPojo> map = new HashMap<>();
  4.     public Map<String, MyPojo> getMap() {
  5.         return this.map;
  6.     }
  7. }
复制代码
考虑下面的配置:
  1.     acme:
  2.       map:
  3.         key1:
  4.           name: my name 1
  5.           description: my description 1
  6.    
  7.     spring:
  8.       profiles: dev
  9.     acme:
  10.       map:
  11.         key1:
  12.           name: dev name 1
  13.         key2:
  14.           name: dev name 2
  15.           description: dev description 2
复制代码
假如 dev profile 未激活,则 AcmeProperties.map 包含一个键为 key1 的实体(name:my name 1,description:my description 1)。但是,假如启用了 dev profile,那么 map 包含两个实体,此中键为 key1(name :my name 1,description:my description 1)和 key2(name :my name 2,description:my description 2)。
注释:前面的合并规则实用于来自所有属性源的属性,而不仅仅是 YAML 文件。
属性转换

当 Spring Boot 绑定到 @ConfigurationProperties bean 时,它尝试将外部应用步伐属性欺凌转换为正确的范例。假如需要自界说范例转换,可以提供 ConversionService bean(带有名为 ConversionService 的 bean)或自界说属性编辑器(通过 CustomEditorConfigurer bean)或自界说 Converters(带有注解为 @ConfigurationPropertiesBinding 的 bean 界说)。
注释:由于此 bean 在应用步伐生命周期的早期被请求,请确保限制 ConversionService 正在使用的依赖项。通常,你需要的任何依赖项在创建时都大概未完全初始化。假如自界说 ConversionService 对配置键欺凌(coercion)来说不是必须的,而且它仅依赖于使用 @ConfigurationPropertiesBinding 限定的自界说转换器,则大概需要重定名它。
转换持续时间
Spring Boot 对表示持续时间有专门的支持。假如公开 java.time.Duration 属性,则应用步伐属性中的以下格式可用:
  1. (1)常规的 long 表示(如果没有指定 @DurationUnit,则使用毫秒作为默认单位)
  2. (2)java.time.Duration 使用的标准 ISO-8601 格式
  3. (3)一种更可读的格式,其中值和单位是结合在一起的(例如,10s 表示 10 秒)
复制代码
考虑以下示例:
  1. ```
  2. @ConfigurationProperties("app.system")
  3. public class AppSystemProperties {
  4.     @DurationUnit(ChronoUnit.SECONDS)
  5.     private Duration sessionTimeout = Duration.ofSeconds(30);
  6.     private Duration readTimeout = Duration.ofMillis(1000);
  7.     public Duration getSessionTimeout() {
  8.         return this.sessionTimeout;
  9.     }
  10.     public void setSessionTimeout(Duration sessionTimeout) {
  11.         this.sessionTimeout = sessionTimeout;
  12.     }
  13.     public Duration getReadTimeout() {
  14.         return this.readTimeout;
  15.     }
  16.     public void setReadTimeout(Duration readTimeout) {
  17.         this.readTimeout = readTimeout;
  18.     }
  19. }
  20. ```
复制代码
要指定 30 秒的会话超时,30、PT30S 和 30s 都是等价的。读取超时 500ms 可以用以下任何形式指定:500、PT0.5S 和 500ms。
还可以使用任何受支持的单位。它们是:
  1. (1)ns:纳秒
  2. (2)us:微秒
  3. (3)ms:毫秒
  4. (4)s:秒
  5. (5)m:分钟
  6. (6)h:小时
  7. (7)d:天
复制代码
默认单位是毫秒,可以使用 @DurationUnit 重写,如上面的示例所示。
提示:假如你是从简朴使用 Long 来表示持续时间的以前版本升级,请确保在切换到 Duration 的同时界说单位(假如不是毫秒,则使用 @DurationUnit 界说)。这样做提供了一个透明的升级路径,同时支持更丰富的格式。
转换数据大小
Spring Framework 有一个 DataSize 值范例,允许以字节表示大小。假如公开 DataSize 属性,则应用步伐属性中的以下格式可用:
  1. (1)常规的 long 表示(如果没有指定 @DataSizeUnit,则使用字节作为默认单位)
  2. (2)一种更可读的格式,其中值和单位是结合在一起的(例如,10MB 表示 10 兆字节)
复制代码
考虑下面的示例:
  1. @ConfigurationProperties("app.io")
  2. public class AppIoProperties {
  3.     @DataSizeUnit(DataUnit.MEGABYTES)
  4.     private DataSize bufferSize = DataSize.ofMegabytes(2);
  5.     private DataSize sizeThreshold = DataSize.ofBytes(512);
  6.     public DataSize getBufferSize() {
  7.         return this.bufferSize;
  8.     }
  9.     public void setBufferSize(DataSize bufferSize) {
  10.         this.bufferSize = bufferSize;
  11.     }
  12.     public DataSize getSizeThreshold() {
  13.         return this.sizeThreshold;
  14.     }
  15.     public void setSizeThreshold(DataSize sizeThreshold) {
  16.         this.sizeThreshold = sizeThreshold;
  17.     }
  18. }
复制代码
要指定 10 兆字节的缓冲区大小,10 和 10MB 是等价的。256 字节的大小阈值可以指定为 256 或 256B。
还可以使用任何受支持的单位。它们是:
  1. (1)B:字节
  2. (2)KB:千字节
  3. (3)MB:兆字节
  4. (4)GB:千兆字节
  5. (5)TB:兆兆字节
复制代码
默认单位是字节,可以使用 @DataSizeUnit 重写,如上面的示例所示。
提示:假如你是从简朴使用 Long 来表示大小的以前版本升级,请确保在切换到 DataSize 的同时界说单位(假如不是字节,则使用 @DataSizeUnit 界说)。这样做提供了一个透明的升级路径,同时支持更丰富的格式。
@ConfigurationProperties 验证

每当使用 Spring 的 @Validated 注解对 @ConfigurationProperties 类进行注解时,Spring Boot 就会尝试验证它们。你可以直接在配置类上使用 JSR-303 javax.validation 约束注解。为此,请确保类路径上有一个兼容的 JSR-303 实现,然后将约束注解添加到字段上,如下面示例所示:
  1. @ConfigurationProperties(prefix="acme")
  2. @Validated
  3. public class AcmeProperties {
  4.     @NotNull
  5.     private InetAddress remoteAddress;
  6.     // ... getters and setters
  7. }
复制代码
提示:你还可以通过注解 @Bean 方法来触发验证,该方法使用 @Validated 创建配置属性。
虽然在绑定时也会验证嵌套属性,但最好还是将关联字段标注为 @Valid。这确保即使找不到嵌套属性,也会触发验证。以下示例基于前面的 AcmeProperties 示例:
  1. @ConfigurationProperties(prefix="acme")
  2. @Validated
  3. public class AcmeProperties {
  4.     @NotNull
  5.     private InetAddress remoteAddress;
  6.     @Valid
  7.     private final Security security = new Security();
  8.     // ... getters and setters
  9.     public static class Security {
  10.         @NotEmpty
  11.         public String username;
  12.         // ... getters and setters
  13.     }
  14. }
复制代码
你还可以通过创建名为 configurationPropertiesValidator 的 bean 界说来添加自界说 Spring Validator。@Bean 方法应当声明为 static。配置属性验证器是在应用步伐生命周期的早期创建的,将 @Bean 方法声明为 static 可以创建 Bean,而无需实例化 @Configuration 类。这样做可以避免任何大概由早期实例化引起的问题。有一个属性验证示例,演示了怎样设置。
提示:spring-boot-actuator 模块包罗一个端点,该端点公开所有 @ConfigurationProperties bean。将 web 浏览器指向 /actuator/configprops 或使用等价的 JMX 端点。详见“生产就绪功能”章节。
@ConfigurationProperties 和 @Value

@Value 注解是一个焦点容器功能,它不提供与范例安全配置属性雷同的功能。下表总结了 @ConfigurationProperties 和 @Value 支持的功能:
功能@ConfigurationProperties@Value宽松的绑定是否元数据支持是否SpEL否是假如你为自己的组件界说了一组配置键,我们建议你将它们分组到一个带有 @ConfigurationProperties 注解的 POJO 中。你还应该留意到,由于 @Value 不支持宽松绑定,因此假如你需要使用环境变量来提供值,那么它就不是一个好的选择。
我是代码匠心,和我一起学习更多精彩知识!!!扫描二维码!关注我,实时获取推送。

源文来自:https://daimajiangxin.cn
源码所在:https://gitee.com/daimajiangxin/springboot-learning

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

郭卫东

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表