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

Java Web Filter 完整指南:核心概念、生命週期與鏈式調用實戰

     編輯:Java 程式設計入門

什麼是 Filter?

在 Java Web 開發中,Filter(過濾器/攔截器) 是一個實現 javax.servlet.Filter 介面的類別,主要用於攔截對 Servlet 的請求與響應。它能在 Servlet 處理請求前後執行特定邏輯,常見應用包括:字符編碼統一、權限驗證、日誌記錄、敏感詞過濾、壓縮響應等。

Filter 核心三大方法

Filter 介面定義了三個關鍵方法,掌握它們的調用時機至關重要:

  • init(FilterConfig filterConfig):初始化階段。Web 容器啟動時實例化 Filter 並調用此方法,僅執行一次。若需使用 FilterConfig 獲取初始化參數(如 <init-param>),必須在這裡完成,構造函數無法獲取該對象。
  • doFilter(ServletRequest, ServletResponse, FilterChain):核心攔截邏輯。每次請求進來都會調用。參數 chain 代表過濾器鏈,必須調用 chain.doFilter(request, response) 才能將請求傳遞給下一個 Filter 或目標 Servlet,否則請求會被攔截終止。
  • destroy():銷毀階段。Web 容器卸載 Filter 前調用,用於釋放資源(關閉資料庫連線、IO 流等),僅執行一次。

實戰一:編寫第一個 Filter

1. 目標 Servlet (Index.java)

package com.net;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class Index extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        PrintWriter out = response.getWriter();
        out.println("Index");
    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

2. 自定義 Filter (MyFilter.java)

package com.net;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class MyFilter implements Filter {
    public void init(FilterConfig fConfig) throws ServletException {
        System.out.println("MyFilter.init()");
    }
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        PrintWriter out = response.getWriter();
        out.println("Hello MyFilter"); // 在目標 Servlet 之前輸出
        chain.doFilter(request, response); // 傳遞給下一個環節
    }
    public void destroy() {
        System.out.println("MyFilter.destroy()");
    }
}

3. web.xml 配置

<filter>
    <filter-name>MyFilter</filter-name>
    <filter-class>com.net.MyFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>MyFilter</filter-name>
    <url-pattern>/Index</url-pattern> <!-- 攔截 /Index 路徑 -->
</filter-mapping>

<servlet>
    <servlet-name>Index</servlet-name>
    <servlet-class>com.net.Index</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>Index</servlet-name>
    <url-pattern>/Index</url-pattern>
</servlet-mapping>

4. 測試結果

訪問 /Index,控制台輸出 MyFilter.init(),頁面顯示:

Hello MyFilter
Index

第一個 Filter 測試結果

進階:Filter 鏈

當配置多個 Filter 攔截同一路徑時,會形成責任鏈模式。調用順序取決於 web.xml 中 <filter-mapping> 的聲明順序。

第二個 Filter (MyFilter2.java)

public class MyFilter2 implements Filter {
    public void init(FilterConfig fConfig) throws ServletException { }
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        PrintWriter out = response.getWriter();
        out.println("Hello MyFilter2 Start");
        chain.doFilter(request, response); // 關鍵:執行完後續邏輯再返回
        out.println("Hello MyFilter2 End"); // 響應階段輸出
    }
    public void destroy() { }
}

web.xml 多 Filter 配置

<filter> <filter-name>MyFilter</filter-name> <filter-class>com.net.MyFilter</filter-class> </filter>
<filter-mapping> <filter-name>MyFilter</filter-name> <url-pattern>/Index</url-pattern> </filter-mapping>

<filter> <filter-name>MyFilter2</filter-name> <filter-class>com.net.MyFilter2</filter-class> </filter>
<filter-mapping> <filter-name>MyFilter2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 攔截所有路徑 -->

<servlet> ... </servlet> <servlet-mapping> ... </servlet-mapping>

執行流程圖解

Filter 鏈示意圖

實際調用順序

請求階段: Request → MyFilter → MyFilter2 → Index(Servlet)
響應階段: Response ← MyFilter ← MyFilter2 ← Index(Servlet)

注意:MyFilter2 的 chain.doFilter() 之後的代碼會在響應返回時執行,這雙向特性是實現「請求預處理 + 響應後處理」的關鍵。

Filter 鏈測試結果

Filter 生命週期深度解析

  • 創建與銷毀:由 Web 容器管理。應用啟動時實例化、調用 init();關閉時調用 destroy()。全生命週期只有一個實例,init() 僅執行一次。
  • FilterConfig 作用:封裝 web.xml 中的註冊信息,提供獲取初始化參數、Filter 名稱、ServletContext 等方法。

FilterConfig 介面方法

使用初始化參數示例

<filter>
    <filter-name>MyFilter</filter-name>
    <filter-class>com.net.MyFilter</filter-class>
    <init-param>
        <param-name>like</param-name>
        <param-value>java</param-value>
    </init-param>
</filter>
public void init(FilterConfig fConfig) throws ServletException {
    System.out.println("MyFilter.init()");
    String filterName = fConfig.getFilterName(); // 獲取 filter-name
    String initParam = fConfig.getInitParameter("like"); // 獲取 init-param 值
    System.out.println(filterName); // 輸出: MyFilter
    System.out.println(initParam);  // 輸出: java
}

最佳實踐總結

  1. 順序敏感:web.xml 中 <filter-mapping> 順序決定執行順序,設計時務必規劃好。
  2. 必須調用 chain.doFilter():否則請求鏈中斷,後續 Filter 與 Servlet 皆不會執行。
  3. 線程安全:單實例多線程共享,成員變量需謹慎使用,避免併發問題。
  4. 資源釋放:在 destroy() 中關閉數據源、線程池等長連接資源。
  5. 現代替代方案:Spring Boot 中推薦使用 @WebFilter 註解或 FilterRegistrationBean 程式化配置,減少 XML 依賴。

Filter 是 Java Web 基礎設施的基石,深入理解其生命週期與鏈式機制,對構建健壯、可維護的 Web 應用至關重要。

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