代碼是寫給人看的,不是寫給機器看的,只是順便計算機能夠執行而已html
——《計算機程序的構造和解釋(SICP)》java
導言
在咱們的項目裏常常會出現須要添加自定義配置的應用場景,例如某個開關變量,在測試環境打開,在生產環境不打開,一般咱們都會使用下面的代碼來實現,而後在Spring Boot配置文件中添加這個key和Valuespring
Application.java:json
application.properties數組
或者是沒有使用@Value而直接在XML中使用咱們配置的屬性值app
application.xmlspring-boot
這樣的代碼和配置在Spring Boot項目中能夠正常啓動並讀取配置,可是在咱們的IDE中卻不會爲咱們提示配置的類型和代碼補全。當咱們有新同事到來,或者是須要爲配置文件添加新的環境的支持的時候,咱們很容易會把配置文件的Key拼錯,或者Value的值與咱們的變量類型並不兼容(實際上真的發生過這樣的問題致使項目啓動失敗)。測試
可是在咱們使用Spring Boot提供的配置的時候,IDE老是能爲咱們自動補全,告訴咱們這個配置的變量類型,甚至是給咱們把這個配置的描述顯示出來。url
咱們是否也能夠爲咱們本身寫的配置添加這樣的IDE支持呢?spa
配置項元數據(Configuration Metadata)
Spring Boot的Jar文件包含元數據文件,這些文件提供了咱們所須要的配置屬性的詳細信息。IDE經過讀取這些元數據文件,而後在使用application.properties或application.yml的時候提供上下文信息和代碼補全。那麼只要知道如何編寫並存放配置項元數據信息文件,咱們也可讓IDE知道如何爲咱們的自定義配置提供上下文信息。
元數據格式
Spring Boot項目的配置項元數據文件都放在META-INF/spring-configuration-metadata.json中。下圖是當咱們配置好Spring Boot項目後默認使用的Spring Boot自動配置的配置項元數據存放的位置
配置項元數據文件按照groups, properties和hints組織。properties下的每一個property都是程序中須要使用的配置項的key值,好比server.port是服務啓動後的端口號。而咱們能夠將一些property按照某些規則組合起來,這個組合就是group(一般咱們並不須要爲properties組織對應的group)。而hints是爲咱們的配置項提供額外的信息,好比時區time.zone支持Asia/Shanghai,咱們能夠爲它提供"Asia/Shanghai"的hint。
properties的參數
名稱 | 類型 | 描述 |
---|---|---|
name | String | 屬性的全名。名稱是小寫字母以句點分割。此屬性是必須的 |
type | String | 屬性的數據類型的完整簽名(java.lang.String),若是是範型的話還應當包含完整的範型參數(java.util.List<java.lang.String>)。爲了保證一致性,須要使用包裝類型來替代基本類型。此屬性不是必須的,可是沒法獲得類型診斷的支持。 |
hints的參數
名稱 | 類型 | 描述 |
---|---|---|
name | String | 該提示所引用的屬性的全稱,和properties的name參數相同。此屬性是必須的 |
values | ValueHint[] | ValueHint對象定義的有效值列表。每一個條目都定義該值,而且能夠具備描述 |
ValueHint的參數
名稱 | 類型 | 描述 |
---|---|---|
value | Object | property給定的類型的有效值,若是property的類型是數組,那麼它也能夠是值的數組。此屬性是必須的。若是是Map類型的屬性,可使用.keys和.values來指定對應的有效值。 |
description | String | 和properties的description相同,提示給用戶的簡短描述。此屬性不是必須的。 |
這裏只展現了咱們經常使用的參數,關於配置項元數據文件格式的詳細信息能夠看Spring Boot的官方文檔(https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-configuration-metadata.html#configuration-metadata-format)
爲自定義配置編寫配置項元數據
接下來咱們將對值、數組場景編寫對應的配置項元數據,併爲這些配置項添加提示(Talk is cheap,show me the code)
在IDE中實際使用的效果
不過這種方式雖然好,可是須要咱們寫不少的JSON配置來告訴IDE該如何進行代碼補全和附加上下文信息,配置和代碼仍是處於分離的狀態,若是能經過寫一個配置類,直接經過這個類和它的註釋就能爲咱們作到IDE支持就行了——Spring Boot開發者也是這麼想的。
爲代碼自動生成配置項元數據
首先咱們要改掉隨處使用@Value的習慣,使用專門的數據類來存放咱們的配置項
接下來咱們建立一個Bean,讓Spring Boot容器來接管這個類的實例
經過@ConfigurationProperties註解,Spring就會自動將配置注入到咱們的配置Bean中,可是此時IDE還沒法識別咱們添加的自動配置,咱們須要添加Spring Boot的註解處理器(annotation processor,從Java 1.6開始支持的特性)
添加註解處理器後從新編譯,咱們就會在target目錄下看到自動生成的META-INF/spring-configuration-metadata.json
裏面的內容基本就是咱們以前本身手動輸入的內容,只是受於Java代碼表達信息的侷限性,沒有辦法生成hints信息。其中sourceType和sourceMethod屬性還能夠幫助IDE跳轉到咱們聲明這個配置的類和方法
若是咱們想要讓咱們使用代碼生成的配置類也能添加提示的話,能夠在咱們的META-INF目錄下添加additional-spring-configuration-metadata.json文件,將hints寫到這個文件裏面
這樣Spring Boot在編譯的時候就會將咱們的提示信息合併到配置信息元數據文件裏面了
雖然這些工做不會增長代碼的運行效率,可是讓咱們的配置集中起來並有IDE的加成,會讓咱們更改配置的時候更加有信心。正如開頭所說的,代碼是寫給人看的,不是寫給機器看的,只是順便計算機能夠執行而已。