3.配置繫結
所謂“配置繫結”就是把配置檔案中的值與 JavaBean 中對應的屬性進行繫結。通常,我們會把一些配置資訊(例如,資料庫配置)放在配置檔案中,然後通過 Java 程式碼去讀取該配置檔案,並且把配置檔案中指定的配置封裝到 JavaBean(實體類) 中。
SpringBoot 提供了以下 2 種方式進行配置繫結:
- 使用 @ConfigurationProperties 註解
- 使用 @Value 註解
一、@ConfigurationProperties
通過 Spring Boot 提供的 @ConfigurationProperties 註解,可以將全域性配置檔案中的配置資料繫結到 JavaBean 中。下面我們以 Spring Boot 專案helloworld 為例,演示如何通過@ConfigurationProperties 註解進行配置繫結。
1. 在 helloworld 的全域性配置檔案 application.yml 中新增以下自定義屬性。
person:
lastName: 張三
age: 18
boss: false
birth: 1990/12/12
maps: { k1: v1,k2: 12 }
lists:
‐ lisi
‐ zhaoliu
dog:
name: 迪迪
age: 5
2. 在 helloworld 專案的 net.biancheng.www.bean 中建立一個名為 Person 的實體類,並將配置檔案中的屬性對映到這個實體類上,程式碼如下。
package net.biancheng.www.bean; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; import java.util.Date; import java.util.List; import java.util.Map; /** * 將配置檔案中配置的每一個屬性的值,對映到這個元件中 * * @ConfigurationProperties:告訴 SpringBoot 將本類中的所有屬性和配置檔案中相關的配置進行繫結; * prefix = "person":配置檔案中哪個下面的所有屬性進行一一對映 * * 只有這個元件是容器中的元件,才能使用容器提供的@ConfigurationProperties功能; */ @Component @ConfigurationProperties(prefix = "person") public class Person { private String lastName; private Integer age; private Boolean boss; private Date birth; private Map<String, Object> maps; private List<Object> lists; private Dog dog; public Person() { } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Boolean getBoss() { return boss; } public void setBoss(Boolean boss) { this.boss = boss; } public Date getBirth() { return birth; } public void setBirth(Date birth) { this.birth = birth; } public Map<String, Object> getMaps() { return maps; } public void setMaps(Map<String, Object> maps) { this.maps = maps; } public List<Object> getLists() { return lists; } public void setLists(List<Object> lists) { this.lists = lists; } public Dog getDog() { return dog; } public void setDog(Dog dog) { this.dog = dog; } public Person(String lastName, Integer age, Boolean boss, Date birth, Map<String, Object> maps, List<Object> lists, Dog dog) { this.lastName = lastName; this.age = age; this.boss = boss; this.birth = birth; this.maps = maps; this.lists = lists; this.dog = dog; } @Override public String toString() { return "Person{" + "lastName='" + lastName + '\'' + ", age=" + age + ", boss=" + boss + ", birth=" + birth + ", maps=" + maps + ", lists=" + lists + ", dog=" + dog + '}'; } }
注意:
- 只有在容器中的元件,才會擁有 SpringBoot 提供的強大功能。如果我們想要使用 @ConfigurationProperties 註解進行配置繫結,那麼首先就要保證該對 JavaBean 物件在 IoC 容器中,所以需要用到 @Component 註解來新增元件到容器中。
- JavaBean 上使用了註解 @ConfigurationProperties(prefix = "person") ,它表示將這個 JavaBean 中的所有屬性與配置檔案中以“person”為字首的配置進行繫結。
2. 在 net.biancheng.www.bean 中,建立一個名為 Dog 的 JavaBean,程式碼如下。
package net.biancheng.www.bean;
public class Dog {
private String name;
private String age;
public Dog() {
}
public Dog(String name, String age) {
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(String age) {
this.age = age;
}
public String getName() {
return name;
}
public String getAge() {
return age;
}
}
3. 修改HelloController 的程式碼,在瀏覽器中展示配置檔案中各個屬性值,程式碼如下。
package net.biancheng.www.controller;
import net.biancheng.www.bean.Person;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class HelloController {
@Autowired
private Person person;
@ResponseBody
@RequestMapping("/hello")
public Person hello() {
return person;
}
}
4. 重啟專案,使用瀏覽器訪問 “http://localhost:8081/hello”,結果如下圖。
圖3:Spring Boot 讀取自定義配置
二、@Value
當我們只需要讀取配置檔案中的某一個配置時,可以通過 @Value 註解獲取。
1. 以 Spring Boot 專案 helloworld 為例,修改實體類 Person 中的程式碼,使用 @Value 註解進行配置繫結,程式碼如下。
package net.biancheng.www.bean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
import java.util.Map;
@Component
public class Person {
@Value("${person.lastName}")
private String lastName;
@Value("${person.age}")
private Integer age;
@Value("${person.boss}")
private Boolean boss;
@Value("${person.birth}")
private Date birth;
private Map<String, Object> maps;
private List<Object> lists;
private Dog dog;
public Person() {
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Boolean getBoss() {
return boss;
}
public void setBoss(Boolean boss) {
this.boss = boss;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
public Map<String, Object> getMaps() {
return maps;
}
public void setMaps(Map<String, Object> maps) {
this.maps = maps;
}
public List<Object> getLists() {
return lists;
}
public void setLists(List<Object> lists) {
this.lists = lists;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
public Person(String lastName, Integer age, Boolean boss, Date birth, Map<String, Object> maps, List<Object> lists, Dog dog) {
this.lastName = lastName;
this.age = age;
this.boss = boss;
this.birth = birth;
this.maps = maps;
this.lists = lists;
this.dog = dog;
}
@Override
public String toString() {
return "Person{" +
"lastName='" + lastName + '\'' +
", age=" + age +
", boss=" + boss +
", birth=" + birth +
", maps=" + maps +
", lists=" + lists +
", dog=" + dog +
'}';
}
}
2. 重啟專案,使用瀏覽器訪問 “http://localhost:8081/hello”,結果如下圖。
圖4:Spring Boot @Value 註解讀取配置檔案值
三、@Value 與 @ConfigurationProperties 對比
@Value 和 @ConfigurationProperties 註解都能讀取配置檔案中的屬性值並繫結到 JavaBean 中,但兩者存在以下不同。
1. 使用位置不同
- @ConfigurationProperties:標註在 JavaBean 的類名上;
- @Value:標註在 JavaBean 的屬性上。
2. 功能不同
- @ConfigurationProperties:用於批量繫結配置檔案中的配置;
- @Value:只能一個一個的指定需要繫結的配置。
3. 鬆散繫結支援不同
@ConfigurationProperties:支援鬆散繫結(鬆散語法),例如實體類 Person 中有一個屬性為 lastName,那麼配置檔案中的屬性名支援以下寫法:
- person.firstName
- person.first-name
- person.first_name
- PERSON_FIRST_NAME
@Vaule:不支援鬆散繫結。
4. SpEL 支援不同
- @ConfigurationProperties:不支援 SpEL 表示式;
- @Value:支援 SpEL 表示式。
5. 複雜型別封裝
- @ConfigurationProperties:支援所有型別資料的封裝,例如 Map、List、Set、以及物件等;
- @Value:只支援基本資料型別的封裝,例如字串、布林值、整數等型別。
6. 應用場景不同
@Value 和 @ConfigurationProperties 兩個註解之間,並沒有明顯的優劣之分,它們只是適合的應用場景不同而已。
- 若只是獲取配置檔案中的某項值,則推薦使用 @Value 註解;
- 若專門編寫了一個 JavaBean 來和配置檔案進行對映,則建議使用 @ConfigurationProperties 註解。
我們在選用時,根據實際應用場景選擇合適的註解能達到事半功倍的效果。
四、@PropertySource
如果將所有的配置都集中到 application.properties 或 application.yml 中,那麼這個配置檔案會十分的臃腫且難以維護,因此我們通常會將與 Spring Boot 無關的配置(例如自定義配置)提取出來,寫在一個單獨的配置檔案中,並在對應的 JavaBean 上使用 @PropertySource 註解指向該配置檔案。
1. 以 helloworld 為例,將與 person 相關的自定義配置移動到 src/main/resources 下的 person.properties 中(注意,必須把 application.properties 或 application.yml 中的相關配置刪除),如下圖。
圖5:person.properties
person.properties 的配置如下。
person.last-name=李四
person.age=12
person.birth=2000/12/15
person.boss=false
person.maps.k1=v1
person.maps.k2=14
person.lists=a,b,c
person.dog.name=dog
person.dog.age=2
2. 在 Person 使用 @PropertySource 註解指向 person.properties,程式碼如下。
package net.biancheng.www.bean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
import java.util.Map;
@PropertySource(value = "classpath:person.properties")//指向對應的配置檔案
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
private String lastName;
private Integer age;
private Boolean boss;
private Date birth;
private Map<String, Object> maps;
private List<Object> lists;
private Dog dog;
public Person() {
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Boolean getBoss() {
return boss;
}
public void setBoss(Boolean boss) {
this.boss = boss;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
public Map<String, Object> getMaps() {
return maps;
}
public void setMaps(Map<String, Object> maps) {
this.maps = maps;
}
public List<Object> getLists() {
return lists;
}
public void setLists(List<Object> lists) {
this.lists = lists;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
public Person(String lastName, Integer age, Boolean boss, Date birth, Map<String, Object> maps, List<Object> lists, Dog dog) {
this.lastName = lastName;
this.age = age;
this.boss = boss;
this.birth = birth;
this.maps = maps;
this.lists = lists;
this.dog = dog;
}
@Override
public String toString() {
return "Person{" +
"lastName='" + lastName + '\'' +
", age=" + age +
", boss=" + boss +
", birth=" + birth +
", maps=" + maps +
", lists=" + lists +
", dog=" + dog +
'}';
}
}
3. 重啟專案,使用瀏覽器訪問 “http://localhost:8081/hello”,結果如下圖。
圖6:Spring Boot 將 person.properties 的屬性注入