關於@PostConstruct與@PreDestroy註解的使用詳解
一、@PostConstruct和@PreConstruct介紹
從JavaEE5規範開始,Servlet增加了兩個影響Servlet生命週期的註解(Annotation):@PostConstruct和@PreConstruct。
這兩個註解被用來修飾一個非靜態的void()方法,而且這個方法不能有丟擲異常宣告。
二、@PostConstruct的使用
@PostContruct是spring框架的註解,在方法上加該註解會在專案啟動的時候執行該方法,也可以理解為在spring容器初始化的時候執行該方法。
2.1 @PostConstruct在專案中的用處
2.1.1 spring專案載入資料字典
@PostConstruct註解的方法在專案啟動的時候執行這個方法,也可以理解為在spring容器啟動的時候執行,可作為一些資料的常規化載入,比如資料字典之類的。
2.1.2 spring專案的定時任務
spring自帶的@schedule,沒有開關,專案啟動總會啟動一個執行緒;做專案的時候就使用Java的timer,這個設定開關即可自由的控制,關閉的時候,不會啟動執行緒;Java的timer也需要找到一個啟動類,可以放到main函式裡面啟動,這樣的話,程式碼的耦合性太高了,而使用PostConstruct是很乾淨的。
spring中Constructor、@Autowired、@PostConstruct的順序
其實從依賴注入的字面意思就可以知道,要將物件p注入到物件a,那麼首先就必須得生成物件p與物件a,才能執行注入。
所以,如果一個類A中有個成員變數p被@Autowired註解,那麼@Autowired注入是發生在A的構造方法執行完之後的。
如果想在生成物件時候完成某些初始化操作,而偏偏這些初始化操作又依賴於依賴注入,那麼就無法在建構函式中實現。
為此,可以使用@PostConstruct註解一個方法來完成初始化,@PostConstruct註解的方法將會在依賴注入完成後被自動呼叫。
Constructor >> @Autowired >> @PostConstruct
2.2 特點:
- 只有非靜態方法能使用此註解
- 被註解的方法不得有任何引數
- 被註解的方法返回值必須為void
- 被註解方法不得丟擲已檢查異常
- 此方法只會被執行一次
2.3 使用
@PostConstruct public void someMethod(){}
或者
public @PostConstruct void someMethod(){}
被@PostConstruct修飾的方法會在伺服器載入Servle的時候執行,並且只會被伺服器執行一次。
@PostConstruct在建構函式之後執行,init()方法之前執行。PreDestroy()方法在destroy()方法執行執行之後執行!
被註解的Servlet生命週期
需要注意的是,註解會多多少少地影響到伺服器的啟動速度。
伺服器在啟動時候會遍歷Web應用的WEB-INF/classes下的所有class檔案與WEB-INF/lib下的所有jar檔案,以檢查哪些類使用了註解。
如果應用程式中沒有使用任何註解,可以在Web.xml中設定的metadata-complete屬性為true。
(支援@PostConstruct和 @PreDestroy的伺服器需要支援Servlet2.5規範。Tomcat5.x僅支援Servlet2.4規範。)
三、@PreDestroy註解使用
在開發中我們如果要在關閉spring容器後釋放一些資源,通常的做法有如下幾種:
1.在方法上加上@PreDestroy註解
2.實現DisposableBean介面,實現其destroy方法
3.1 使用場景
可以在bean例項被銷燬時,做一些清理工作,比如關閉一些資料庫或者網路的連線,記錄一些系統關閉的日誌資訊等。
執行時機
(1)Servlet中:在Servlet被伺服器解除安裝的時候執行,並且只會執行一次,被該註解修飾的方法會在Servlet的destroy方法執行之後,在Servlet被徹底解除安裝完成之前執行。
(2)Spring中:在Spring釋出容器關閉事件之後,在執行Bean的destroy方法之前執行。
3.2 @PreDestroy使用示例
例:在容器關閉的時候,刪除系統快取的和使用者資訊相關的快取檔案
標註在一個非靜態的void方法上,而且被標註的方法不能宣告丟擲異常:
點選檢視程式碼
@Service
public class UserService {
@PreDestroy
public void destroyUserService() {
// 可以在該步驟中清理系統的快取檔案
FileUtils.clearAllUserCacheFile();
System.out.println("context close...");
}
}