1. 程式人生 > 其它 >3.配置繫結

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 的屬性注入