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

Servlet 生命周期與工作原理深度解析:從 init 到 destroy 的完整旅程

     編輯:Java 綜合教學

Servlet 容器如何管理 Servlet:生命周期、請求處理、線程模型全景圖

Servlet 是 Java Web 的基石,理解其生命周期與工作原理,是掌握 Spring MVC、Filter、Listener 等上層框架的前提。本文系統梳理三大階段、加載時機、Service 分發邏輯、Tomcat 參數解析、銷毀觸發條件,並對比 Servlet 與 JSP 定位差異。

一、三大生命周期階段

  1. 初始化:容器創建實例 → 調用 init(ServletConfig),僅執行一次。
  2. 請求服務:每請求一線程調用 service(ServletRequest, ServletResponse)。
  3. 銷毀:容器關閉/重載/移除應用 → 調用 destroy(),釋放資源。

二、Servlet 加載時機

無 <servlet-mapping> 的 Servlet:配合 load-on-startup 用於啟動時初始化數據源、緩存、定時任務等全局資源。

三、請求處理核心流程

1. 入口:service 方法分發

// HttpServlet 源碼簡化
protected void service(HttpServletRequest req, HttpServletResponse resp) {
    String method = req.getMethod();
    if ("GET".equals(method)) doGet(req, resp);
    else if ("POST".equals(method)) doPost(req, resp);
    // ... PUT, DELETE, HEAD, OPTIONS, TRACE
    else throw new ServletException("不支持的方法: " + method);
}
  • GenericServlet 實現 Servlet 接口,提供 init/config/log 默認實現。
  • HttpServlet 繼承 GenericServlet,實現 HTTP 協議綁定:將 ServletRequest/Response 強轉為 HttpServletRequest/Response,再調用無參 service(req, resp) 分發到 doXxx。
  • 開發者必須重寫 doGet/doPost 等,父類默認返回 405/400 錯誤。

2. Tomcat 參數解析機制

// 內部實現簡化
private Hashtable<String, String[]> paramHashStringArray = new Hashtable<>();
// 解析 query string / body 後填充 Map
// 獲取:request.getParameter("key") → String
// 獲取多值:request.getParameterValues("key") → String[]
  • 使用 Hashtable(線程安全)而非 HashMap,因參數解析階段可能多線程並發寫入(早期版本)。
  • 現代 Tomcat 優化為無鎖解析 + 不可變快照,但對外 API 保持一致。

四、線程模型與共享狀態風險

  • Servlet 實例單例多線程:容器僅創建一個實例服務所有請求。
  • 實例變量非線程安全:private int count; 并发訪問會數據競態。
  • 解決方案:
    1. 無狀態設計:不定義實例變量,所有數據放方法局部變量。
    2. ThreadLocal 隔離:每線程獨享副本。
    3. 同步鎖 / 原子類:性能較差,慎用。

五、銷毀階段與資源釋放

public void destroy() {
    // 關閉數據庫連接池、線程池、文件句柄、定時任務
    // 移除 ThreadLocal 引用防內存洩漏
    super.destroy();
}

觸發場景:應用卸載、容器關閉、熱部署重載、Servlet 類刪除。

六、Servlet vs JSP 定位對比

條件說明
啟動加載web.xml <load-on-startup>1</load-on-startup>,容器啟動時實例化並 init。
首次請求無 load-on-startup,首次訪問時創建實例。
類文件更新開發模式下熱部署觸發重載,舊實例 destroy,新實例 init。
維度ServletJSP
本質Java 類模板文件(編譯為 Servlet)
擅長業務邏輯、流程控制、數據處理頁面渲染、標籤庫、前端展示
調試斷點、單步、重構友好行號映射複雜、EL 表達式難調試
職責分離Controller / ServiceView

最佳實踐:Servlet 做控制器分發,JSP/Thymeleaf/Freemarker 做視圖渲染,嚴禁在 JSP 中寫業務邏輯、JDBC 代碼。

七、Web 應用啟動順序

  1. 容器啟動 → 掃描 web.xml / ServletContainerInitializer。
  2. 實例化 load-on-startup Servlet、ServletContextListener、Filter。
  3. 調用 contextInitialized → 初始化 Spring 容器、連接池等。
  4. 應用就緒,接收請求。

八、總結

Servlet 生命周期由容器完全托管,開發者聚焦於 init 初始化資源、doXxx 處理業務、destroy 釋放資源。牢記「單例多線程、無狀態設計」,配合 Filter/Listener 構建完整 Web 應用骨架。

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