Spring Boot(07)——ConfigurationProperties介紹
ConfigurationProperties介紹
ConfigurationProperties是一個註解,可以標註在一個Class上,這樣Spring Boot會從Environment中獲取其屬性對應的屬性值給其進行注入。比如下面的程式碼定義中,Spring Boot在例項化TestConfigurationProperties這個bean時就會把從Environment中獲取屬性名為appName的屬性值賦給TestConfigurationProperties的appName屬性。
@ConfigurationProperties @Data public class TestConfigurationProperties{ private String appName; }
所以當你的application.properties檔案中定義了appName=Test
時就會把Test
賦值給TestConfigurationProperties物件的appName屬性。實際上下面的定義和appName=Test
是等價的。也就是說在從Environment中獲取屬性值繫結到ConfigurationProperties標註的物件上時,對大小寫是不敏感的,而且其中的-
和_
都會被剔除。
APPname=Test app-Name=Test app-name=Test app_name=Test
@ConfigurationProperties
標註的Class通常用於從Environment中繫結屬性值,然後供bean容器中的其它bean使用,通常是跟@Configuration
標註的Class一起使用,其內部會注入@ConfigurationProperties
標註的物件用來定義bean。如果你去檢視Spring Boot的AutoConfiguration包,你會發現裡面基本都是這樣的用法。單獨跟@Configuration
標註的Class一起使用時,通常還會在@Configuration
標註的Class上加上@EnableConfigurationProperties
@ConfigurationProperties
的配置類,這樣Spring Boot就會把它例項化為一個bean,然後在@Configuration
配置類中就可以進行依賴注入並進行使用了。以下程式碼就是一個簡單的示例。
@Configuration @EnableConfigurationProperties(TestConfigurationProperties.class) public class TestConfig { @Autowired private TestConfigurationProperties props; @Bean public Object initBean() { //使用注入的ConfigurationProperties標註的物件進行bean構造 return this.props.getAppName(); } }
當
@ConfigurationProperties
標註的Class本身就標註為一個bean定義時就不需要在@Configuration
標註的Class上使用@EnableConfigurationProperties
進行指定了,可以直接進行注入,因為它已經是一個bean了。
指定需要對映的字首
在application.properties檔案中定義的屬性通常不是單一名稱的屬性,而是以a.b.c.d
這種形式構成的屬性,多個層級之間以點分隔,從而形成不同的分類。這種屬性需要繫結到@ConfigurationProperties
標註的物件屬性上時可以指定一個通用的字首,然後只對去除字首之後的內容進行繫結。下面的程式碼指定了繫結屬性時的字首是test.config
,所以TestConfigurationProperties物件的username屬性將繫結配置檔案中的test.config.username
屬性,password屬性將匹配配置檔案中的test.config.password
屬性。
@ConfigurationProperties("test.config") @Data public class TestConfigurationProperties { private String username; private String password; }
當在application.properties檔案中進行了如下定義時,TestConfigurationProperties物件的username屬性繫結的值是u1
,password屬性繫結的值是p1
。
test.config.username=u1 test.config.password=p1
@ConfigurationProperties
中有一個屬性value用來指定字首,屬性prefix也可以用來指定字首。有一個ignoreInvalidFields
用來指定當需要繫結的屬性值不合法時是否需要忽略該屬性繫結,屬性不合法主要是指型別不匹配。比如需要繫結值的屬性定義的型別是int,通過自動繫結機制獲取到的屬性值是abc
,它就不能轉換為int。ignoreInvalidFields
預設是false
,即當出現屬性不合法時將不忽略,將丟擲異常。還有一個ignoreUnknownFields
屬性,用來指定當需要繫結值的屬性沒有找到對應的繫結屬性時是否將忽略,預設是true
。
級聯繫結
下面的程式碼中TestConfigurationProperties的inner屬性是一個物件,需要對其進行繫結時需要以.
進行級聯繫結。
@ConfigurationProperties("test.config") @Data public class TestConfigurationProperties { private Inner inner; @Data public static class Inner { private String username; private String password; } }
在application.properties檔案中進行如下定義會為TestConfigurationProperties物件的inner屬性繫結一個Inner物件,其username屬性的值是u1,password的值是p1。
test.config.inner.username=u1 test.config.inner.password=p1
在application.yml檔案中進行如下定義與上面的定義等價。
test.config.inner: username: u1 password: p1
繫結集合屬性
下面的程式碼中使用@ConfigurationProperties
標註的Class有一個List型別的屬性。
@ConfigurationProperties("test.config") @Data public class TestConfigurationProperties { private List<String> list; }
需要給List繫結值時,可以通過[index]
的形式指定值,下面的程式碼就定義了List中的三個元素,分別是ABC
、DEF
和GHI
。
test.config.list[0]=ABC test.config.list[1]=DEF test.config.list[2]=GHI
也可以使用英文逗號分隔List中的多個值,以下配置跟上面的配置是等價的。
test.config.list=ABC,DEF,GHI
Set、Array型別的屬性值繫結也可以使用類似的語法(索引和逗號分隔)。
在YAML配置檔案定義集合型別的值繫結時可以定義為如下這樣:
test.config.list: - ABC - DEF - GHI
它也可以使用逗號分隔的多個值。
test.config.list: ABC,DEF,GHI
如果需要繫結值的集合元素是一個物件怎麼辦呢?下面的程式碼中list屬性的元素型別就是一個Inner物件,其中Inner物件又有username和password兩個屬性。
@ConfigurationProperties("test.config") @Data public class TestConfigurationProperties { private List<Inner> list; @Data public static class Inner { private String username; private String password; } }
在application.properties檔案中進行如下定義可以為list屬性繫結兩個Inner物件,其中第一個物件的username屬性值為u1,password屬性值為p1;第二個物件的username屬性值為u2,password屬性值為p2。
test.config.list[0].username=u1 test.config.list[0].password=p1 test.config.list[1].username=u2 test.config.list[1].password=p2
在application.yml檔案中進行如下定義與上面的定義等價,可以達到相同的值繫結效果。
test.config.list: - username: u1 password: p1 - username: u2 password: p2
繫結Map屬性
下面的程式碼中擁有一個Map型別的map屬性,Key和Value都是String型別。
@ConfigurationProperties("test.config") @Data public class TestConfigurationProperties { private Map<String, String> map; }
需要給上面的map屬性繫結值時可以使用key=value
的形式,下面的配置會給map屬性繫結兩個元素,分別是key1對應value1,key2對應value2。
test.config.map.key1=value1 test.config.map.key2=value2
在application.yml檔案中使用YAML語法定義就更簡單了,以下定義等價於上面的定義。
test.config.map: key1: value1 key2: value2
如果需要繫結的Value是一個物件怎麼辦呢?比如map屬性的定義改為如下這樣:
@ConfigurationProperties("test.config") @Data public class TestConfigurationProperties { private Map<String, Inner> map; @Data public static class Inner { private String username; private String password; } }
在application.properties檔案中進行如下定義,會繫結兩個元素到map,第一個元素的Key是key1,Value是一個Inner物件,其username屬性的值是u1,password屬性的值是p1;第二個元素的Key是key2,Value的username屬性的值是u2,password屬性的值是p2。
test.config.map.key1.username=u1 test.config.map.key1.password=p1 test.config.map.key2.username=u2 test.config.map.key2.password=p2
在application.yml檔案中定義時,如下定義等價於上面的定義。
test.config.map: key1: username: u1 password: p1 key2: username: u2 password: p2
使用JSR303註解進行有效性校驗
可以對@ConfigurationProperties
標註的Class的屬性進行有效性校驗,要使校驗生效,需要在Class上新增@org.springframework.validation.annotation.Validated
,還需要Classpath下擁有JSR303 Validator的實現,比如Hibernate Validator,這樣Spring Boot在進行屬性值繫結後會校驗其合法性。下面的程式碼中就指定了name屬性不能為null或空字串,如果繫結後的值為空將丟擲異常。
@Validated @ConfigurationProperties("test.config") @Data public class TestConfigurationProperties { @NotBlank(message="引數test.config.name不能為空") private String name; }
如果需要進行屬性值繫結的屬性是一個物件,需要對該物件中的某個屬性進行合法性校驗,比如下面程式碼中需要對Inner物件中的username屬性進行非空校驗,則需要在inner屬性上加上@Valid
,同時在username屬性上加上@NotBlank
。
@Validated @ConfigurationProperties("test.config") @Data public class TestConfigurationProperties { @NotBlank(message="引數test.config.name不能為空") private String name; @Valid private Inner inner; @Data public static class Inner { @NotBlank(message="引數test.config.inner.username不能為空") private String username; private String password; } }
繫結屬性值到第三方jar中包含的Class
如果需要繫結屬性值到第三方jar中包含的Class物件,我們是無法直接在Class上加上@ConfigurationProperties
註解的,這時候可以在@Configuration
標註的Class中定義一個需要繫結值的Class型別的bean,然後在該方法上加上@ConfigurationProperties
。比如下面程式碼中通過initTestConfigurationProperties()
定義了一個TestConfigurationProperties型別的bean,在該方法上加上了@ConfigurationProperties
,Spring Boot就會為該bean進行屬性值繫結。
@Configuration public class TestConfig { @Bean @ConfigurationProperties("test.config") public TestConfigurationProperties initTestConfigurationProperties() { return new TestConfigurationProperties(); } }
參考文件
(注:本文是基於Spring Boot 2.0.3所寫)