從零開始學Spring Boot系列-外部化配置

来源:https://www.cnblogs.com/daimajiangxin/p/18125642
-Advertisement-
Play Games

Spring Boot 允許你將配置外部化,以便可以在不同的環境中使用相同的應用程式代碼。可以使用屬性文件、YAML文件、環境變數和命令行參數將配置外部化。屬性值可以通過使用 @Value 註解直接註入 bean,可以通過 Spring 的 Environment 抽象訪問,也可以通過 @Confi... ...


Spring Boot 允許你將配置外部化,以便可以在不同的環境中使用相同的應用程式代碼。可以使用屬性文件、YAML文件、環境變數和命令行參數將配置外部化。屬性值可以通過使用 @Value 註解直接註入 bean,可以通過 Spring 的 Environment 抽象訪問,也可以通過 @ConfigurationProperties。

Spring Boot 使用一種非常特殊的 PropertySource 順序,其設計目的是允許合理地覆蓋值。屬性按以下順序考慮:

(1)主目錄上的 Devtools 全局設置屬性(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)僅在 random.* 中具有屬性的 RandomValuePropertySource。
(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 文件,該文件覆蓋 name。對於一次性測試,可以使用特定的命令行開關啟動(例如,java -jar app.jar --name="Spring")。

提示:SPRING_APPLICATION_JSON 屬性可以在帶有環境變數的命令行上提供。例如,可以在 UN*X shell 中使用以下行:

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

在前面的示例中,你在 Spring Environment 中使用 acme.name=test 結尾。你還可以在系統屬性中將 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 。

配置隨機值

RandomValuePropertySource 用於註入隨機值(例如,在機密或測試用例中)。它可以產生 integers、longs、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 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)當前目錄的 /config 子目錄
(2)當前目錄
(3)類路徑的 /config 包
(4)類路徑的根目錄

列表按優先順序排序(在列表中較高位置定義的屬性覆蓋在較低位置定義的屬性)。

註釋:你還可以使用 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 文件中為應用程式提供預設值。你可以在其中一個預設位置的 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 進行篩選,因此可以引用以前定義的值(例如,來自系統屬性的)。

app.name=MyApp
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 文檔:

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] 取消引用(dereferencers)的屬性鍵表示。例如,考慮以下 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 所做的)綁定到類似的屬性,需要在目標 bean 中有一個 java.util.List(或 Set) 類型的屬性,並且需要提供 setter 或使用可變值初始化它。例如,下麵的示例綁定到前面顯示的屬性:

@ConfigurationProperties(prefix="my")
public class Config {

    private List<String> servers = new ArrayList<String>();

    public List<String> getServers() {
        return this.servers;
    }
}

在 Spring 環境中將 YAML 作為屬性公開

YamlPropertySourceLoader 類可用於在 Spring Environment 中將 YAML 公開為 PropertySource。這樣就可以使用帶有占位符語法的 @Value 註解來訪問 YAML 屬性。

多配置的 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)或配置文件表達式。profile 表達式允許表達更複雜的 profile 邏輯,例如: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 配置文件可以通過使用“!”字元取反。如果為單個文檔同時指定了否定配置文件和非否定配置文件,則必須至少有一個非否定配置文件匹配,並且不能有否定配置文件匹配。

YAML 的缺點

無法使用 @PropertySource 註解載入 YAML 文件。因此,如果需要以這種方式載入值,則需要使用屬性文件。

在特定配置的 YAML 文件中使用多個 YAML 文檔語法可能會導致意外行為。例如,在名為 application-dev.yml 的文件中考慮以下配置,其中 dev 配置文件處於活動狀態:

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

在上面的例子中,profile 否定和 profile 表達式的行為將不符合預期。我們建議你不要將特定配置的 YAML 文件和多個 YAML 文檔組合在一起,而只使用其中的一個。

類型安全的配置屬性

使用 @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 定義了以下屬性:

