【基礎系列】ConfigurationProperties 配置綁定中那些你不知道的事情
在 SpringBoot 項目中,獲取配置屬性能夠說是一個很是簡單的事情,將配置寫在aplication.yml
文件以後,咱們就能夠直接經過@Value
註解來綁定並獲取;此外咱們也能夠將一個結構化的配置,藉助@ConfigurationPorperties
綁定到一個 POJO,而後供項目使用,那麼在使用它的時候,不知是否有想過java
@ConfigurationPorperties
修飾的類如何生效若是上面這些都已經瞭然於心,那麼本文的幫助將不會特別大;若是對此有所疑問,接下來將逐一進行解惑python
<!-- more -->git
本項目藉助SpringBoot 2.2.1.RELEASE
+ maven 3.5.3
+ IDEA
進行開發github
下面是核心的pom.xml
(源碼能夠再文末獲取)spring
<!-- 這個依賴是幹嗎的,後文會介紹 --> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> </dependency> </dependencies>
假定咱們如今自定義一個功能模塊,裏面有一些咱們自定義的參數,支持經過 yaml 配置文件的方式注入json
首先咱們能夠先定義一個配置類 BindConfig
bash
@Data @ConfigurationProperties(prefix = "hhui.bind") public class BindConfig { private String name; private Integer age; private List<String> list; private Map<String, String> map; }
請注意上面的註解中,prefix = hhui.bind
,簡單來說就是會讀取配置文件中,前綴爲 hhui.bind
的屬性,而後依次賦值到這個類中微信
BindConfig.name = hhui.bind.name
BindConfig.age = hhui.bind.age
對應的配置文件以下maven
hhui: bind: name: YiHui age: 18 list: - java - c - python map: wechat: 小灰灰blog blogs: http://blog.hhui.top git: http://github.com/liuyueyi
注意事項ide
@Data
省略了 Setter 方法的顯示聲明而已類的屬性名與配置文件中的配置名要求匹配
關於上面最後一點,也就代表咱們能夠在自動 AutoConfiguration 類中,聲明一個內部類來綁定配置信息,以下
@Configuration @EnableConfigurationProperties({AutoConfiguration.BindConfig.class}) public class AutoConfiguration { @Data @ConfigurationProperties(prefix = "hhui.bind") static class BindConfig { private String name; private Integer age; private List<String> list; private Map<String, String> map; } }
咱們經過@ConfigurationProperties
修飾配置類以後,是否直接會生效呢?一般來說,讓它生效有下面三種方式
@Component
等註解修飾方式直接在配置類上添加@Component
, @Configuration
等註解,讓 Spring 容器掃描並加載它
@Data @Component @ConfigurationProperties(prefix = "hhui.bind") public class BindConfig { }
使用這種方式時,須要注意配置類在自動掃描的包路徑下,不然可能不會被掃描(主要是做爲第三方 jar 包提供服務時,可能出現掃描不到的問題)
@Bean
註冊把它當成一個普通的 bean,藉助 bean 註冊的方式來實現,也是一個可選的方案,通常的實現方式以下
@Configuration public class AutoConfiguration { @Bean public BindConfig bindConfig() { return new BindConfig(); } }
@EnableConfigurationProperties
方式在配置類上,添加這個註解以後,能夠實現配置註冊,通常常見的使用姿式如
@EnableConfigurationProperties({BindConfig.class}) @Configuration public class AutoConfiguration { }
上面三種註冊方式,前面兩種的思路是將配置類做爲 bean,第三種實現思路和主動註冊 bean 一致(因此想實現主動註冊 bean,能夠考慮它的實現邏輯)
若是咱們在配置中,一個原本但願接收 int 類型的參數,結果實際上填了一個非整形,會怎樣?
好比前面的配置類,咱們實際的配置文件將age
填 18y,來看一下最終會發生什麼事情
hhui: bind: Name: YiHui AGE: 18y list: - java - c - python map: wechat: 小灰灰blog blogs: http://blog.hhui.top git: http://github.com/liuyueyi
簡單演示,直接在啓動類中測試一下會如何
@SpringBootApplication public class Application { public Application(BindConfig config) { System.out.println(config); } public static void main(String[] args) { SpringApplication.run(Application.class); } }
參數異常以後,直接啓動失敗,若是對參數的要求沒有那麼嚴格,即容許失敗,咱們能夠經過設置ignoreInvalidFields = true
@Data @ConfigurationProperties(prefix = "hhui.bind", ignoreInvalidFields = true) public class BindConfig { }
再次執行以後,會發現正常啓動,輸出以下
BindConfig(name=YiHui, age=null, list=[java, c, python], map={wechat=小灰灰blog, blogs=http://blog.hhui.top, git=http://github.com/liuyueyi})
注意查看上面的 age,由於傳入的參數非法,因此是 null
說明
結合默認值 + ignoreInvalidFields
方式來支持配置的最大可用性:
@Data @ConfigurationProperties(prefix = "hhui.bind", ignoreInvalidFields = true) public class BindConfig { private String name; private Integer age = 18; private List<String> list; private Map<String, String> map; }
再次執行輸出如
BindConfig(name=YiHui, age=18, list=[java, c, python], map={wechat=小灰灰blog, blogs=http://blog.hhui.top, git=http://github.com/liuyueyi}, mainPwd=Pwd(user=一灰灰blog, pwd=yihuihui, code=9))
常見的配置除了基本類型以外,能嵌套自定義對象麼,非基本類型又能夠如何解析呢?
咱們新定義一個 Pwd 類
@Data public class Pwd { private String user; private String pwd; private Integer code; }
而後擴展一下BindConfig
@Data @ConfigurationProperties(prefix = "hhui.bind", ignoreInvalidFields = true) public class BindConfig { private String name; private Integer age = 18; private List<String> list; private Map<String, String> map; private Pwd mainPwd; }
這個時候 mainPwd 對應的 yaml 配置文件能夠以下設置
hhui: bind: Name: YiHui AGE: 1h list: - java - c - python map: wechat: 小灰灰blog blogs: http://blog.hhui.top git: http://github.com/liuyueyi # 下面這個對應的是 BindConfg.mainPwd; 能夠寫成 main_pwd也能夠寫成mainPwd main_pwd: user: 一灰灰blog pwd: yihuihui code: 9
從上面的介紹也能夠看出,對於自定義的 POJO 類是支持的,使用姿式也沒什麼區別
此外,對於 List 和 Map 的使用也給出了實例
上面咱們自定義的Pwd
類,主要藉助setter
方法,將匹配的屬性塞入進去;若是個人配置就是一個 json 串,能夠注入到一個 POJO 類麼
hhui: bind: Jwt: '{"token": "11111111123", "timestamp": 1610880489123}'
對應的 Jwt 類以下
@Data public class Jwt { private String token; private Long timestamp; }
這個時候如想實現上面的配置解析,能夠經過實現org.springframework.core.convert.converter.Converter
接口來支持,並經過@ConfigurationPropertiesBinding
註解來代表這是個配置屬性轉換類,不加這個註解會不生效哦
@Component @ConfigurationPropertiesBinding public class JwtConverter implements Converter<String, Jwt> { @Override public Jwt convert(String source) { return JSONObject.parseObject(source, Jwt.class); } }
說明
使用自定義的配置解析規則時,注意兩點
Converter
@ConfigurationPropertiesBinding
修飾註解Spring 提供了一些默認的配置解析規則,如
文件大小DataSize
持續時間Duration
一個配置類,對應的類中沒有這個屬性會怎樣?
如針對前面的BindConfig
,沒有notExist
這個屬性,可是配置文件中,卻加上了這個
hhui: bind: notExist: true
實測以後,發現沒有任何影響,經過查看@ConfigurationProperties
註解的成員,發現能夠設置ignoreUnknownFields=false
,從字面上表示出現了未能識別的成員,不會略錯誤,可是在實際測試中,並無生效
參數校驗能夠說比較經常使用的 case 了,好比前面的配置age
,基本上不會容許這個參數能是負數,如須要對參數進行校驗,咱們能夠藉助@Validated
來實現校驗
添加 pom 依賴
<dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> </dependency>
而後再配置類上添加@Validated
,而後就能夠在須要校驗的字段上添加對應的限制
@Data @Validated @ConfigurationProperties(prefix = "hhui.bind", ignoreInvalidFields = true, ignoreUnknownFields = false) public class BindConfig { @Min(13) @Max(66) private Integer age = 18; }
若是咱們將 age 參數設置不知足上面的條件
hhui: bind: age: 10
再次測試會發現報以下錯誤
平時在 Spring 開發過程當中,在 yaml 文件中添加配置時,配合 idea 有很是友好的提示,能夠很是友好的補全參數配置
那麼咱們自定義的參數想實現這個效果應該怎麼作呢?
添加文章最開頭的依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> </dependency>
添加上面的依賴以後,打包mvn clean package
,而後會發如今 META-INF 下面有個spring-configuration-metadata.json
{ "groups": [ { "name": "hhui.bind", "type": "com.git.hui.boot.bind.config.BindConfig", "sourceType": "com.git.hui.boot.bind.config.BindConfig" } ], "properties": [ { "name": "hhui.bind.age", "type": "java.lang.Integer", "sourceType": "com.git.hui.boot.bind.config.BindConfig", "defaultValue": 18 }, { "name": "hhui.bind.jwt", "type": "com.git.hui.boot.bind.config.Jwt", "sourceType": "com.git.hui.boot.bind.config.BindConfig" }, { "name": "hhui.bind.list", "type": "java.util.List<java.lang.String>", "sourceType": "com.git.hui.boot.bind.config.BindConfig" }, { "name": "hhui.bind.main-pwd", "type": "com.git.hui.boot.bind.config.Pwd", "sourceType": "com.git.hui.boot.bind.config.BindConfig" }, { "name": "hhui.bind.map", "type": "java.util.Map<java.lang.String,java.lang.String>", "sourceType": "com.git.hui.boot.bind.config.BindConfig" }, { "name": "hhui.bind.name", "type": "java.lang.String", "sourceType": "com.git.hui.boot.bind.config.BindConfig" } ], "hints": [] }
而後自動補全就有了
說明
idea 推薦添加插件Spring Assistant
,支持很是友好的配置注入
本文介紹了@ConfigurationProperties
修飾 POJO 類,實現配置的綁定,能夠經過將這個類聲明爲一個普通 bean 的方式進行註冊,也能夠藉助@EnableConfigurationProperties
來註冊
在配置參數時,須要注意若是參數類型不一致,會致使項目啓動失敗;能夠經過設置ConfigurationProperties#ignoreInvalidFields = true
,來避免這種場景
經過實現接口Converter
+ @ConfigurationPropertiesBinding
來自定義參數解析轉換規則,能夠實現各路姿式的參數解析
配置的自動提示支持也比較簡單,添加org.springframework.boot:spring-boot-configuration-processor
依賴,打包以後在 META-INF 中會多一個 json 文件spring-configuration-metadata.json
項目源碼
系列博文
盡信書則不如,以上內容,純屬一家之言,因我的能力有限,不免有疏漏和錯誤之處,如發現 bug 或者有更好的建議,歡迎批評指正,不吝感激
下面一灰灰的我的博客,記錄全部學習和工做中的博文,歡迎你們前去逛逛