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)。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章