iT邦幫忙

2023 iThome 鐵人賽

DAY 9
3
Software Development

Spring Boot 零基礎入門系列 第 9

Spring Boot 零基礎入門 (9) - Bean 的初始化 - @PostConstruct

  • 分享至 

  • xImage
  •  

賀!此系列文榮獲 2023 iThome 鐵人賽《優選》獎項,正在規劃出書中,感謝大家的支持🙏,同名課程「Java 工程師必備!Spring Boot 零基礎入門」也已在 Hahow 平台上架

哈囉大家好,我是古古

在前幾篇文章中,我們有介紹了創建 Bean 的方法 @Component、注入 Bean 的方法 @Autowired、以及指定 Bean 名字的方法 @Qualifier,所以到目前為止,我們可以說是對 Bean 已經有了更多的認識,現在的我們已經可以成功的在 Spring Boot 程式中運用 Bean 了!

那麼這篇文章,我們就會深入介紹一下,要如何在創建一個 Bean 出來之後,去初始化這個 Bean 的值

什麼是 Bean 的初始化?


所謂的「Bean 的初始化」,指的是 「在 Bean 被創建出來之後,對這個 Bean 去做一些初始值的設定」 ,譬如說把變數的值設定成 5,或是進行一些運算之類的,簡單的說就是對這個 Bean 去做初始的出廠設定就對了

舉個例子來說的話,我們可以來試著改寫一下之前所寫的 HpPrinter class,我們在這個 HpPrinter 裡面去加上一個 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,所以 Spring Boot 到時候就會為我們創建一個 hpPrinter 的 Bean 出來,並且存放在 Spring 容器裡面

不過到目前為止,因為我們沒有去設定 Bean 的初始化,因此 Spring Boot 就只會去把這個 Bean 給創建出來,並不會去為裡面的 count 值進行初始化,因此這個 hpPrinter Bean 裡面的 count 值就會是 0

https://ithelp.ithome.com.tw/upload/images/20231018/20151036AV3aMRqd6J.png

如果我們想要讓 Spring Boot 在創建這個 hpPrinter 出來之後,同時也去為這個 count 變數賦予一個初始值,那麼我們就可以使用 @PostConstruct 來幫助我們達成這件事!

初始化 Bean 的方法:@PostConstruct


@PostConstruct 的用途,就是 「為這個 Bean 去進行初始化」,因此我們就可以透過 @PostConstruct 的功能,去設定這個 Bean 中的變數的初始值了

還是上面那個 HpPrinter 的例子,如果我們想要把 HpPrinter 裡面的 count 變數的值,去初始化成 5 的話,那麼我們就可以這樣做:

我們可以在 HpPrinter 這個 class 裡面,去新增一個新的方法,並且在這個方法上面加上 @PostConstruct,這樣就可以在這個 「有加上 @PostConstruct 的方法中」,去初始化 Bean 的值了

https://ithelp.ithome.com.tw/upload/images/20231018/20151036KQLPotng2H.png

像是我們在 HpPrinter 裡面,就去新增了一個 initialize() 的方法,並且在這個方法上面,去加上了 @PostConstruct 這行程式,因此我們就可以在這個 initialize() 的方法中,去初始化這個 Bean 的值,譬如說我們可以把 count 的值設成 5 之類的

所以到時候,當 Spring Boot 創建完 Bean 時,Spring Boot 就會接著去執行 「有加上 @PostConstruct 的那個方法」(此處指的就是 initialize() 方法),進而去完成 Bean 的初始化!

因此在這個情境下,Spring Boot 就是會去執行 initialize() 方法去進行初始化,將 count 的值設定成 5,所以到時候儲存在 Spring 容器裡面的 hpPrinter Bean,他裡面的 count 變數的值就會是 5

https://ithelp.ithome.com.tw/upload/images/20231018/20151036pYTBN2M0uE.png

1. 使用 @PostConstruct 的注意事項之一:方法有特定格式

在前面有提到,我們是可以在 class 中新增一個方法,然後在該方法上加上 @PostConstruct,這樣就可以在「該方法裡面」,去寫上初始化 Bean 的程式

不過這個「被加上 @PostConstruct 的方法」,他在宣告上也是有一些格式需要遵守的:

  1. 這個方法必須是 public
  2. 這個方法的返回值必須是 void
  3. 這個方法「不能」有參數
  4. 這個方法的名字可以隨意取,不影響 Spring Boot 運作

所以綜合以上 4 點的話,基本上這個「初始化 Bean 的方法」,通常就會長得像是下面這個樣子

public void XXX();

