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();
}
}
當标注的Class本身就标注為一個bean定義時就不需要在
@ConfigurationProperties
标注的Class上使用
@Configuration
進行指定了,可以直接進行注入,因為它已經是一個bean了。
@EnableConfigurationProperties
指定需要映射的字首
在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
中有一個屬性value用來指定字首,屬性prefix也可以用來指定字首。有一個
@ConfigurationProperties
用來指定當需要綁定的屬性值不合法時是否需要忽略該屬性綁定,屬性不合法主要是指類型不比對。比如需要綁定值的屬性定義的類型是int,通過自動綁定機制擷取到的屬性值是
ignoreInvalidFields
,它就不能轉換為int。
abc
預設是
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();
}
}
參考文檔
https://docs.spring.io/spring-boot/docs/2.0.3.RELEASE/reference/html/boot-features-external-config.html#boot-features-external-config-typesafe-configuration-properties(注:本文是基于Spring Boot 2.0.3所寫)