Spring Boot 配置文件及自動配置原理
前言
前面我們說到,springboot使用了特定的方式來進行配置,即約定優於配置
(Spring Boot在底層已經把配置都約定(配置)
好了)的設計範式,從而使開發人員不再需要定義樣板化的配置,就可以正常運行一個spring程序。但是在一些特殊的情況下,我們需要偏離springboot中的約定(默認配置),這時我們就需要自定義一些配置用來修改springboot的默認配置。
一、配置文件的兩種類型
Spring Boot 爲我們提供一個名稱爲 application 的全局配置文件,支持兩種類型,一種properties類型,一種YAML類型,用於修改 Spring Boot 的默認配置。
兩種配置文件
application.properties
application.yaml 或者 application.yml
在上一篇文章中我們可以看到,當我們創建一個springboot項目的時候,系統默認會爲我們在 src/main/java/resources 目錄下創建一個 application.properties 配置文件。
因爲我個人更喜歡 yaml 格式的配置文件,所以一般在創建好項目後我會將 application.properties 修改爲 application.yml。可能我們會在不同的項目中看見兩種不同的配置文件格式,實際上兩種格式都是OK的。我會在後面詳細介紹一下 YAML語言,關於properties就展開來說了。
二、YAML 語言入門
YAML是 YAML Ain't Markup Language
(YAML 不是一種標記語言)的遞歸縮寫 ,YAML還可以理解爲 Yet Another Markup Language
(仍是一種標記語言)。
YAML 是專門用來寫配置文件的語言,以數據爲中心
,非常簡潔和強大,比json、xml等更適合做配置文件。
1、基本語法
- 採用 key: value方式表示數據(冒號後面需要空格隔開)
- 大小寫敏感
- 使用縮進表示層級關係
- 縮進不允許使用tab,只允許空格
- 縮進的空格數不重要,只要相同層級的元素左對齊即可
- '#'表示註釋
需要注意的是,YMAL語言只支持單行註釋,從 #
開始一直到行尾,都會被解析器忽略。
2、數據類型
YAML 支持以下幾種數據類型:
- 純量(scalars):單個的、不可再分的值(數字,字符串,布爾。。。)
- 數組:一組按次序排列的值,又稱爲序列(sequence) / 列表(list)
- 對象:鍵值對的集合,又稱爲映射(mapping)/ 哈希(hashes) / 字典(dictionary)
下面我們分別對這三種數據類型進行詳細的講解,在這之前先給大家推薦一個在線編輯 yaml 的網站吧,可以將我下面的代碼粘進去看結果。不是打廣告啊,我這博客有沒有人看還不一定,在線卑微。。。在線編輯 yaml
2.1、YAML 純量
純量是最基本的,不可再分的值,包括:
-
字符串
# 字符串是最常見一種數據類型,默認不用加上單引號或者雙引號 content: 好好學習,天天向上 # == "好好學習,天天向上" # 如果字符串之中包含空格或特殊字符,需要放在引號之中,其中雙引號不會轉義字符串,而單引號會 content: "好好學習\n天天向上" # == "好好學習\n天天向上",會進行換行 content: '好好學習\n天天向上' # == "好好學習\\n天天向上",不會換行 # 單引號之中如果還有單引號,必須連續使用兩個單引號轉義 content: 'YAML Ain''t Markup Language' # == "YAML Ain't Markup Language" # 字符串可以拆成多行,換行符會被轉化成一個空格(轉義第二行開始,只需要一個空格) content: 小明 是一個 大帥哥,誰贊同?誰反對? # == "小明 是一個 大帥哥,誰贊同?誰反對?" # 多行字符串可以使用 | 保留換行符,也可以使用 > 摺疊換行 content: | # == "小明\n是一個\n大帥哥,誰贊同?誰反對?\n" 小明 是一個 大帥哥,誰贊同?誰反對? content: > # == "小明 是一個 大帥哥,誰贊同?誰反對?\n" 小明 是一個 大帥哥,誰贊同?誰反對? # 可以使用 |+ 保留文字塊末尾的換行,也可以使用 |— 刪除字符串末尾的換行 content: |+ # == "小明\n是一個\n大帥哥,誰贊同?誰反對?\n" 小明 是一個 大帥哥,誰贊同?誰反對? content: |- # == "小明\n是一個\n大帥哥,誰贊同?誰反對?" 小明 是一個 大帥哥,誰贊同?誰反對? # 字符串之中可以插入 HTML content: | # == "<p style=\"color: red\">\n 段落\n</p>\n" <p style="color: red"> 段落 </p>
看完這麼一大串是不是感覺有點麻煩。。。其實在實際的開發中,我們只會用到最基本的,就我個人而言,引號也就是在配置日誌格式和顏色時用到了,後面的換行,換行符什麼的,我是一個也沒用過。。。
-
布爾值
# 布爾值用true和false表示 falg: true isSuccess: false
-
整數、浮點數
# 數值直接以字面量的形式表示 age: 20 age: 0b1010_0111_0100_1010_1110 #二進制表示
-
Null
# null用 ~ 表示 string: ~ # == "string": null
-
日期、時間
# 日期和時間都是採用ISO8601的格式表示的 # 日期格式爲 yyyy-MM-dd createDate: 2020-06-24 # 轉換爲json爲 {"createDate": "2020-06-24T00:00:00.000Z"} # 時間格式爲 時間和日期之間使用T連接,最後使用 +、-(這裏不是加減號,是連字符)代表時區 datetime: 2020-06-24T22:00:00-08:00 # 轉換爲json爲 {"datetime": "2020-06-25T06:00:00.000Z"} datetime: 2020-06-24T22:00:00+08:00 # 轉換爲json爲 {"datetime": "2020-06-24T14:00:00.000Z"} # 從上面的例子可以看出 連字符前面的時間爲默認的 0 時區,其後 -08:00 則表示爲西八區,而我國則在東八區,用 +08:00 表示
2.2、數組
在yaml中,以 -
開頭的行則表示成一個數組,例:
calss:
- xiaoming
- xiaohong
- xiaoxiao # == ['xiaoming', 'xiaohong', 'xiaoxiao']
同時,yaml 還支持多維數組,例:
calss:
-
- xiaoming
- xiaohong
- xiaoxiao # == [['xiaoming', 'xiaohong', 'xiaoxiao']]
數組也可以採用行內寫法
# 這個和上面的例子表示的意思是一樣的
class: [[xiaoming, xiaohong, xiaoxiao]]
2.3、對象
在 yaml 中一個對象可以使用冒號結構的 key: value 表示,冒號後面要加一個空格。例
city: shanghai # 這個表示一個對象 {city: 'shanghai'},對象中有一個city屬性,屬性值是shanghai
Yaml 也可以使用 key: {key1: value1, key2: value2, ...}
,將所有鍵值對寫成一個行內對象。
# 表示一個班級對象,裏面有三個屬性,班主任、班導、學生
class: {班主任: xiaoming, 班導: xiaohong, 學生: xiaoxiao}
較爲複雜的對象格式,可以使用問號加一個空格代表一個複雜的 key,配合一個冒號加一個空格代表一個 value:
?
- key1
- key2
:
- value1
- value2 # 意思即對象的屬性是一個數組 [key1, key2],對應的值也是一個數組 [value1, value2]
2.4、開發實例
上面我們舉了這麼多的例子,相信大家對 YAML 語言已經有一定的瞭解了,下面我們來看看實際開發中 YAML 在 Spring Boot 中的應用。
server:
# 修改運行端口
port: 9521
# 配置項目路徑
servlet:
context-path: /xm-admin
spring:
# 配置程序名稱
application:
name: xm-admin
# 配置運行環境(dev、test、prod)
profiles:
active: dev
jackson:
# 設置日期格式化
date-format: yyyy-MM-dd HH:mm:ss
# 設置時區
time-zone: GMT+8
mybatis-plus:
configuration:
# 控制檯打印sql
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
好了,關於 yaml 語言的介紹就到這裏結束啦。下面我們來介紹 Spring Boot 如何在配置文件中取值。
三、Spring Boot 配置文件取值
Spring Boot 讀取配置文件的方式可以分爲
- 通過 Spring Boot 的環境變量取值
- 通過註解方式讀取
1、通過獲取環境變量獲取配置
1.1、創建新工程
首先我們需要先創建一個新工程來進行獲取配置文件的演示(spring initializr)。
POM文件如下:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
1.2、編寫配置文件
個人習慣先將 application.properties 修改爲 application.yml。
在配置文件中隨便寫點內容:
name: xiaoming
age: 24
hobby:
- 看電影
- 聽音樂
- 打遊戲
1.3、獲取配置內容
1.3.1、啓動類獲取環境變量獲取配置
我們可以通過在啓動類中獲取到 Spring Boot 上下文對象,從而獲取到 Spring Boot 運行的環境變量
@SpringBootApplication
public class AppRun {
public static void main(String[] args) {
SpringApplication.run(AppRun.class, args);
}
}
上面這段代碼,相信大家已經很熟悉了,就是一個標準的 Spring Boot 啓動類。基本上大家都是這麼寫的吧,其實我們是可以用一個變量去接收SpringApplication.run(AppRun.class, args);
語句的返回值,而返回的對象正是 Spring Boot 的上下文對象。所以我們修改一下代碼:
public static void main(String[] args) {
// 獲取 Spring Boot 上下文
ConfigurableApplicationContext ctx = SpringApplication.run(AppRun.class, args);
// 獲取 Spring Boot 運行的環境變量
ConfigurableEnvironment ce = ctx.getEnvironment();
// 通過環境變量獲取 字符串
String name = ce.getProperty("name");
// 獲取 Integer 類型的值
Integer age = ce.getProperty("age", Integer.class);
// 獲取 數組 類型的值
String hobby0 = ce.getProperty("hobby[0]", String.class);
String hobby1 = ce.getProperty("hobby[1]", String.class);
String hobby2 = ce.getProperty("hobby[2]", String.class);
System.out.println("name:" + name);
System.out.println("age:" + age);
System.out.println("hobby[0]:" + hobby0);
System.out.println("hobby[1]:" + hobby1);
System.out.println("hobby[2]:" + hobby2);
}
控制檯的輸出如下:
從上圖可以看到,輸出中文的時候會亂碼顯示。亂碼的本質原因就是輸入和輸出時的編碼不一致,所以我們需要修改一下配置文件的編碼格式即可解決問題,修改步驟如下:
點擊 File -> Settings -> Editor -> File Encodings,修改相關編碼格式爲UTF-8,建議將 Transparent native-to-ascii conversion 勾選上。
修改完成之後控制檯顯示的就是正常的中文了。
1.3.2、注入環境變量獲取配置
spring核心庫中爲我們提供了一個環境變量的接口
Environment
,我們可以使用@Autowired
直接注入到我們的Bean
中。
下面我們在 test 包下編寫我們的測試類。
@SpringBootTest
class AppRunTests {
/**
* 直接注入即可
*/
@Autowired
Environment env;
@Test
void contextLoads() {
// 通過直接注入環境變量來獲取配置文件的屬性
String name = env.getProperty("name");
Integer age = env.getProperty("age", Integer.class);
String hobby0 = env.getProperty("hobby[0]", String.class);
String hobby1 = env.getProperty("hobby[1]", String.class);
String hobby2 = env.getProperty("hobby[2]", String.class);
System.out.println("name:" + name);
System.out.println("age:" + age);
System.out.println("hobby[0]:" + hobby0);
System.out.println("hobby[1]:" + hobby1);
System.out.println("hobby[2]:" + hobby2);
}
}
控制檯輸出的還是和上面的例子是一樣的
通過環境變量獲取配置文件的方式我們就講到這,其實使用環境變量不止能夠獲取到我們配置文件內容,還能夠獲取到許多與環境變量有關的值,例如 java.home、java.version、user.name、user.dir 等等一系列的環境變量的默認配置。
2、通過註解獲取配置
更新中(2020-06-29)。。。