哈囉大家好,我是古古。
在前幾篇文章中,我們分別介紹了 Bean 的相關特性,像是:
@Component
@Autowired
@Qualifier
所以到目前為止,我們可以說是對 Bean 有了更多的認識,並且已經可以成功的在 Spring Boot 程式中運用 Bean 了!
那麼這篇文章,我們就會繼續來探討 Bean 的更多用法,來介紹要如何在創建一個 Bean 出來之後,去「初始化」這個 Bean 的值。
所謂的「Bean 的初始化」,就是指「在 Bean 被創建出來之後,對這個 Bean 去做一些初始值的設定」,譬如說把他內部的變數的值設定成 5、或是進行一些運算之類的,反正就是對這個 Bean 去做初始的出廠設定就對了。
舉例來說,我們可以先改寫一下之前所寫的 HpPrinter,先在這個 HpPrinter 中去加上一個 count 變數,用 count 變數計算這台印表機還可以印幾次。
所以每當我們 call 一次 print()
方法時,這個 count 的數量就要減一,表示已經印過一次了,實際程式如下:
@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 上面加上 @Component
,將他變成 Bean,所以 Spring Boot 到時候就會為我們創建一個 hpPrinter 的 Bean 出來,並且存放在 Spring 容器裡面。
不過到目前為止,因為我們沒有去設定 Bean 的初始化,因此 Spring Boot 就只會去把這個 Bean 給創建出來,並不會為裡面的 count 值進行初始化,因此在這個 hpPrinter 中的 count 值,預設就會是 0。
不過,如果我們想要讓 Spring Boot 在創建這個 hpPrinter 出來之後,同時也去為這個 count 變數賦予一個初始值的話,那麼我們就可以透過 @PostConstruct
來幫助我們達成這件事!
@PostConstruct
的用途,就是「為這個 Bean 去進行初始化」,因此我們就可以透過 @PostConstruct
,去設定這個 Bean 中的變數的初始值了。
因此如果我們想要改寫上面的 HpPrinter,將他裡面的 count 變數的值「初始化成 5」的話,那麼我們就可以這樣做:
首先我們先在 HpPrinter 新增一個新的方法 initialize()
(方法名稱可以隨意取,後面會解釋),並且在這個方法上面,加上一行 @PostConstruct
,這樣我們等一下就可以在這個方法中, 去初始化 Bean 的值。
@PostConstruct
public void initialize() {
count = 5;
}
像是我們可以在 initialize()
的方法中,去初始化這個 Bean 的值,譬如說我們可以把 count 的值設成 5,就可以將 count 變數的值初始化成 5。
所以到時候,當 Spring Boot 創建出 hpPrinter 這個 Bean 之後,Spring Boot 就會接著去執行 initialize()
方法,將 count 的設定成 5,進而就可以完成 Bean 的初始化了!
在上面的實作中,當我們想要初始化 Bean 中的變數的值時,我們需要先在該 class 中,先去新增一個方法出來(像是 HpPrinter 中的 initialize()
方法),接著再為這個方法加上 @PostConstruct
,這樣子我們就可以在這個方法裡面, 去實作初始化 Bean 的程式了。
不過這個 initialize()
方法(也就是被加上 @PostConstruct
的方法),其實也是有一些格式需要遵守的:
public
void
所以綜合以上四點的話,這個「初始化 Bean 的方法」,通常就會長得像是下面這個樣子:
@PostConstruct
public void XXX();
其中的方法名稱 XXX()
,可以替換成大家喜歡的單字,常見的有 setup()
、init()
、initialize()
…等等,這些單字都可以拿來使用,不會影響到 Spring Boot 的運作。
補充:Spring Boot 在判斷一個 Bean 中有沒有初始化的方法時,是 「尋找有沒有方法加上
@PostConstruct
,如果有的話,就執行該方法」。也因為如此,所以這個初始化的方法名稱對 Spring Boot 而言是完全不重要的, 大家就選擇自己喜好的單字(ex:setup()
、init()
)來使用即可。
由於當某個方法上面加上 @PostConstruct
,該方法就會變成「初始化 Bean 的程式」,因此假設在同一個 class 裡面,同時有多個方法都加上 @PostConstruct
的話,那麼 Spring Boot 就會不知道要先運行哪一個方法去初始化 Bean。
因此在這種情況下,雖然 Spring Boot 程式不會報錯,但是實際上初始化 Bean 的順序是完全隨機的,因此可能會造成程式邏輯的錯誤,並且後續也很難統一管理初始化的設定。
所以就建議大家,在使用 @PostConstruct
去初始化 Bean 的時候,在同一個 class 中,只在其中一個方法上面加上 @PostConstruct
,統一的去管理初始化 Bean 的設定,這樣子不管是在運作上、還是後續的維護,都是比較好的做法。
由於上面的例子因為比較簡單,所以有的人可能會覺得:「為什麼我們不直接在宣告 count 變數的同時,把 count 值也設成 5 就好?」,就像是下面這個樣子,直接在宣告 count 變數的同時,也將他初始化成 5,這樣子就可以省去 @PostConstruct
的程式了。
雖然在這個例子中,確實是可以透過上述的方式,簡單的將 count 值初始化成 5,但是在實際的工作中,@PostConstruct
的應用還是很廣泛的。
使用 @PostConstruct
來初始化的優勢,就是 @PostConstruct 可以進行「複雜的初始化」,譬如說在 map 變數裡生成初始的數據、或是取得注入的 Bean 的資訊、或者檢查注入的 Bean 是否為 null 值…等等,這些實作只能夠透過 @PostConstruct
做到,使用一般的簡單方式無法實作出這些效果。
因此在實務上,使用 @PostConstruct
來進行 Bean 的初始化仍舊是很常見的作法,建議大家還是要了解一下這個用法會比較好!
想要在 Spring Boot 中初始化 Bean,除了可以使用這篇文章所介紹 @PostConstruct
之外,其實 Spring Boot 也有支援另一種方法去初始化 Bean 的,也就是「實作 InitializingBean interface 裡面的 afterPropertiesSet()
方法」。
用 afterPropertiesSet()
的方式所實作出來的效果,和 @PostConstruct
的效果一模一樣的。
不過因為實作 afterPropertiesSet()
方法算是比較舊的寫法,在業界中越來越少用到,因此在本系列文中就不會特別介紹這部分,如果大家有興趣的話,可以再上網查詢相關資料。
但一般在實作上,還是會建議使用 @PostConstruct
來初始化 Bean 會比較好!
這篇文章我們介紹了要如何使用 @PostConstruct
,去初始化 Spring Boot 所創建出來的 Bean,所以大家以後就可以透過 @PostConstruct
,去對 Bean 進行初始化的設定了。
而到這篇文章為止,我們就算是對 Spring IoC 有了比較全面的認識,現在我們已經了解了什麼是 IoC、DI,也了解了 Spring 容器和 Bean,並且也知道要如何在 Spring Boot 中使用 @Component
、@Autowired
、@Qualifier
以及 @PostConstruct
這些註解,去對 Bean 進行創建、注入、以及初始化。
那麼下一篇文章,我們就會繼續深入來介紹,要如何透過 @Value
,將 Spring Boot 設定檔中的值讀取到 Bean 裡面,讓我們所寫的 Java 程式可以去運用 Spring Boot 設定檔中的值,那我們就下一篇文章見啦!
補充:本文是擷取自我開設的線上課程 「Java 工程師必備!Spring Boot 零基礎入門」 的內容,如果你想了解更多的 Spring Boot 的用法,歡迎參考課程簡介 (輸入折扣碼「HH202504KU」即可享 85 折優惠)。