使用 @Value("${property}") 註釋注入配置屬性有時會很麻煩,尤其是當你使用多個屬性或你的資料是分層的時候。
Spring Boot 引入了一個可替換的方案 —— @ConfigurationProperties 來注入屬性。
JavaBean 屬性繫結
@Data
@ConfigurationProperties("my.service")
public class MyProperties {
// 我們可以簡單地用一個值初始化一個欄位來定義一個預設值
private boolean enabled = true;
private InetAddress remoteAddress;
private final Security security = new Security();
@Data
public static class Security {
private String username;
private String password;
// 如果這個屬性配置的話,預設是“USER”
private List<String> roles = new ArrayList<>(Collections.singleton("USER"));
}
}
在配置檔案中進行如下配置:
my:
service:
enabled: true
remoteAddress: 127.0.0.1
security:
username: csx
password: passwoed
roles:
- role1
- role2
最後生成的 Bean 的屬性如下:
{
"enabled": true,
"remoteAddress": "127.0.0.1",
"security": {
"username": "csx",
"password": "passwoed",
"roles": [
"role1",
"role2"
]
}
}
以上的繫結當時需要提供預設的建構函式,以及get/setter方法。
並且不支援 JavaBean 中的靜態成員變數的資料繫結
另外,@ConfigurationProperties 還有兩個其他屬性。
@ConfigurationProperties( value = "my.service",
ignoreInvalidFields = false,
ignoreUnknownFields = false)
ignoreInvalidFields:是否忽略非法值,比如將一個字串 “foo” 賦值給 bool 值,不忽略的話會報啟動異常。
ignoreUnknownFields:對於多餘的配置是否會報異常。
建構函式繫結
有些情況下,我們需要繫結的 JavaBean 是不可變的(防止配置注入 Bean 以後,開發者在程式中錯誤地將配置改掉了)。這種情況下我們可以使用建構函式形式的繫結,只提供 getter 方法。
@Getter
@ConstructorBinding
@ConfigurationProperties("my.service")
public class MyProperties {
private boolean enabled;
private InetAddress remoteAddress;
private final Security security;
public MyProperties(boolean enabled, InetAddress remoteAddress, Security security) {
this.enabled = enabled;
this.remoteAddress = remoteAddress;
this.security = security;
}
@Getter
public static class Security {
private String username;
private String password;
private List<String> roles;
public Security(String username, String password, @DefaultValue("USER") List<String> roles) {
this.username = username;
this.password = password;
this.roles = roles;
}
}
}
@DefaultValue 可以指定預設值。
使用建構函式繫結的方式,只能 @EnableConfigurationProperties 或者 @ConfigurationPropertiesScan 的方式啟用 Bean。而不能使用 @Component、@Bean 或者 @Import 的方式進行資料繫結。
如果你的類有多個建構函式,可以直接指定使用哪個。
@ConstructorBinding
public MyProperties(boolean enabled, InetAddress remoteAddress, Security security) {
this.enabled = enabled;
this.remoteAddress = remoteAddress;
this.security = security;
}
啟用方式
方式一:新增 @Component 註解
上面的方式需要保證 MyProperties 能被 Spring 掃到。
@Data
@Component
@ConfigurationProperties("my.service")
public class MyProperties {
}
方式二:通過 @Bean 方法
@Configuration
public class ServiceConfig {
@Bean
public MyProperties myProperties(){
return new MyProperties();
}
}
方式三:@EnableConfigurationProperties(推薦)
@Configuration
@EnableConfigurationProperties(MyProperties.class)
public class ServiceConfig {
}
方式四:@ConfigurationPropertiesScan
@SpringBootApplication
@ConfigurationPropertiesScan({ "com.example.app", "com.example.another" })
public class MyApplication {
}
怎麼使用
我們通過配置在 Spring 容器中生成了配置 Bean,那麼需要怎麼使用他們呢?
@Service
public class MyService {
// 依賴注入
@Autowired
private MyProperties properties;
public void service(){
System.out.println(properties.getRemoteAddress());
}
}
@Service
public class MyService {
private MyProperties properties;
// 通過建構函式注入,一般推薦這種方式
public MyService(MyProperties properties) {
this.properties = properties;
}
public void service(){
System.out.println(properties.getRemoteAddress());
}
}
給第三方類繫結值
假如某些類不是你自己開發的,你也想使用 @ConfigurationProperties 的方式給他繫結值,那麼可以進行下面的方式進行配置。
@Configuration(proxyBeanMethods = false)
public class ThirdPartyConfiguration {
@Bean
@ConfigurationProperties(prefix = "another")
public AnotherComponent anotherComponent() {
return new AnotherComponent();
}
}
寬鬆繫結原則(Relaxed Binding)
所謂的寬鬆繫結原則是指:並不是 JavaBean 中的屬性必須要和配置檔案中的一致才能繫結資料,context-path 也能繫結到 contextPath 屬性上。下面舉個列子:
@ConfigurationProperties(prefix = "my.main-project.person")
public class MyPersonProperties {
private String firstName;
public String getFirstName() {
return this.firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
}
下面的幾種方式,都能將配置檔案或者環境變數中的值繫結到 firstName 上。
形式 | 使用場景 |
---|---|
my.main-project.person.first-name |
推薦使用在 .properties and .yml files. |
my.main-project.person.firstName |
Standard camel case syntax. |
my.main-project.person.first_name |
推薦使用在 .properties and .yml files. |
MY_MAINPROJECT_PERSON_FIRSTNAME |
推薦使用在系統環境變數讀取配置時使用 |
和 @Value 對比
@Value 是 Spring Framework 中的註解,而 @ConfigurationProperties 是在 Spring Boot 中引入的。