首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Servlet 生命週期注解 @PostConstruct 與 @PreDestroy 完整解析:執行順序、用法與避坑指南

     編輯:Java 綜合教學

Java EE 5+ 引入 @PostConstruct、@PreDestroy 規範化生命週期回調,替代傳統 init()/destroy() 的耦合寫法。本文詳細對比執行順序、代碼驗證、注意事項與最佳實踐。

核心規範

  • 修飾非靜態、無參、void、無拋出異常的方法。
  • 類可有多個此類方法,調用順序不保證(同類內通常按聲明順序)。
  • 屬於 JSR-250 (Common Annotations),需 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"); } }

運行輸出(Tomcat 啟動 → 請求 → 關閉)

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

控制台輸出

web.xml 配置(Servlet 3.0+ 可省略,註解掃描自動生效)

<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>

關鍵避坑指南

  1. @PostConstruct 中不可用 ServletConfig/Context:此時尚未注入,需在 init() 中獲取。
  2. @PreDestroy 執行後 Servlet 已不可服務:僅用於釋放數據源、線程池、緩存等資源。
  3. 異常處理:回調方法拋異常會中斷生命週期,容器記錄錯誤但繼續銷毀流程,建議內部 try-catch 記錄日志。
  4. 掃描性能影響:容器啟動掃描所有類檢查注解,大型項目可在 web.xml 設置 <web-app metadata-complete="true"> 關閉掃描(需在 web.xml 完整聲明所有 Servlet/Filter/Listener)。
  5. 容器版本要求:Tomcat 6.0+ (Servlet 2.5)、Jetty 7+、JBoss 6+、WebLogic 12c+。
  6. Spring 管理的 Bean:同樣支持 @PostConstruct/@PreDestroy,執行順序在 Spring 初始化/銷毀階段,與 Servlet 容器生命週期分離。

對比總結表

特性@PostConstructinit()@PreDestroydestroy()
規範來源JSR-250Servlet SpecJSR-250Servlet Spec
執行順序構造器後、init前@PostConstruct後destroy後@PreDestroy前
可訪問 ServletConfig否是是(尚未銷毀)是
適用範圍任意托管 Bean僅 Servlet/Filter任意托管 Bean僅 Servlet/Filter
推薦用法資源初始化(連接池、緩存)獲取初始化參數資源釋放同步清理 Servlet 級資源

掌握注解生命週期,讓資源管理從「散落在 init/destroy」變為「語義清晰、框架通用、可單元測試」的標準化模式。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved