SpringBoot 2.X課程學習 | 第六篇:挖掘配置檔案的祕密
一、兩種配置檔案獲取值的方式
因為普遍屬性比較簡單,可能複雜屬性有些小夥伴們不知道怎麼獲取。因此我將application.yml和application.properties兩種配置檔案中物件複雜屬性定義的內容列舉出來:
application.properties檔案:
#自定義list集合 person.lists=a,b,c #自定義map集合 person.maps.k1=va2 person.maps.k2=v2 #自定義person中的dog物件屬性 person.dog.name=毒瓦斯 person.dog.age=8
application.yml檔案:
#自定義map集合 #縮排方式 person: maps: k1: v2 k2: v3 #行內方式 person: maps:{k1: v2,k2: v3} #自定義陣列 #縮排方式 person lists: - 鐮刀灣 - 瓦斯的 #行內方式 person: lists:[鐮刀灣,瓦斯的] #自定義物件屬性 person: dog: name: awdwa age: 11
1、方式一 通過@ConfigurationProperties註解
@ConfigurationProperties註解作用是告訴springboot將本類中的所有屬性與配置檔案中的屬性進行繫結,它需要提供prefix屬性,可通過統一字首批量將類中屬性和配置檔案中屬性進行繫結,使用該方式的時候需要引入配置檔案處理器依賴:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency>
並且使用新增@Component、@Configuration或者@EnableConfigurationProperties註解,將類作為容器中的元件,才能使用容器中的功能。
示例程式碼如下:
package com.example.demo.entity;
import org.springframework.stereotype.Component;
@Component
@Data
public class Dog {
private String name;
private int age;
}
1.1、使用@Component註解
package com.example.demo.entity;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
@Component
@ConfigurationProperties(prefix = "person")
@Data
public class Person {
private Map<String,Object> maps;
private List<Object> lists;
private Dog dog;
}
1.2、使用@configuration註解:
package com.example.demo.entity;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
@configuration
@ConfigurationProperties(prefix = "person")
@Data
public class Person {
private Map<String,Object> maps;
private List<Object> lists;
private Dog dog;
}
1.3、使用@EnableConfigurationProperties註解
package com.example.demo.entity;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
@ConfigurationProperties(prefix = "person")
@Data
public class Person {
private Map<String,Object> maps;
private List<Object> lists;
private Dog dog;
}
@SpringBootApplication
@EnableConfigurationProperties(Person.class)
public class DemoApplication {
@Autowired
private Person person;
@RequestMapping(value = "/hello", method = RequestMethod.GET)
@ResponseBody
public String hello() {
System.out.println("person" + person);
return "hello world";
}
public static void main(String[] args) {
//SpringApplication.run(TestProperty1.class, args);
new SpringApplicationBuilder(DemoApplication.class).web(SERVLET).run(args);
}
}
2、方式二 通過@Value註解
@Value註解類似在原始spring專案在配置檔案中配置bean標籤,在bean標籤中配置了properties標籤,並提供value屬性值,例如:
<bean class="xxx">
<properties name="xxx" value=""/>
</bean>
@Value註解相當於這個properties標籤中的value屬性值。
使用@Value註解不能通過字首批量將類中所有屬性與配置檔案中特定屬性繫結,它支援使用${key}(從環境變數、配置檔案中獲取值)、#{SpEl}等。
比如:
@Value("${person.last-name}")
private String name;
@Value("#{11*2}") /**為spring表示式
private int age;
@Value("true")
private boolean flag;
將配置檔案中的屬性繫結到類中的屬性時,對於物件屬性,如果鍵包含除小寫字母數字字元或-以外的任何字元,則需要使用括號表示法,以便保留原始值。如果鍵未被[]包圍,則將刪除任何非字母數字或-的字元。比如map屬性:
#yml檔案寫法
#自定義map集合
person:
maps:
"[/key1]": value1
/key3: value3
k2: v2
#properties檔案寫法
#自定義map集合
person.maps.[/key1]=va2
person.maps./key3=v2
那麼使用註解獲取到的map集合內容為maps={/key1=va2, key3=v2}
二、@ConfigurationProperties和@Value註解不同
@ConfigurationProperties | @Value | |
功能 | 批量注入配置檔案中的屬性 | 只能一個一個的注入 |
鬆散繫結(Relaxed Binding) | 支援 | 不支援 |
SrEl表示式 | 不支援 | 支援 |
JSR303資料檢驗 | 支援 | 不支援 |
複雜型別封裝 | 支援 | 不支援 |
繫結類屬性是否提供set、get方法 | 是 | 否 |
2.1、鬆散繫結
比如類中定義了一個屬性,屬性名為firstName,如果使用@ConfigurationProperties,那麼配置檔案中,該屬性可以寫成如下形式:
person.firstName:使用標準方式
person.first-name:大寫用-,建議在.properties和.yml檔案中使用。
person.first_name:大寫用_,它是用於.properties和.yml檔案的可選格式。
PERSON.FIRST_NAME 大寫格式,建議在使用系統環境變數時使用。
但是如果使用@Value註解,那麼只能寫成@Value("${person.firstName}")。
每個屬性源的寬鬆繫結規則:
屬性源 | Simple | List |
Properties Files | Camel case(駝峰式), kebab case(短橫線), or underscore notation(下劃線符號) | 使用[]或逗號分隔值的標準列表語法 |
YAML Files | Camel case(駝峰式), kebab case(短橫線), or underscore notation(下劃線符號) | 標準yaml列表語法或逗號分隔值 |
Environment Variables (環境變數) |
以下劃線作為分隔符的大寫格式。“-”不應在屬性名中使用 | 由下劃線包圍的數字值,例如my_Acme_1_Other=my.Acme[1].Other |
System properties (系統屬性) |
Camel case(駝峰式), kebab case(短橫線), or underscore notation(下劃線符號) | 使用[]或逗號分隔值的標準列表語法 |
2.2、JSR303資料校驗
@ConfigurationProperties註解支援JSR303資料校驗,意味著進行資料校驗的屬性必須符合規則才給予通過,否則報錯。比如給類中的某個屬性新增@Email註解,則規定,該屬性值必須符合郵箱格式才進行通過。檢視程式碼:
@Validated
public class Person {
@Value("${person.last-name}")
@Email
private String name;
}
2.3、關於繫結類中的屬性是否需要提供set、get方法
這個情況只適應於使用@ConfigurationProperties註解。由於繫結是通過標準javaBean屬性,因此絕大情況下屬性都需要提供setter和getter方法,除以下情況可以省略setter方法:
- 集合或者陣列 可以通過索引(通常使用yaml)或使用單個逗號分隔值(屬性)訪問。對於陣列屬性,setter方法是強制的。我們建議始終為此類型別新增setter方法。如果初始化集合,請確保它不是不可變的。
- 初始化了巢狀的POJO屬性,例如:person類中有一個屬性:private Dog dog=new Dog();則不需要setter方法,但是是private Dog dog;則需要提供setter方法。如果希望繫結器使用其預設建構函式動態建立例項,則需要一個setter方法。
- 最後,只考慮標準的JavaBean屬性,不支援對靜態屬性的繫結。
三、配置檔案佔位符
springboot配置檔案中允許使用隨機數或者在配置檔案中引用前面配置過的屬性來作為佔位符。
比如使用隨機數的佔位符:
${random.int}
${random.long}
${random.value}
${random.uuid}
${random.int(10)}
${random.int[1024,65523]}
比如在檔案中引用前面配置過的屬性作為佔位符:
app.name=MyApp
app.decription=${app.name} is a SpringBoot Application
如果配置檔案上下文沒有該屬性時,我們隨便輸入一個屬性名,那麼它將會把這個屬性名打印出來,比如:
app.name=Myapp
app.decription=${MyProject} is a SpringBoot Application
那麼使用註解獲取app.decription這個屬性值時,列印的結果為:MyProject is a SpringBoot Application
我們還可以為這個配置檔案上下文都沒有的屬性值賦值。比如如下操作:
app.name=Myapp
app.decription=${MyProject:customProject} is a SpringBoot Application
那麼使用註解獲取app.decription這個屬性值時,列印的結果為:customProject is a SpringBoot Application