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

Java Web Servlet 技術深度解析:從入門到進階實戰

     編輯:Java 相關知識

前言

Servlet 是 Java Web 開發的基石。本文系統涵蓋:Servlet 核心介面、生命週期、初始化參數、ServletConfig/ServletContext 應用、URL 映射規則、執行緒安全、預設 Servlet、負載啟動等完整知識體系,並附帶最佳實踐與常見坑點。

核心架構

  • 頂層介面:javax.servlet.Servlet(5 方法:init、service、destroy、getServletConfig、getServletInfo)
  • 兩大實作基類:GenericServlet(協定無關)、HttpServlet(HTTP 專用,已實作 service 分派 doGet/doPost)
  • 開發慣例:繼承 HttpServlet,覆寫 doGet/doPost,勿覆寫 service。

第一支 Servlet 完整範例

@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        resp.setContentType("text/html;charset=UTF-8");
        resp.getWriter().write("Hello, Servlet!");
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        doGet(req, resp);
    }
}

Servlet 3.0+ 推薦用 @WebServlet 註解替代 web.xml。

生命週期三階段

階段觸發時機方法呼叫次數
初始化首次請求或啟動時 (load-on-startup)init()1 次
服務每次請求service() → doGet/doPostN 次
銷毀容器關閉/應用重載destroy()1 次

啟動載入 <load-on-startup>

@WebServlet(value = "/init", loadOnStartup = 1)
public class InitServlet extends HttpServlet {
    @Override public void init() {
        // 初始化連線池、載入配置、建立資料表...
    }
}

數值越小優先級越高;正整數才會啟動載入。

ServletConfig:單一 Servlet 初始化參數

@WebServlet(value = "/config", initParams = {
    @WebInitParam(name = "encoding", value = "UTF-8"),
    @WebInitParam(name = "maxSize", value = "1048576")
})
public class ConfigServlet extends HttpServlet {
    @Override public void init(ServletConfig config) {
        String encoding = config.getInitParameter("encoding");
        // ...
    }
}

ServletContext:全域共享與資源存取

三大核心功能

  1. 全域初始化參數:<context-param> → context.getInitParameter()
  2. 屬性共享 (Context 屬性):setAttribute/getAttribute/removeAttribute,所有 Servlet 可見,適合快取、共享資料源。
  3. 資源存取:getResourceAsStream("/WEB-INF/config.properties")、getRealPath()、getRequestDispatcher() 轉發/包含。

屬性共享範例

// Servlet A 寫入
context.setAttribute("appConfig", configObj);

// Servlet B 讀取
AppConfig cfg = (AppConfig) context.getAttribute("appConfig");

URL 映射規則與通配符優先順序

模式範例優先順序
精確路徑/user/profile最高
目錄通配/user/*次之
副檔名通配*.do, *.action再次之
預設 Servlet/最低

匹配原則:「最長路徑優先」→「目錄通配」→「副檔名通配」→「預設」。

執行緒安全:核心陷阱與解決方案

問題示範

public class UnsafeServlet extends HttpServlet {
    private int count = 0;  // 實例變數 = 共享變數
    protected void doGet(...) {
        count++;  // 非原子操作,併發下會丟失更新
        resp.getWriter().write("Count: " + count);
    }
}

解決方案對比

方案程式碼優點缺點
區域變數int count = 0; 在 doGet 內天然線程安全,無鎖開銷無法跨請求保持狀態
ThreadLocalThreadLocal<Integer> tl = new ThreadLocal<>();隔離執行緒狀態記憶體洩漏風險,需手動 remove
同步鎖synchronized(this) { count++; }簡單嚴重降低併發吞吐
原子類別AtomicInteger count = new AtomicInteger();無鎖高併發僅適用簡單計數/累加
無狀態設計Servlet 不保存狀態,狀態外移至 Redis/DB水平擴展最佳架構複雜度提升

黃金法則:Servlet 必須無狀態。所有請求相關資料放在區域變數、Request 屬性或外部分散式快取。

預設 Servlet 與靜態資源

Tomcat conf/web.xml 內建 DefaultServlet 映射 /,處理:靜態檔案 (HTML/CSS/JS/圖片)、目錄列表、預設歡迎頁。自訂 / 映射會覆蓋它,慎用。

最佳實踐清單

  • ✅ 使用 @WebServlet 註解,棄用 web.xml。
  • ✅ 繼承 HttpServlet,只覆寫 doGet/doPost。
  • ✅ Servlet 無狀態,共享資料用 ServletContext 屬性或外部存儲。
  • ✅ 初始化昂貴資源放在 init() + loadOnStartup=1。
  • ✅ 回應編碼統一設定:resp.setContentType("application/json;charset=UTF-8")。
  • ✅ 異常統一交由 <error-page> 或 Filter 處理,Servlet 不捕獲棧追蹤。

總結

Servlet 雖非現代框架 (Spring MVC, Jakarta REST) 的直接開發介面,但它是所有框架的運行基座。精通其生命週期、共享機制、URL 映射、執行緒模型,能讓你在排查疑難雜症、調優效能、設計架構時擁有底層視野。

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