哈囉大家好,我是古古。
在前面的文章中,我們已經對 Spring IoC 有了滿多的認識,並且也能夠在 Spring Boot 中應用 Spring IoC 的核心用法了。
那麼接著這篇文章,我們就會繼續深入來介紹,要如何透過 @Value
,將 Spring Boot 設定檔中的值讀取到 Bean 裡面,讓我們所寫的 Java 程式可以去運用 Spring Boot 設定檔中的值,所以我們就開始吧!
所謂的 Spring Boot 設定檔,指的是 「放在 src/main/resources 資料夾底下的 applicaiton.properties 檔案」,而這個 application.properties 的目的,就是「存放 Spring Boot 程式的設定值」。
所以大家以後只要聽到別人在說「Spring Boot 設定檔」,就要第一時間想到他所指的其實是 application.properties 這個檔案。
如果我們點擊兩下打開 application.properties 檔案的話,可以看到右邊有一行 spring.application.name=demo
的程式,這個是 IntelliJ 在創建 Spring Boot 專案時所自動生成的設定值。
這裡大家可以自由選擇要不要將 spring.application.name=demo
這一行程式刪掉(刪掉此設定不影響 Spring Boot 運作),如果不想刪除的話,也可以直接按下 Enter 鍵換行,這樣子就可以繼續在這個 application.properties 檔案中,繼續添加其他的設定值了。
補充:由於版面的緣故,因此在下面的截圖中不會出現
spring.application.name=demo
的設定。
如果想要在 application.properties 中,添加 Spring Boot 的相關設定的話,那就要遵循一定的寫法格式才可以。
首先大家可以觀察一下,application.properties 這個檔案,他是一個「檔名為 application、並且副檔名為 .properties」的檔案。 因此這就表示,這個 application.properties 檔案,是使用 「properties 語法」 來撰寫設定值的。
而在 properties 的語法中,是使用 key=value
的格式來撰寫設定值,並且每一行程式,就是一組 key 和 value 的配對。
像是下面這個例子,我們就在第 1 行寫上了 count=5
,所以這一行程式就是表示:我們定義了一個 key(他的名字是 count),並且這個 count 的 value 值,就是 5。
所以大家其實可以把這個 key=value
的寫法,簡單的想像成是 變數=值
的概念,在前面的 key 就等同於是 Java 中的變數名稱,而後面的 value,就是這個變數的值,所以 properties 語法的概念其實和 Java 是很相近的!
因此當我們在 application.properties 中,寫上了一行 count=5
的程式時,就表示我們定義了一個變數 count
,然後他的值是 5
這樣,就是這麼的簡單暴力!
大概了解了 properties 語法的核心概念 key=value
的寫法之後,接著我們可以來看一些使用 properties 語法的注意事項。
當我們以前在寫 Java 程式的時候,習慣會在 =
的前後加上空白鍵,去做排版的美化,所以就會像是下面這個樣子:
// 美化前
int count=5;
// 加上空白鍵美化後
int count = 5;
不過在 properties 語法裡面,是 「不需要」 在 =
的前後加上空白鍵,去做排版的美化的,只要全部連在一起寫就好,多加空白鍵反而會導致程式運行時出現問題。
所以在 properties 語法裡面,建議就使用下面這種寫法,把你的空白鍵收起來,一路連字連到底就對了!
count=5
.
是表示「的」的概念
#
在前面我們有介紹到,properties 語法中是使用 key=value
來撰寫程式的,而 key 所代表的,就是變數的名字。
不過這個 key 在命名上,是允許裡面帶上 .
符號的,並且這個 .
的符號的邏輯意義,就是中文的「的」的意思。
舉例來說,我們可以在 application.properties 裡面,在第 2 行寫上 my.name=John
的程式,而當我們這樣寫之後,my.name
這個 key 就是變數的名字,其中文意義就是表示「我的名字」(因為 .
是表示「的」的意思)。
所以 my.name=John
這一整行的意思,就是「我的名字叫做 John」。
或是我們也可以在下面,再新增一行 my.age=20
的程式,而這一行程式所代表的,就是「我的年齡是 20 歲」的意思。
所以大家以後在撰寫 properties 語法時,就可以將 key 中的 .
,翻譯成是中文的「的」的意思,所以我們就可以透過這種方式,去傳遞更豐富的邏輯意義出來了。
#
來表示 comment
#
在 properties 語法中,我們也是可以去添加 comment 的,只要在撰寫程式時,在最前面加上一個 #
的符號,那麼那一行就會被 properties 語法給忽略了(用法和 Java 中的 //
一樣)。
在了解了 Spring Boot 設定檔(也就是 application.properties 檔案)的用途、以及 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);
}
}
在這段程式之中,HpPrinter 中的 count 變數沒有被初始化,因此 count 的值預設就會是 0。
但是如果我們在這個 count 的變數上面,去添加一行 @Value("${count}")
的程式的話,這樣子就可以從 application.properties 中,去讀取 key 為 count
的值,並且將這個值給賦予到 HpPrinter 中的 count 變數裡面。
而又因為我們前面有在 application.properties 的檔案中,在第 1 行寫上了 count=5
的設定。
所以到時候 HpPrinter 中的 count 變數的值,就會被設定成是 application.properties 中所定義的「5」了!
當大家改寫好上述的程式之後,我們也可以試著來運行一下 Spring Boot 程式,來實際感受一下 @Value
的效果。
以目前的程式來說(記得將 MyController 的 @Qualifier
的值改回成 hpPrinter),只要大家運行起 Spring Boot 程式,並且請求 http://localhost:8080/test 之後,IntelliJ 就會在 console 下方呈現下列的資訊。
其中之所以會輸出「剩餘使用次數: 4」,就是因為我們有在 HpPrinter 中添加一行 @Value("${count}")
的程式,因此 HpPrinter 中的 count 的值就會被設定成 5,才導致這裡會輸出「剩餘使用次數為 4 次」的資訊。
大家如果想玩玩看的話,也可以試著把 application.properties 中的 count 的值改成別的數字,譬如說改成 count=10
之類的。修改完之後,只要重新運行 Spring Boot 程式,並且重新請求 http://localhost:8080/test,這樣子在 console 中所輸出的剩餘使用次數,就會變成是 99 了。
總而言之,透過上述的運行結果,就代表我們能夠成功的透過 @Value
的用法,將 application.properties 中的設定值讀取到 Bean 裡面了!
大概了解了 @Value
的用法之後,接著我們也來介紹一下使用 @Value
的一些注意事項。
在使用 @Value
去讀取 application.properties 中的值時,一定要使用下面這種格式撰寫 @Value
的程式才可以:
@Value("${XXX}")
在這個格式中,其中的 XXX
的部分,可以替換成 application.properties 中的任意一個 key,但是外層的 "${}"
是不能夠省略的!!切記!!!
也因為 @Value
的固定格式寫法確實比較複雜一點,因此就建議大家,可以直接複製上面這段程式,後續再去修改裡面的 XXX
的值即可。
舉例來說,假設我們想要讀取 application.properties 中的 printer.count
這個 key,那我們就可以這樣寫:
printer.count=100
而後續在使用 @Value
去讀取時,就直接把後面的 XXX
替換成 printer.count
就可以了,所以就可以在 Java 中實作下面這些程式:
@Value("${printer.count}")
private int count;
因此透過上述的寫法,我們就可以使用 @Value
,去讀取 application.properties 中的設定值到 Bean 裡面了!
只要是有使用到 @Value
的地方,該 class 本身就得是一個 Bean、或是一個帶有 @Configuration
的設定 class,這樣子 @Value
才能夠真的生效。
所以當大家在使用 @Value
時,當你覺得你的程式明明寫得很對,但是不知道為什麼卻沒有作用時,這時候就可以回頭檢查,是不是因為這個 class 還沒變成 Bean,所以 @Value
才會毫無作用。
因此發生這種情況時,大家就只要在 class 上面加上一個 @Component
,將這個 class 變成一個 Bean,這樣子就可以確保 @Value
能真的生效了!
補充:
@Value
除了能在 Bean 中生效之外,在那些帶有@Configuration
的 class 中也是能生效的,不過因為在此系列文中不會特別介紹到@Configuration
的用法,所以大家可以先有個印象就可以了。
在使用 @Value
去讀取 application.properties 中的值時,那個被添加 @Value
的 Java 變數,他的變數類型必須要和 application.properties 中的類型一致才可以。
舉例來說,在 application.properties 裡面,我們定義了一組 key 和 value 如下:
printer.count=5
上面這行程式的意思,是表示 printer.count
的值為 5,而 5 這個數字,就暗示了他的類型為「整數」。
因此在 Spring Boot 的程式中,我們就必須將 @Value
加在一個「int 或是 long 類型」的變數上,這樣子到時候 @Value
在讀取值時,才不會出現問題。
@Value("${printer.count}")
private int count;
又或是說,假設我們在 application.properties 裡面定義了另一組 key 和 value 如下:
my.name=John
上面這行程式的意思,是表示 my.name
的值為 John,而 John 這個單字,就暗示了他的類型為「字串」。
因此在 Spring Boot 的程式中,我們就必須將 @Value
加在一個「String 類型」的變數上,這樣子到時候 @Value
在讀取值時,也才不會出現問題。
@Value("${my.name}")
private String name;
在使用 @Value
去讀取 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}"」的錯誤,表示找不到 printer.count
這個 key,所以才會導致運行失敗。
如果大家想要避免這個問題的話,@Value
也是有提供另一種輔助方式讓我們使用,也就是「設定預設值」。
像是我們在撰寫 @Value
的程式時,可以在 @Value
中的 key 的後面加上一個 :
,並且在後面寫上想要的預設值,譬如說這裡我們就寫上 200:
@Value("${printer.count:200}")
private int count;
所以上面這一段程式的意思就是:「@Value
會先去application.properties 中尋找有沒有 printer.count
這個 key,如果有的話,就讀取 application.properties 中的值到 count 變數裡面;如果沒有的話,則將 count 變數的值,設定成預設值 200」。
因此當我們這樣寫之後,如果 application.properties 中「有設定」printer.count
的值的話(如下方程式所示),那麼 Spring Boot 程式中的 count 變數的值,就會是 5。
printer.count=5
但是如果 application.properties 中,「沒有設定」printer.count
的值的話(如下方程式所示),那麼 Spring Boot 程式中的 count 變數的值,就會是 @Value
所設定的預設值 200。
# no key-value
所以總結來說,如果想要避免「application.properties 中找不到該 key,導致 Spring Boot 程式運行失敗」的狀況的話,那麼就可以在 @Value
中使用 :
,接著在後面寫上預設值,這樣子當 application.properties 中找不到該 key 時,就可以直接改成使用預設值來運行。
補充:不過老實說,
@Value
的預設值的用法其實是有好有壞,因為當我們使用了@Value
的預設值之後,就會讓設定值四散在各個 calss 裡面,後續會比較難統一進行管理,因此建議大家斟酌使用。
因為 @Value
的注意事項比較多,所以我們也可以來總結一下 @Value
的用法和注意事項有哪些。
想要使用 @Value
去讀取 Spring Boot 設定檔(也就是 application.properties 檔案)中的值的話,必須注意以下的事項:
@Value("${XXXX}")
@Configuration
只要注意好上述這些地方,大家以後就可以自由的運用 @Value
,在 Spring Boot 程式中去讀取 Spring Boot 設定檔(也就是 application.properties 檔案)中的值了!
在前面我們有介紹到,Spring Boot 的設定檔指的就是「application.properties」這個檔案,而 application.properties 裡面所放的,就是 Spring Boot 程式的設定值。
不過其實在 Spring Boot 中,可以使用兩種不同的語法來撰寫 Spring Boot 的設定,分別是「properties 語法」和「yml 語法」。
舉例來說:
key=value
。key:value
。所以在 Spring Boot 程式裡面,application.properties 和 application.yml 這兩個檔案,他們的目的都是一樣的,都可以作為 Spring Boot 的設定檔,去儲存相關的設定值,差別只在於他們使用了不同的語法來撰寫而已。
不過在 Spring Boot 中,我們一次只能夠選擇一種語法來撰寫,所以換句話說的話,就是 application.properties 和 application.yml 這兩個檔案,不能同時存在,只能擇一使用,這是大家在使用上要特別注意的地方。
補充:雖然我個人是比較喜歡使用 application.properties,不過實務上兩種語法都會看到,因此建議大家兩種語法都還是要熟悉一下會比較好。
在前面我們有詳細介紹了 properties 語法的用法,在這裡我們也來補充一些 yml 語法的寫法,提供給大家參考。
不同於 properties 語法,在 yml 語法中,是採用 key: value
的方式來撰寫設定值。
不過這裡要特別注意,在 :
的後面,必須要先加上一個空白鍵,然後才能寫上 value 值,這是在撰寫 yml 語法的時候,要特別留意的地方。
count: 5
在 yml 中,除了會使用 key: value
來撰寫設定值之外,yml 中也改成用「縮排」的方式,來表示中文的「的」的概念。
像是在前面所介紹的 properties 語法中,當我們寫了下面這行程式,他的中文意義為「我的名字叫做 John」(因為 properties 語法中的 .
,就是表示中文的「的」的意思)。
my.name=John
但是在 yml 中,則是會改寫成下面這個樣子,透過 「將 name 這一行往右縮排 2 個空白鍵」,表示中文的「的」的意思。
my:
name: John
所以上面這一段程式讀起來,一樣也是「我的名字是 John」,只是 yml 是透過縮排的方式來表達,而 properties 是使用 .
的方式來表達而已。
所以比較一下 properties 語法和 yml 語法的差別的話,基本上他們在 key 和 value 的寫法上是很類似的,但就是「縮排」的概念需要轉換一下,這是大家在實作上,要特別注意的細節。
下圖也比較了 properties 語法和 yml 語法的差別,提供給大家參考:
這篇文章我們先介紹了什麼是 Spring Boot 的設定檔(即是 application.properties 檔案)、以及 properties 語法的使用方法,並且我們也介紹了要如何使用 @Value
,去讀取 application.properties 中的值到 Bean 裡面。
那麼到這篇文章為止,有關於 Spring IoC 的介紹就告一個段落了,在這個 Spring IoC 的部分中:
@Component
、@Autowired
、@Qualifier
以及 @PostConstruct
這些註解的用法,去對 Bean 進行創建、注入、以及初始化。@Value
,去讀取 application.properties 的值到 Bean 裡面所以透過「Day 5~Day 10」的文章介紹,我們就介紹完 Spring IoC 的重要概念了,雖然這些內容沒辦法涵蓋 Spring IoC 的全部細節,不過作為入門來說,算是已經非常足夠的了!
那麼從下一篇文章開始,我們就會來了解 Spring 框架中的另一個也很重要的特性:AOP,那我們就下一篇文章見啦!
補充:本文是擷取自我開設的線上課程 「Java 工程師必備!Spring Boot 零基礎入門」 的內容,如果你想了解更多的 Spring Boot 的用法,歡迎參考課程簡介 (輸入折扣碼「HH202504KU」即可享 85 折優惠)。