(1)acme.enabled,預設值為 false。
(2)acme.remote-address,其類型可以從 String 轉換過來。
(3)acme.security.username,具有嵌套的“security”對象,其名稱由屬性的名稱確定。特別是,返回類型根本沒有使用,它可能是 SecurityProperties。
(4)acme.security.password。
(5)acme.security.roles,包含一個字元串集合。

註釋:getter 和 setter 通常是必需的,因為綁定是通過標準的 Java Beans 屬性描述符進行的,就像 Spring MVC 一樣。在下列情況下,可省略 setter:

(1)Maps,只要它們被初始化,就需要一個 getter,但不一定需要 setter,因為綁定器可以對它們進行修改。
(2)可以通過索引(通常使用 YAML)或使用單個逗號分隔值(屬性)訪問集合和數組。在後一種情況下,setter 是必需的。我們建議始終為這樣的類型添加 setter。如果初始化集合,請確保它不是不可變的(如前一個示例所示)。
(3)如果嵌套的 POJO 屬性被初始化(就像前面例子中 Security 欄位),則 setter 不是必須的。如果希望綁定器使用實例的預設構造函數動態創建它,則需要一個 setter。

有些人使用 Project Lombok 自動添加 getter 和 setter。確保 Lombok 不會為這樣的類型生成任何特定的構造函數,因為容器會自動使用它來實例化對象。

最後,只考慮標準的 Java Bean 屬性,不支持綁定靜態屬性。

你還需要在 @EnableConfigurationProperties 註解中列出要註冊的屬性類,如下麵的示例所示:

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

註釋:當 @ConfigurationProperties bean 以這種方式註冊時,bean 有一個常規名稱:<prefix>-<fqn>,其中 <prefix> 是在 @ConfigurationProperties 註解中指定的環境鍵首碼,<fqn> 是 bean 的完全限定名。如果該註解沒有提供任何首碼,則只使用 bean 的全完限定名。

上面例子中的 bean 名稱是 acme-com.example.AcmeProperties。

前面的配置為 AcmeProperties 創建一個常規 bean。我們建議 @ConfigurationProperties 只處理環境,特別是不要從上下文中註入其他 bean。請記住,@EnableConfigurationProperties 註解也會自動應用到你的項目中,以便從 Environment 配置任何帶有 @ConfigurationProperties 註解的現有 bean。不是用 @EnableConfigurationProperties(AcmeProperties.class) 註解 MyConfiguration,你可以使 AcmeProperties 成為一個 bean,如下麵的示例所示:

@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 可以使用這些文件為自己的 keys 提供自動完成功能。

第三方配置

除了使用 @ConfigurationProperties 註解類之外,還可以在公共 @Bean 方法上使用它。如果要將屬性綁定到不在你控制範圍內的第三方組件,那麼這樣做特別有用。

要從 Environment 屬性配置 bean,請將 @ConfigurationProperties 添加到其 bean 註冊中,如下所示:

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

用 another 首碼定義的任何屬性都映射到 AnotherComponent bean,其方式與前面的 AcmeProperties 示例類似。

寬鬆的綁定

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;
    }

}

在上面的示例中,以下屬性名都可以使用:

寬鬆綁定

屬性 註釋
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:

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

上面的屬性將綁定到以 /key1、/key2 和 key3 作為鍵的 Map。

合併複雜類型

當在多個位置配置列表時,重寫通過替換整個列表來工作。

例如,假設一個 MyPojo 對象的 name 和 description 屬性預設為空。下麵的示例公開來自 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 profile 未激活,則 AcmeProperties.list 包含一個 MyPojo 實體,如前所定義。但是,如果啟用了 dev profile,則 list 仍然只包含一個實體(name:my another name,description:null)。此配置不會向列表中添加第二個 MyPojo 實例,也不會合併實例。

