Day 10 - 讀取 Spring Boot 設定檔 - @Value、application.properties

古古

2023/11/10


哈囉大家好,我是古古

在前面的文章中,我們已經對 Spring IoC 有了滿多的認識,那麼接著這篇文章,我們會延伸出去,介紹一下要如何透過 @Value,將 Spring Boot 設定檔中的值給讀取到 Bean 裡面

什麼是 Spring Boot 設定檔? #

所謂的 Spring Boot 設定檔,指的是「放在 src/main/resources 這個資料夾底下的 applicaiton.properties 檔案」,而他的目的,就是去「存放 Spring Boot 程式的設定值」

Spring Boot 設定檔(application.properties)的寫法 #

大家如果點擊兩下打開 application.properties 檔案的話,可以看到右邊是空白一片,表示我們目前還沒有在這個 application.properties 檔案中,設定任何的設定值

如果想要在這個 application.properties 的檔案裡面,添加 Spring Boot 的設定值的話,需要遵循一定的寫法格式才可以

首先大家可以觀察一下,application.properties 這個檔案,他是一個「檔名為 application、並且副檔名為 .properties」的檔案,也因為如此,這個 application.properties 檔案,他就是使用 「properties 這個語法」 來撰寫的

properties 的語法格式 #

在 properties 的語法中,是使用 key=value 這樣子的格式來撰寫,並且「每一行」都是一組 key 和 value 的配對

像是下面這個例子,我們就在第 1 行寫上了 count=5,所以這一行程式就表示,我們定義了一個 key 的名字是 count,並且這個 count 的 value 值,就是 5

大家可以把這個 key=value 的寫法,想像成是 變數=值 的概念,所以前面的 key 其實就等同於是 Java 中的變數,而後面的 value,就是這個變數的值,就是這麼的簡單暴力!

因此當我們在 application.properties 檔案中,去寫上了一行 count=5 的程式,就表示我們定義了一個變數 count,然後他的值是 5 這樣,僅此而已

1. properties 語法的注意事項之一:不需要加上空白鍵排版 #

大概了解了 properties 語法的核心概念 key=value 之後,接著我們可以來看一些使用 properties 語法的注意事項

當我們以前在寫 Java 程式的時候,習慣會在 = 的前後加上一堆空白鍵,去做排版的美化,像是下面這個樣子:

// 美化前
int count=5;

// 加上空白鍵美化後
int count = 5;

不過在 properties 語法裡面,是 「不需要」= 的前後,去加上空白鍵去做排版的美化,只要全部連在一起寫就好,多加空白鍵反而可能有機會導致程式運行出現問題

所以在 properties 語法裡面,建議就是使用下面這種寫法,把你的空白鍵拔掉,一路連自連到底就對了

count=5

2. properties 語法的注意事項之二:key 中的 . 表示「的」的概念 #

在前面有提到,properties 語法中是使用 key=value 來撰寫程式的,而 key 所代表的,就是變數的名字

不過這個 key 在命名上,是允許裡面帶上 . 符號的,並且這個 . 的符號,他的邏輯意義就是中文的「的」的意思

舉例來說,我們可以在 application.properties 檔案裡面,在第 2 行寫上 my.name=John 的程式,而當我們這樣寫之後,my.name 這個 key 就是變數的名字,其中文意義是表示「我的名字」(因為 . 是表示「的」的意思)

所以 my.name=John 這一整行的意思,就是「我的名字叫做 John」

或是我們也可以在下面,再新增一行 my.age=20 的程式,而這一行程式所代表的,就是「我的年齡是 20 歲」的意思

所以大家以後就可以將 key 中的 .,去翻譯成是中文的「的」的意思,這樣就可以透過這種格式,去傳遞更豐富的意義出來

3. properties 語法的注意事項之三:使用 # 來表示 comment #

在 properties 語法中,也是可以去添加 comment 的,只要在最前面加上一個 # 的符號,那一行就會被 properties 語法給忽略了(用法同 Java 中的 // 一樣)

讀取 Spring Boot 設定檔(application.properties)中的值:@Value #

了解了要如何在 application.properties 檔案中透過 key=value 的寫法,去添加一行行的設定之後,接著我們可以來看一下,要如何透過 @Value,將 application.properties 中的設定值讀取到 Bean 裡面

還是之前的 HpPrinter 的例子,我們可以稍微改寫一下 HpPrinter 中的程式,讓他變成下面這個樣子

@Component
public class HpPrinter implements Printer {

    private int count;

    @Override
    public void print(String message) {
        count--;
        System.out.println("HP印表機: " + message);
        System.out.println("剩餘使用次數: " + count);
    }
}

而在這之中,count 變數的值沒有被設定成任何一個數字,因此 count 值就會是預設的 0

但是如果我們在這個 count 的變數上面,去添加一個 @Value("${count}") 的話,這樣子就可以從 Spring Boot 設定檔 (application.properties 檔案) 中,去讀取其中的 count 這個 key 的值,並且將這個值給賦予到 HpPrinter 中的 count 變數裡面

而因為目前在 application.properties 檔案中,我們是在第 1 行,去寫上了 count=5 的設定