其中 XXX 可以替換成大家喜歡的單字,常見的有 setup、init、initialize 之類的,皆可以拿來使用

2. 使用 @PostConstruct 的注意事項之二:一個 class 建議只有一個方法加上 @PostConstruct

在使用 @PostConstruct 去初始化 Bean 的時候,在同一個 class 中,建議一次只讓一個方法加上 @PostConstruct,不要同時在多個方法上,都加上 @PostConstruct

如果在同一個 class 中,同時有多個方法上面都加上 @PostConstruct,雖然 Spring Boot 程式仍舊是可以正常運行起來,但是我們無法知道 Spring Boot 會先執行哪一個方法去初始化 Bean,因此可能會造成程式邏輯的錯誤,並且後續也很難統一管理初始化的設定

因此就建議大家,在同一個 class 內,一次只使用一個 @PostConstruct,統一的去管理初始化的設定,這樣子不管是在維護上還是運作上,都是比較好的做法

補充 1:我們真的需要 @PostConstruct 嗎?


上面的例子因為比較簡單,所以有的人可能會覺得「為什麼不直接在宣告 count 變數的同時,把 count 值也設成 5 就好?感覺用 @PostConstrcut 有點多此一舉?」,不過其實在實務上,@PostConstruct 的用途還是滿多的

使用 @PostConstruct 來初始化的強項在於 @PostConstruct 可以進行複雜的初始化」,譬如說在 Map 裡生成預先定義好的數據、或是取得其他注入的 Bean 的資訊、或是檢查注入的 Bean 是否為 null 值....之類的,這些都是可以在 @PostConstruct 中做到的

因此在實務上,使用 @PostConstruct 來進行 Bean 的初始化是很常見的作法~

補充 2:初始化 Bean 的另一種方法


除了可以使用這篇文章所介紹的 @PostConstruct 去初始化 Bean 之外,其實也是有另一種方法可以去初始化 Bean 的,那就是「去實作 InitializingBean interface 裡面的 afterPropertiesSet 方法」,用這種寫法的初始化效果,是和使用 @PostConstruct 一模一樣的

不過因為「去實作 InitializingBean interface」算是比較舊的寫法,因此在此系列文中就沒有特別介紹到這部分,並且在實務上,也會建議大家盡量使用 @PostConstruct 來進行 Bean 的初始化

總結


這篇文章介紹了要如何使用 @PostConstruct,去對 Spring Boot 創建出來的 Bean 進行初始化,所以大家以後就可以透過 @PostConstruct,將存放在 Spring 容器中的 Bean 的值,進行初始的出廠設定了

那到這篇文章為止,我們就算是對 Spring IoC 有了比較多的認識,我們已經了解了什麼是 IoC、DI,什麼又是 Spring 容器和 Bean,也知道要怎麼樣在 Spring Boot 中使用 @Component@Autowired@Qualifier 以及 @PostConstruct 這些註解,去對 Bean 進行創建、注入、以及初始化

那麼下一篇文章,我們會延伸出去介紹,要如何透過 @Value 這個註解,將 Spring Boot 設定檔中的值給讀取到 Bean 裡面,讓我們所寫的 Java 程式可以去運用 Spring Boot 設定檔中的值,那麼我們就下一篇文章見啦!

相關連結



上一篇
Spring Boot 零基礎入門 (8) - 指定注入的 Bean - @Qualifier
下一篇
Spring Boot 零基礎入門 (10) - 讀取 Spring Boot 設定檔 - @Value、application.properties
系列文
Spring Boot 零基礎入門30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
rockywang
iT邦新手 5 級 ‧ 2024-10-08 18:38:52

請問不能直接使用建構子來初使 count 的數值嗎?

古古 iT邦新手 3 級 ‧ 2024-10-10 00:11:45 檢舉

建構子也是可以拿來初始化的!
只是就如同文中的「補充 1:我們真的需要 @PostConstruct 嗎?」提到的,使用 @PostConstruct 來初始化的強項在於 @PostConstruct 可以進行複雜的初始化」,所以通常在 Spring Boot 中,還是會優先使用 @PostConstruct 來進行初始化!

rockywang iT邦新手 5 級 ‧ 2024-10-11 10:52:02 檢舉

建構子不是一樣能進行複雜的初始化嗎? 這樣一說,請教建構子跟 @PostConstruct 的順序,應該是先建構子,等建構完成後,接著才會執行 @PostConstruct 對嗎?

如果建構子也能進行複雜的始化,與 @PostConstruct 的差異是什麼?

我要留言

立即登入留言