Java EE 5+ 引入 @PostConstruct、@PreDestroy 規範化生命週期回調,替代傳統 init()/destroy() 的耦合寫法。本文詳細對比執行順序、代碼驗證、注意事項與最佳實踐。
javax.annotation:javax.annotation-api 依賴(Java 9+ 模組化後需額外引入)。構造器 ↓ @PostConstruct 方法(依賴注入完成後、init() 前) ↓ init(ServletConfig) // Servlet 標準初始化 ↓ service(req, resp) // 每請求調用 ↓ destroy() // Servlet 標準銷毀 ↓ @PreDestroy 方法 // 最後釋放資源
package com.servlet;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;
public class AnnotationServlet extends HttpServlet {
private SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss.SSS");
public AnnotationServlet() {
System.out.println(df.format(new Date()) + " 構造器");
}
@PostConstruct
public void postConstruct() {
System.out.println(df.format(new Date()) + " @PostConstruct");
}
@Override public void init() throws ServletException {
log(df.format(new Date()) + " init()");
}
@Override protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
log(df.format(new Date()) + " service() -> " + req.getMethod());
super.service(req, resp);
}
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
log(df.format(new Date()) + " doGet()");
resp.getWriter().println("AnnotationServlet
");
}
@Override public void destroy() {
log(df.format(new Date()) + " destroy()");
}
@PreDestroy
public void preDestroy() {
System.out.println(df.format(new Date()) + " @PreDestroy");
}
}
10:00:00.123 構造器 10:00:00.125 @PostConstruct 10:00:00.126 init() --- 請求 --- 10:00:05.456 service() -> GET 10:00:05.457 doGet() --- 關閉/重新部署 --- 10:05:00.000 destroy() 10:05:00.001 @PreDestroy

<servlet> <servlet-name>AnnotationServlet</servlet-name> <servlet-class>com.servlet.AnnotationServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>AnnotationServlet</servlet-name> <url-pattern>/servlet/AnnotationServlet</url-pattern> </servlet-mapping>
init() 中獲取。web.xml 設置 <web-app metadata-complete="true"> 關閉掃描(需在 web.xml 完整聲明所有 Servlet/Filter/Listener)。| 特性 | @PostConstruct | init() | @PreDestroy | destroy() |
|---|---|---|---|---|
| 規範來源 | JSR-250 | Servlet Spec | JSR-250 | Servlet Spec |
| 執行順序 | 構造器後、init前 | @PostConstruct後 | destroy後 | @PreDestroy前 |
| 可訪問 ServletConfig | 否 | 是 | 是(尚未銷毀) | 是 |
| 適用範圍 | 任意托管 Bean | 僅 Servlet/Filter | 任意托管 Bean | 僅 Servlet/Filter |
| 推薦用法 | 資源初始化(連接池、緩存) | 獲取初始化參數 | 資源釋放 | 同步清理 Servlet 級資源 |
掌握注解生命週期,讓資源管理從「散落在 init/destroy」變為「語義清晰、框架通用、可單元測試」的標準化模式。