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

Web 開發中 Servlet 技術全面解析:生命周期、請求處理、線程安全與配置實戰

     編輯:Java 綜合教學

Web 開發中 Servlet 技術全面解析:生命周期、請求處理、線程安全與配置啟動

Servlet 是 Java Web 核心控制層組件,運行於 Servlet 容器(Tomcat/Jetty)中,處理 HTTP 請求/響應。本文系統梳理 Servlet 定義、生命周期、核心 API、線程安全、部署配置、字符編碼、錯誤頁面、監聽器/過濾器等實戰知識點。

1. Servlet 是什麼?

  • 實現 javax.servlet.Servlet 接口(通常繼承 HttpServlet)的 Java 類。
  • 由容器管理生命周期,處理客戶端請求,生成動態響應。
  • MVC 模式中擔任 Controller(控制器):接收請求 → 調用 Service → 轉發/重定向到 View。

2. 生命周期三大方法

public class MyServlet extends HttpServlet {

    @Override
    public void init() throws ServletException {
        // 1. 實例化後、首次請求前調用(僅一次)
        // 適用:加載配置、初始化連接池、緩存預熱
        System.out.println("init() 執行");
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        // 2. 每次請求調用,分發到 doGet/doPost 等
        // 可在此處理通用邏輯(編碼、日志、權限)
        super.service(req, resp);
        System.out.println("service() 執行");
    }

    @Override
    public void destroy() {
        // 3. 容器卸載 Servlet 前調用(僅一次)
        // 適用:釋放資源、關閉連接池、保存狀態
        System.out.println("destroy() 執行");
    }
}

3. 定義 Servlet 必備步驟

  1. 類繼承 HttpServlet。
  2. 重寫 doGet/doPost(或 service)。
  3. 實現業務邏輯。
  4. web.xml 配置映射(或 Servlet 3.0+ @WebServlet 註解)。

4. 請求轉發與重定向

// 轉發(服務端跳轉,URL 不變,共享 request)
RequestDispatcher rd = request.getRequestDispatcher("/target.jsp");
rd.forward(request, response);

// 重定向(客戶端跳轉,URL 變化,新 request)
response.sendRedirect("/target.jsp");

5. 作用域對象

6. 線程安全核心問題

Servlet 默認單實例多線程:容器創建一個實例,每個請求分配一個線程調用 service()。

public class UnsafeServlet extends HttpServlet {
    private String username; // 實例變量 = 共享變量!

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
        username = req.getParameter("username"); // 線程 A 寫入 "Zhang"
        try { Thread.sleep(6000); } catch (InterruptedException e) {}
        resp.getWriter().write(username); // 線程 B 已改為 "Smith",A 也輸出 "Smith"!
    }
}

解決方案

  • 避免實例變量存儲請求狀態:使用局部變量(棧內存,線程私有)。
  • 若必須共享:使用 ThreadLocal、同步塊、ConcurrentHashMap、或請求作用域 request.setAttribute()。
  • 無狀態設計:Servlet 只做分發,業務邏輯委託給無狀態 Service Bean(Spring 默認單例,但無實例字段)。

7. web.xml 核心配置

<web-app>
    <!-- 歡迎頁面 -->
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

    <!-- Servlet 映射 -->
    <servlet>
        <servlet-name>MyServlet</servlet-name>
        <servlet-class>com.demo.MyServlet</servlet-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup> <!-- 啟動時加載 -->
    </servlet>
    <servlet-mapping>
        <servlet-name>MyServlet</servlet-name>
        <url-pattern>/myservlet</url-pattern>
    </servlet-mapping>

    <!-- 錯誤頁面 -->
    <error-page>
        <error-code>500</error-code>
        <location>/error/500.jsp</location>
    </error-page>
    <error-page>
        <exception-type>java.lang.NullPointerException</exception-type>
        <location>/error/500.jsp</location>
    </error-page>

    <!-- Session 超時(分鐘) -->
    <session-config>
        <session-timeout>30</session-timeout>
    </session-config>

    <!-- 過濾器 -->
    <filter>
        <filter-name>EncodingFilter</filter-name>
        <filter-class>com.demo.EncodingFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>EncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- 監聽器 -->
    <listener>
        <listener-class>com.demo.MySessionListener</listener-class>
    </listener>
</web-app>

8. 字符編碼處理

  • POST 表單:request.setCharacterEncoding("UTF-8")(必須在 getParameter() 前調用)。
  • GET 參數:Tomcat 8+ 默認 UTF-8;舊版需 URIEncoding="UTF-8" 在 server.xml <Connector>。或手動轉碼:new String(param.getBytes("ISO-8859-1"), "UTF-8")。
  • 響應輸出:response.setContentType("text/html;charset=UTF-8") 或 response.setCharacterEncoding("UTF-8")。
  • 轉發/重定向攜帶中文:重定向需 URLEncoder.encode(msg, "UTF-8"),接收端 URLDecoder.decode()。

9. 自動加載 Servlet (load-on-startup)

  • 值為正整數,數值越小越早加載。
  • 應用:啟動時預熱緩存(如加載字典表、初始化定時任務)。
  • 配合 ServletContextListener 實現應用級初始化(更推薦)。

10. 過濾器與監聽器

  • Filter:實現 Filter 接口,doFilter(req, resp, chain) 中調用 chain.doFilter() 放行。用途:編碼統一、登錄攔截、XSS 過濾、日志記錄、壓縮響應。
  • Listener:實現 ServletContextListener, HttpSessionListener, ServletRequestListener 等。用途:應用啟動初始化、Session 統計在線人數、請求耗時監控。

總結

Servlet 雖被 Spring MVC 等框架封裝,但其生命周期、線程模型、作用域、配置機制是理解框架原理、排查疑難雜症(如線程安全 Bug、編碼亂碼、內存洩漏)的基石。掌握原生 Servlet,方能駕馭上層框架。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
作用域獲取方式生命周期典型用途
Requestrequest.setAttribute()一次請求表單數據回顯、頁面間傳值
Sessionrequest.getSession().setAttribute()用戶會話(默認 30min)登錄狀態、購物車、用戶偏好
ApplicationgetServletContext().setAttribute()整個 Web 應用全局配置、緩存數據、計數器