Spring 獲取配置的三種方式

前言

最近在寫框架時(shí)遇到需要根據(jù)特定配置(可能不存在)加載 bean 的需求,所以就學(xué)習(xí)了下 Spring 中如何獲取配置的幾種方式。

Spring 中獲取配置的三種方式

  1. 通過 @Value 方式動(dòng)態(tài)獲取單個(gè)配置
  2. 通過 @ConfigurationProperties + 前綴方式批量獲取配置
  3. 通過 Environment 動(dòng)態(tài)獲取單個(gè)配置

通過 @Value 動(dòng)態(tài)獲取單個(gè)配置

  1. 作用

    1. 可修飾到任一變量獲取,使用較靈活
  2. 優(yōu)點(diǎn)

    1. 使用簡(jiǎn)單,且使用關(guān)聯(lián)的鏈路較短
  3. 缺點(diǎn)

    1. 配置名不能被有效枚舉到

    2. 每一個(gè)配置的使用都需重新定義,使用較為麻煩

    3. 項(xiàng)目強(qiáng)依賴配置的定義,配置不存在則會(huì)導(dǎo)致項(xiàng)目無法啟動(dòng)

  4. 使用場(chǎng)景

    1. 項(xiàng)目強(qiáng)依賴該配置的加載,想要從源頭避免因配置缺失導(dǎo)致的未知問題

    2. 只想使用少數(shù)幾個(gè)配置

  5. 代碼示例

    @Configuration
    public class ConfigByValueAnnotation {
    
        @Value("${server.port}")
        private String serverPort;
    
        public String getServerPort() {
            return serverPort;
        }
    }
    
  6. 測(cè)試代碼

@DisplayName("multipart get config")
@SpringBootTest
public class MultipartGetConfigTest {

    private static final Logger log = LoggerFactory.getLogger(MultipartGetConfigTest.class);

    @Autowired
    private ConfigByValueAnnotation configByValueAnnotation;

    @Test
    public void getByValueAnnotation(){
        log.info("get by @Value, value: {}", configByValueAnnotation.getServerPort());
    }
}
  1. 測(cè)試結(jié)果
org.spring.demo.MultipartGetConfigTest   : get by @Value, value: 7100

通過 @ConfigurationProperties + 前綴方式批量獲取

  1. 作用

    1. 用于配置類的修飾或批量配置的獲取
  2. 優(yōu)點(diǎn)

    1. 使用配置只需確定 key 的前綴即能使用,有利于批量獲取場(chǎng)景的使用

    2. 因采用前綴匹配,所以在使用新的相同前綴 key 的配置時(shí)無需改動(dòng)代碼

  3. 缺點(diǎn)

    1. 使用復(fù)雜,需定義配置類或者手動(dòng)創(chuàng)建 bean 后引入使用

    2. 增加新的前綴相同 key 時(shí)可能會(huì)引入不穩(wěn)定因素

  4. 使用場(chǎng)景

    1. 需要同時(shí)使用多前綴相同 key 的配置

    2. 期望增加新配置但不修改代碼的 properties 注入

  5. 代碼示例

    @Component
    @ConfigurationProperties(prefix = "server", ignoreInvalidFields = true)
    public class ConfigByConfigurationProperties {
    
        private Integer port;
    
        public Integer getPort() {
            return port;
        }
    
        public ConfigByConfigurationProperties setPort(Integer port) {
            this.port = port;
            return this;
        }
    }
    
    @Configuration
    public class ConfigByConfigurationPropertiesV2 {
    
        @Bean("configByValueAnnotationV2")
        @ConfigurationProperties(prefix = "server2")
        public Properties properties(){
            return new Properties();
        }
    
    }
    
    1. 測(cè)試代碼
@DisplayName("multipart get config")
@SpringBootTest
public class MultipartGetConfigTest {

       private static final Logger log = LoggerFactory.getLogger(MultipartGetConfigTest.class);
    
       @Autowired
       private ConfigByConfigurationProperties configByConfigurationProperties;
    
       @Autowired
       @Qualifier("configByValueAnnotationV2")
       private Properties properties;
    
       @Test
       public void getByConfigurationProperties(){
           log.info("get by @ConfigurationProperties, value: {}", configByConfigurationProperties.getPort());
           log.info("get by @ConfigurationProperties and manual create bean, value: {}", properties.getProperty("port"));
       }

}
  1. 測(cè)試結(jié)果
org.spring.demo.MultipartGetConfigTest   : get by @ConfigurationProperties, value: 7100
org.spring.demo.MultipartGetConfigTest   : get by @ConfigurationProperties and manual create bean, value: 7100

