SpringBoot系列之@ConfigurationProperties VS @Value註解(三)

前言

上一節咱們經過註解@PropertySource讀取內外部配置文件,而後經過註解@Value讀取其值,在Spring中經過註解@ConfigurationProperties也能夠讀取配置文件中的值,接下來咱們一塊兒來看看註解@ConfigurationProperties和@Value有何區別。java

@ConfigurationProperties VS @Value註解

關於註解@Value上一節咱們已經詳細討論過,那麼咱們首先來分析註解@ConfigurationProperties,接下來咱們在配置文件application.properties中給出一段咱們須要讀取的值,以下:spring

#app
app.trade-currency=USD
app.refresh-time-unit=seconds
app.refresh-rate=3

接下來咱們在建立的配置文件類Spring.Config中來讀取值,以下:數據庫

package com.demo.springboot;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Currency;
import java.util.concurrent.TimeUnit;

@Configuration
@ConfigurationProperties(prefix = "app")
public class SpringConfig {

    private int refreshRate;
    private TimeUnit refreshTimeUnit;
    private Currency tradeCurrency;

    @Bean
    public UserDAL getUserDAL() {
        return new UserDAL();
    }

    @Override
    public String toString() {
        System.out.println();
        return "SpringConfig:{" +
                "refreshRate = '" + refreshRate + '\'' +
                ", refreshTimeUnit = '" + refreshTimeUnit + '\'' +
                ", tradeCurrency =  '" + tradeCurrency + '\'' +
                 '}';
    }
}

如上咱們並未添加註解@PropertySource指定讀取文件位置,由於默認會從默認建立的配置文件application.properties中讀取。註解@ConfigurationProperties須要明確參數prefix(前綴),並且不能爲空,咱們看到在配置文件中所給出的值的前綴都爲app,因此如上咱們給出其參數前綴爲app,接下來咱們調用該配置文件類並打印出映射結果,以下:springboot

package com.demo.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class SpringbootApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringbootApplication.class, args);

        SpringConfig bean = context.getBean(SpringConfig.class);
        System.out.println(bean);
    }
}

如上咱們能夠看到值都爲默認值並未映射上,這是爲何呢?由於經過註解@ConfigurationProperties綁定字段時,必需要使用屬性。以下咱們添加屬性:app

    public int getRefreshRate() {
        return refreshRate;
    }
    public void setRefreshRate(int refreshRate) {
        this.refreshRate = refreshRate;
    }
    public TimeUnit getRefreshTimeUnit() {
        return refreshTimeUnit;
    }
    public void setRefreshTimeUnit(TimeUnit refreshTimeUnit) {
        this.refreshTimeUnit = refreshTimeUnit;
    }
    public Currency getTradeCurrency() {
        return tradeCurrency;
    }
    public void setTradeCurrency(Currency tradeCurrency) {
        this.tradeCurrency = tradeCurrency;
    }

既然註解@ConfigurationProperties經過屬性來綁定,那麼對於咱們在配置文件中的名稱是否有大小寫要求或者說必須精確匹配呢? 註解@ConfigurationProperties對屬性綁定遵循relaxed bind rule【暫且翻譯爲鬆散綁定規則】,並不須要精確匹配。好比對屬性【app.username】,經過【app.userName】、【app.user-name】、【app.user_name】、【app.USER_NAME】、【app.USER-NAME】等均可匹配,咱們可理解爲模糊匹配。上述咱們看到時間值咱們聲明的是小寫,但最終翻譯成了大寫,可是對於上述貨幣而言,咱們必須定義成大寫,在配置文件中不能定義成小寫或者大小寫混用,好比在配置文件中咱們聲明其值爲usd,不然將拋出以下異常。ide

對於註解@Value而言,佔位符必須嚴格和配置文件中對應鍵一致,不然拋出沒法解析異常。到此咱們能夠知道若一個類中有不少字段,那麼必須在每個字段上都添加@Value註解,如此一來比較繁瑣,對少數字段仍是比較友好,其實呢應該推薦使用註解@ConfigurationProperties,由於少數字段映射咱們徹底可藉助註解@Environment接口獲取。一言以蔽之,咱們總結下註解@ConfigurationProperties和@Value的區別: @ConfigurationProperties用於使用POJO bean映射屬性,而註解@Value經過鍵注入特定的屬性值。this