在多個 profiles 中指定 List 時,將使用優先順序最高的(且僅使用該 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 profile 已激活,則 AcmeProperties.list 包含一個 MyPojo 實體(name:my another name ,description: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 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)常規的 long 表示(如果沒有指定 @DurationUnit,則使用毫秒作為預設單位)
(2)java.time.Duration 使用的標準 ISO-8601 格式
(3)一種更可讀的格式,其中值和單位是結合在一起的(例如,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。

還可以使用任何受支持的單位。它們是:

(1)ns:納秒
(2)us:微秒
(3)ms:毫秒
(4)s:秒
(5)m:分鐘
(6)h:小時
(7)d:天

預設單位是毫秒,可以使用 @DurationUnit 重寫,如上面的示例所示。

提示:如果你是從簡單使用 Long 來表示持續時間的以前版本升級,請確保在切換到 Duration 的同時定義單位(如果不是毫秒,則使用 @DurationUnit 定義)。這樣做提供了一個透明的升級路徑,同時支持更豐富的格式。

轉換數據大小

Spring Framework 有一個 DataSize 值類型,允許以位元組表示大小。如果公開 DataSize 屬性,則應用程式屬性中的以下格式可用:

(1)常規的 long 表示(如果沒有指定 @DataSizeUnit,則使用位元組作為預設單位)
(2)一種更可讀的格式,其中值和單位是結合在一起的(例如,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。

還可以使用任何受支持的單位。它們是:

(1)B:位元組
(2)KB:千位元組
(3)MB:兆位元組
(4)GB:千兆位元組
(5)TB:兆兆位元組

預設單位是位元組,可以使用 @DataSizeUnit 重寫,如上面的示例所示。

提示:如果你是從簡單使用 Long 來表示大小的以前版本升級,請確保在切換到 DataSize 的同時定義單位(如果不是位元組,則使用 @DataSizeUnit 定義)。這樣做提供了一個透明的升級路徑,同時支持更豐富的格式。

@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

}

提示:你還可以通過註解 @Bean 方法來觸發驗證,該方法使用 @Validated 創建配置屬性。

雖然在綁定時也會驗證嵌套屬性,但最好還是將關聯欄位標註為 @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 端點。詳見“生產就緒功能”章節。

@ConfigurationProperties 和 @Value

@Value 註解是一個核心容器功能,它不提供與類型安全配置屬性相同的功能。下表總結了 @ConfigurationProperties 和 @Value 支持的功能:

功能 @ConfigurationProperties @Value
寬鬆的綁定
元數據支持
SpEL

如果你為自己的組件定義了一組配置鍵,我們建議你將它們分組到一個帶有 @ConfigurationProperties 註解的 POJO 中。你還應該註意到,由於 @Value 不支持寬鬆綁定,因此如果你需要使用環境變數來提供值,那麼它就不是一個好的選擇。


我是代碼匠心,和我一起學習更多精彩知識!!!掃描二維碼!關註我,實時獲取推送。
公眾號

源文來自:https://daimajiangxin.cn

源碼地址:https://gitee.com/daimajiangxin/springboot-learning


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 單線程下的單例模式: public class Singleton { private static Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance == ...
  • 獲取數組的大小 要獲取數組的大小,可以使用 sizeof() 運算符: 示例 int myNumbers[5] = {10, 20, 30, 40, 50}; cout << sizeof(myNumbers); 結果: 20 為什麼結果顯示為 20 而不是 5,當數組包含 5 個元素時? 這是因為 ...
  • 提供者目錄 Provider Authenticator BaseDirectGrantAuthenticator AbstractFormAuthenticator AbstractUsernameFormAuthenticator RequiredActionProvider FormActio ...
  • 強制等待 即sleep()方法,由python中的time模塊提供,強制讓代碼等待xxx時間,無論前面的代碼是否執行完成或者還未完成,都必須等待設定的時間。 示例代碼如下: # coding = utf-8 from selenium import webdriver from time impor ...
  • 拓展閱讀 MySQL View MySQL truncate table 與 delete 清空表的區別和坑 MySQL Ruler mysql 日常開發規範 MySQL datetime timestamp 以及如何自動更新,如何實現範圍查詢 MySQL 06 mysql 如何實現類似 oracl ...
  • maku-generator —— 一款低代碼生成器,可根據自定義模板內容,快速生成前後端代碼,可實現項目的快速開發、上線,減少重覆的代碼編寫,開發人員只需專註業務邏輯即可。 ...
  • 目錄簡介源碼函數說明arv_camera_newarv_camera_acquisitionarv_camera_get_model_namearv_buffer_get_image_widtharv_buffer_get_image_height 簡介 本文針對官方常式中的第一個常式:single ...
  • DDD 領域驅動設計理解(Domain Driven Design) 目錄DDD 領域驅動設計理解(Domain Driven Design)概念核心目標 概念 領域驅動設計事實上是1針對OOAD的一個擴展和延申。DDD基於面向對象分析與設計技術。 對技術架構進行了分層規劃。 對每個類進行了策略和劃 ...
一周排行
    -Advertisement-
    Play Games
  • .Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 實測可以完整運行在 win7sp1/win10/win11. 如果用其他工具打包,還可以運行在mac/linux下, 傳送門BlazorHybrid 發佈為無依賴包方式 安裝 WebView2Runtime 1.57 M ...
  • 目錄前言PostgreSql安裝測試額外Nuget安裝Person.cs模擬運行Navicate連postgresql解決方案Garnet為什麼要選擇Garnet而不是RedisRedis不再開源Windows版的Redis是由微軟維護的Windows Redis版本老舊,後續可能不再更新Garne ...
  • C#TMS系統代碼-聯表報表學習 領導被裁了之後很快就有人上任了,幾乎是無縫銜接,很難讓我不想到這早就決定好了。我的職責沒有任何變化。感受下來這個系統封裝程度很高,我只要會調用方法就行。這個系統交付之後不會有太多問題,更多應該是做小需求,有大的開發任務應該也是第二期的事,嗯?怎麼感覺我變成運維了?而 ...
  • 我在隨筆《EAV模型(實體-屬性-值)的設計和低代碼的處理方案(1)》中介紹了一些基本的EAV模型設計知識和基於Winform場景下低代碼(或者說無代碼)的一些實現思路,在本篇隨筆中,我們來分析一下這種針對通用業務,且只需定義就能構建業務模塊存儲和界面的解決方案,其中的數據查詢處理的操作。 ...
  • 對某個遠程伺服器啟用和設置NTP服務(Windows系統) 打開註冊表 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer 將 Enabled 的值設置為 1,這將啟用NTP伺服器功 ...
  • title: Django信號與擴展:深入理解與實踐 date: 2024/5/15 22:40:52 updated: 2024/5/15 22:40:52 categories: 後端開發 tags: Django 信號 松耦合 觀察者 擴展 安全 性能 第一部分:Django信號基礎 Djan ...
  • 使用xadmin2遇到的問題&解決 環境配置: 使用的模塊版本: 關聯的包 Django 3.2.15 mysqlclient 2.2.4 xadmin 2.0.1 django-crispy-forms >= 1.6.0 django-import-export >= 0.5.1 django-r ...
  • 今天我打算整點兒不一樣的內容,通過之前學習的TransformerMap和LazyMap鏈,想搞點不一樣的,所以我關註了另外一條鏈DefaultedMap鏈,主要調用鏈為: 調用鏈詳細描述: ObjectInputStream.readObject() DefaultedMap.readObject ...
  • 後端應用級開發者該如何擁抱 AI GC?就是在這樣的一個大的浪潮下,我們的傳統的應用級開發者。我們該如何選擇職業或者是如何去快速轉型,跟上這樣的一個行業的一個浪潮? 0 AI金字塔模型 越往上它的整個難度就是職業機會也好,或者說是整個的這個運作也好,它的難度會越大,然後越往下機會就會越多,所以這是一 ...
  • @Autowired是Spring框架提供的註解,@Resource是Java EE 5規範提供的註解。 @Autowired預設按照類型自動裝配,而@Resource預設按照名稱自動裝配。 @Autowired支持@Qualifier註解來指定裝配哪一個具有相同類型的bean,而@Resourc... ...