通過 Environment 動(dòng)態(tài)獲取單個(gè)配置

  1. 作用

    1. 用于動(dòng)態(tài)在程序代碼中獲取配置,而配置 key 不需提前定義
  2. 優(yōu)點(diǎn)

    1. 獲取的配置的 key 可不提前定義,程序靈活性高

    2. 配置 key 可使用枚舉統(tǒng)一放置與管理

  3. 缺點(diǎn)

    1. 使用較復(fù)雜,需繼承 Environment 接口形成工具類進(jìn)行獲取

    2. 獲取 key 對(duì)應(yīng)的枚舉與 key 定義分離,value 獲取鏈路較長(zhǎng)

  4. 使用場(chǎng)景

    1. 只需使用少量的配置

    2. 獲取配置的 key 無提前定義,需要根據(jù)對(duì)配置的有無進(jìn)行靈活使用

  5. 代碼示例

@Component
public class ConfigByEnvironment implements EnvironmentAware {

     private static final Logger log = LoggerFactory.getLogger(ConfigByEnvironment.class);
  
     private Environment environment;
  
     public Optional<String> get(String configKey){
         String config = environment.getProperty(configKey);
         return Objects.isNull(config) ? Optional.empty() : Optional.of(config);
     }
  
     public void get(String configKey, Consumer<String> consumer){
         Optional<String> config = get(configKey);
         if(!config.isPresent()){
             log.warn("application config, get config by key fail, key: {}", configKey);
         }
         config.ifPresent(consumer);
     }
  
     @Override
     public void setEnvironment(@NonNull Environment environment) {
         this.environment = environment;
     }
}

public enum ConfigByEnvironmentKey {

     SERVER_PORT("server.port", "server port");
  
     private String key;
  
     private String description;
  
     ConfigByEnvironmentKey(String key, String description) {
         this.key = key;
         this.description = description;
     }
  
     public String getKey() {
         return key;
     }
  
     public String getDescription() {
         return description;
     }
}
  1. 測(cè)試代碼
@DisplayName("multipart get config")
   @SpringBootTest
   public class MultipartGetConfigTest {

       private static final Logger log = LoggerFactory.getLogger(MultipartGetConfigTest.class);
    
       @Autowired
       private ConfigByEnvironment configByEnvironment;
    
       @Test
       public void getByEnvironment(){
           configByEnvironment.get(ConfigByEnvironmentKey.SERVER_PORT.getKey()).ifPresent(value -> log.info("get by environment, value: {}", value));
       }

}
  1. 測(cè)試結(jié)果
org.spring.demo.MultipartGetConfigTest   : get by environment, value: 7100

總結(jié)

獲取配置方式 優(yōu)點(diǎn) 缺點(diǎn) 使用場(chǎng)景
通過 @Value 動(dòng)態(tài)獲取單個(gè)配置 使用簡(jiǎn)單,且使用關(guān)聯(lián)的鏈路較短 1. 配置名不能被有效枚舉到<br />2. 每一個(gè)配置的使用都需重新定義,使用較為麻煩<br />3. 項(xiàng)目強(qiáng)依賴配置的定義,配置不存在則會(huì)導(dǎo)致項(xiàng)目無法啟動(dòng) 1. 項(xiàng)目強(qiáng)依賴該配置的加載,想要從源頭避免因配置缺失導(dǎo)致的未知問題<br />2. 只想使用少數(shù)幾個(gè)配置
通過 @ConfigurationProperties + 前綴方式批量獲取 1. 使用配置只需確定 key 的前綴即能使用,有利于批量獲取場(chǎng)景的使用 <br />2. 因采用前綴匹配,所以在使用新的相同前綴 key 的配置時(shí)無需改動(dòng)代碼 1. 使用復(fù)雜,需定義配置類或者手動(dòng)創(chuàng)建 bean 后引入使用<br />2. 增加新的前綴相同 key 時(shí)可能會(huì)引入不穩(wěn)定因素 1. 需要同時(shí)使用多前綴相同 key 的配置<br />2. 期望增加新配置但不修改代碼的 properties 注入
通過 Environment 動(dòng)態(tài)獲取單個(gè)配置 1. 獲取的配置的 key 可不提前定義,程序靈活性高<br />2. 配置 key 可使用枚舉統(tǒng)一放置與管理 1. 使用較復(fù)雜,需繼承 Environment 接口形成工具類進(jìn)行獲取<br />2. 獲取 key 對(duì)應(yīng)的枚舉與 key 定義分離,value 獲取鏈路較長(zhǎng) 1. 只需使用少量的配置<br />2. 獲取配置的 key 無提前定義,需要根據(jù)對(duì)配置的有無進(jìn)行靈活使用

本代碼示例已放置于 github,測(cè)試代碼位置,有需要的可自取。
本文首發(fā)于 cartoon的博客

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容