因此到時候 HpPrinter 中的 count 變數的值,就會變成是 application.properties 檔案中所定義的「5」

所以這也就表示,我們就成功的透過 @Value 的用法,將 Spring Boot 設定檔 (application.properties 檔案) 中的值,給成功的讀取到 Bean 裡面的變數中了!

1. 使用 @Value 的注意事項之一:需要遵守固定格式寫法 #

大概了解了 @Value 的用法之後,我們可以來看一下使用 @Value 的一些注意事項

在使用 @Value 去讀取 Spring Boot 設定檔 (application.properties 檔案) 中的值的時候,一定要在 @Value 後面的括號中,寫上如下的格式:

@Value("${XXXX}")

其中 XXXX 可以替換成 application.properties 檔案中的任意一個 key,但是外層的 "${}" 是不能夠省略的,因此在寫法上會稍微複雜一點,建議大家之後可以直接複製貼上這段程式,再去改裡面的 XXX 的值即可

舉例來說,假設 application.properties 中的 key 為 printer.count

printer.count=100

那麼在使用 @Value 去注入時,就是把後面的 XXX 替換成 printer.count,所以就會變成是:

@Value("${printer.count}")
private int count;

因此就可以透過這樣的寫法,將 application.properties 中的設定值,給注入到 Bean 中的變數了

2. 使用 @Value 的注意事項之二:只有在 Bean 和 Configuration 中才能生效 #

只要是有使用到 @Value 的地方,該 class 本身得是一個 Bean、或是一個 Configuration 的設定 class@Value 才能夠生效

所以假設大家在使用 @Value 時,明明程式就寫得很對,但是不知道為什麼他不起作用,很大的原因就是因為這個 class 還沒變成 Bean,所以 @Value 才會毫無作用

因此發生這種情況時,只要記得在 class 上面加上一個 @Component,將這個 class 變成是一個 Bean,這樣子就可以確保 @Value 能生效了

補充:@Value 在那些帶有 @Configuration 的 class 中,也是能夠生效的,不過因為在此系列文中不會特別介紹到 @Configuration 的用法,所以大家可以先有個印象就可以了

3. 使用 @Value 的注意事項之三:類型需要一致 #

在使用 @Value 去讀取 Spring Boot 設定檔 (application.properties 檔案) 中的值時,Java 中的變數的類型,必須要和 application.properties 中的類型一致才可以

舉例來說,在 application.properties 檔案裡面,我們定義了一組 key 和 value 如下:

printer.count=5

上面這行程式,其實就是在暗示 printer.count 的值為「一個整數」,因此在 Spring Boot 程式中,我們就得將 @Value 加在一個「Int 或是 Long 類型」的變數上,這樣子在賦予值的時候才不會出現問題

@Value("${printer.count}")
private int count;

又或是說,假設我們在 application.properties 檔案裡面,定義了另一組 key 和 value 如下:

my.name=John

上面這行程式,也是在暗示 my.name 的值為「一個字串」,因此在 Spring Boot 程式中,我們就得將 @Value 加在一個「String 類型」的變數上,這樣子在賦予值的時候,也才不會出現問題

@Value("${my.name}")
private String name;

4. 使用 @Value 的注意事項之四:可以設定預設值 #

在使用 @Value 去讀取 Spring Boot 設定檔 (application.properties 檔案) 中的值時,有可能會發生一種情況,就是「該 key 不存在在 application.properties 檔案裡面」

譬如說我們在 Spring Boot 程式裡面,寫上了下面這一段程式,嘗試去將 application.properties 檔案中的 printer.count 的值,去儲存到 count 變數中

@Value("${printer.count}")
private int count;

如果這時候 application.properties 檔案中「沒有」printer.count 這個 key 的話,那麼 Spring Boot 程式就會運作失敗,出現「Could not resolve placeholder ‘printer.count’ in value “${printer.count}"」的錯誤,導致無法成功啟動

如果大家想要避免這個問題的話,@Value 也是有提供另一種輔助方式可以讓我們使用,即是「設定預設值」

我們可以在 @Value 的 key 的後面,加上一個 :,並且在後面寫上想要的值,譬如說這裡寫上 200

@Value("${printer.count:200}")
private int count;

上面這一段程式的意思是:「@Value 會先去找尋 application.properties 中有沒有 printer.count 這個 key,有的話,就去讀取那個 key 的值到 count 變數中,如果沒有的話,則將 count 變數的值,設定成預設的 200」

所以當我們這樣寫之後,如果 application.properties 中「有設定」printer.count 的值(如下方程式所示),那麼 Spring Boot 程式中的 count 變數的值就會是 5

printer.count=5

但是如果 application.properties 中,「沒有設定」printer.count 的值(如下方程式所示),那麼 Spring Boot 程式中的 count 變數的值就會是預設的 200

# no key-value

所以簡單的說的話,如果想要「避免 application.properties 中找不到該 key,導致 Spring Boot 程式運行失敗」的狀況的話,那麼就可以在 @Value 中使用 :,在後面加上預設值,當找不到 key 時,就可以直接無縫接軌改成使用預設值來運行