深刻探討註解@ConfigurationProperties

上述咱們只是討論了註解@ConfigurationProperties的使用方式,接下來咱們來探討下該註解正確使用姿式,上述咱們在使用該註解時,咱們發現同時添加了註解@Configuration,要是咱們不添加會報錯以下:spa

此時又多出一個註解@EnableConfigurationProperties,難道是在使用註解@ConfigurationProperties時,必須添加該註解,說明咱們要啓用該註解或者添加註解@Component嗎?顯然不是這樣,使用註解@Configuration說明咱們要使用bean, 咱們知道註解@ConfigurationProperties是進行POJO映射,因此是乾淨的一個原始實體,徹底不用再添加其餘註解,這裏報錯咱們暫且無論,咱們改造以下:翻譯

package com.demo.springboot;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.Currency;
import java.util.concurrent.TimeUnit;

@ConfigurationProperties(prefix = "app")
public class SpringConfig {

    private int refreshRate;
    private TimeUnit refreshTimeUnit;
    private Currency tradeCurrency;

    public int getRefreshRate() {
        return refreshRate;
    }
    public void setRefreshRate(int refreshRate) {
        this.refreshRate = refreshRate;
    }
    public TimeUnit getRefreshTimeUnit() {
        return refreshTimeUnit;
    }
    public void setRefreshTimeUnit(TimeUnit refreshTimeUnit) {
        this.refreshTimeUnit = refreshTimeUnit;
    }
    public Currency getTradeCurrency() {
        return tradeCurrency;
    }
    public void setTradeCurrency(Currency tradeCurrency) {
        this.tradeCurrency = tradeCurrency;
    }

    @Override
    public String toString() {
        System.out.println();
        return "SpringConfig:{" +
                "refreshRate = '" + refreshRate + '\'' +
                ", refreshTimeUnit = '" + refreshTimeUnit + '\'' +
                ", tradeCurrency =  '" + tradeCurrency + '\'' +
                 '}';
    }
}

假設上述是讀取的是鏈接數據庫的相關配置,接下來咱們建立以下類:3d

package com.demo.springboot;

public class DbConnectionConfiguration {
      ......    
}

咱們建立上述類要鏈接數據庫並進行相關操做,此時則須要用到上述數據庫配置類,此時就要用到註解@EnableConfigurationProperties,經過添加該註解表示要查找並註冊註解爲@ConfigurationProperties做爲bean,同時呢咱們也要添加註解@Configuration提供進行數據源的bean,以下:

package com.demo.springboot;

import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableConfigurationProperties(SpringConfig.class)
public class DbConnectionConfiguration {

    private SpringConfig springConfig;

    public DbConnectionConfiguration(SpringConfig springConfig) {
        this.springConfig = springConfig;
    }

    @Bean
    public DataSource dataSource() {
       ......
    }
}

此時咱們將發現Spring.Config再也不報錯,由於上述咱們使用Spring.Config做爲了一個bean,不然在開始時,咱們看到報錯,立馬添加註解@Component,接下來運行將拋出Spring.Config已屢次被註解爲bean,以下:

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: ...... available: expected single matching bean but found 2: springConfig,app-com.demo.springboot.SpringConfig

 相信經過上述個人舉例,閱讀本文的您可以明白這幾者的區別所在了,在這裏呢,咱們能夠下一個結論: 註解@ConfigurationProperties用於將類與外部屬性配置文件綁定,由於其徹底屬於POJO,因此必須將Bean類與配置實體類隔離開。而在這種狀況下註解@Configuration用於建立配置POJO的Spring bean。@EnableConfigurationProperties用於在配置實體類和Spring配置之間建立綁定,以便在注入服務內部以後能夠輕鬆地檢索到對應屬性。

總結

本節咱們重點討論了註解@ConfigurationProperties的使用,對於批量屬性映射POJO,很明顯會經過註解@ConfigurationProperties操做,相對註解@Value而言,它更加靈活,我想這也是推薦使用該註解的緣由,好了,本節咱們到此爲止,感謝您的閱讀,咱們下節見。

相關文章
相關標籤/搜索