補充:使用 @Value 的預設值寫法,其實是有點雙面刃的做法,因為這樣會讓設定值四散在各處,後續會比較難進行管理,因此建議大家斟酌使用

小結:所以,@Value 到底要怎麼用? #

所以說到這邊,我們可以來總結一下 @Value 的用法和注意事項

想要使用 @Value 去讀取 Spring Boot 設定檔 (application.properties 檔案) 中的值的話,必須滿足:

  1. 必須使用固定格式 @Value("${XXXX}")
  2. 該 class 必須是 Bean 或是 Configuration
  3. Java 中的變數和 application.properties 中的類型需要一致
  4. 可以視情況添加預設值

只要注意好這些地方,大家以後就可以透過 @Value,在 Spring Boot 程式中去讀取 Spring Boot 設定檔 (application.properties 檔案) 中的值了!

補充 1:Spring Boot 設定檔的兩種語法(properties 和 yml) #

在前面我們有介紹到,Spring Boot 的設定檔所指的,就是「application.properties」這個檔案,而他裡面所放的,就是 Spring Boot 程式的設定值

不過其實 Spring Boot 設定檔,是可以使用兩種不同的語法來撰寫的,分別是 properties 和 yml

  • 當 Spring Boot 設定檔 「命名成 application.properties」,即是表示他是使用 properties 語法來撰寫,因此格式是 key=value
  • 當 Spring Boot 設定檔 「命名成 application.yml」,即是表示他是使用 yml 語法來撰寫,格式則為 key: value

所以在 Spring Boot 程式裡面,application.properties 和 application.yml 這兩個檔案,他們的目的都是一樣的,都是去作為 Spring Boot 的設定檔,去儲存相關的設定值,差別只在他們使用了不同的語法來撰寫而已

不過在這裡要特特特特別注意的一點,就是 「一份 Spring Boot 程式中只能使用一種語法來撰寫」,換句話說的話,就是 application.properties 和 application.yml 這兩個檔案,他們「不能同時存在」

所以一開始在創建 Spring Boot 程式時,要不就是選用 application.properties 寫到底,要不就是使用 appilcation.yml 寫到底,不能夠讓這兩個檔案同時並存,否則會使得 Spring Boot 程式運作失敗,這是大家在使用上要特別注意的地方

補充:我自己是比較喜歡使用 application.properties 來設定,yml 語法寫起來感覺很容易出錯😂(一個恍神不小心縮排就毀了),供大家參考

補充 2:yml 的語法 #

在前面我們有詳細介紹了 properties 語法的用法,而這裡也可以來補充一些 yml 語法的寫法

key: value 的寫法 #

在 yml 語法中,是採用 key: value 的方式來撰寫,注意在 value 前面 「必須」 加上一個空白鍵來隔開 :,所以寫起來的效果如下:

count: 5

上面這一段程式所表示的,就是去宣告一個 key 為 count,並且他的值為 5,而如果想用 properties 語法來表示同樣的效果的話,則會寫成下面這樣子:

count=5

縮排的寫法 #

yml 除了使用 key: value 的方式來設定值之外,並且 yml 是使用「縮排」的方式,來表示中文的「的」的概念

像是在 properties 語法中,當我們寫了下面這行程式,其中文意義是表示「我的名字叫做 John」(因為 properties 語法中的 .,就是表示中文的「的」的意思)

my.name=John

而在 yml 中,則會寫成下面這個樣子,透過 「將 name 這一行往右縮排 2 個空白鍵」,表示中文的「的」的意思

my:
  name: John

所以上面這一段程式讀起來,一樣也是「我的名字是 John」,只是 yml 是透過縮排的方式來表達,而 properties 是使用 . 的方式來表達而已

小結:properties 和 yml 的差別 #

下面總結了 properties 語法和 yml 語法在寫法上的差別,基本上是大同小異,就是「縮排」的這個概念需要轉換一下,其他部分(像是 key 和 value 的寫法),大致上都還是滿相似的

總結 #

這篇文章先介紹了什麼是 Spring Boot 的設定檔,也介紹了 application.properties 檔案的用途,以及 properties 的語法介紹

並且我們也介紹到,要如何使用 @Value,將 Spring Boot 設定檔 (application.properties 檔案) 中的值讀取到 Bean 裡面,也介紹了使用 @Value 的注意事項和預設值的用法

最後則是補充了 Spring Boot 設定檔的兩種命名方式,也介紹了 yml 的語法,以及 properties 語法和 yml 語法的差別

所以到這篇文章為止,有關於 Spring IoC 的介紹就告一個段落了,在這個章節中:

  • 我們先介紹了 Spring IoC 中最重要的兩個概念:IoC 和 DI
  • 也介紹了什麼是 Spring 容器以及 Bean,並且介紹要如何透過 @Component@Autowired@Qualifier 以及 @PostConstruct 這些註解,去對 Bean 進行創建、注入、以及初始化
  • 最後也介紹了要如何透過 @Value,將 Spring Boot 設定檔中的值讀取到 Bean 裡面

那麼從下一篇文章開始,我們就會來了解 Spring 框架中的另一個也很重要的特性:AOP,那我們就下一篇文章見啦!

相關連結 #