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

Servlet Filter 原理深度解析:鏈路調用順序、初始化參數與日誌記錄實戰

     編輯:Java 相關知識

Servlet Filter 是 Web 容器請求處理管道的核心擴展點。本文從 Filter 接口三大方法、鏈路調用順序(請求前→目標→響應後)、web.xml 映射規則、初始化參數讀取、ServletContext.log() 日誌記錄五個維度,配合兩個完整 Filter 示例(SimpleFilter1、SimpleFilter2)與控制台輸出,徹底講透 Filter 工作機制。

Filter 接口與生命周期

public interface Filter {
  void init(FilterConfig config) throws ServletException;  // 容器啟動時調用一次
  void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) 
      throws IOException, ServletException;                // 每請求調用
  void destroy();                                          // 容器關閉時調用一次
}

鏈路調用順序演示

配置兩個 Filter 映射 /*,順序為 filter1 → filter2:

<filter><filter-name>filter1</filter-name><filter-class>...SimpleFilter1</filter-class></filter>
<filter-mapping><filter-name>filter1</filter-name><url-pattern>/*</url-pattern></filter-mapping>
<filter><filter-name>filter2</filter-name><filter-class>...SimpleFilter2</filter-class></filter>
<filter-mapping><filter-name>filter2</filter-name><url-pattern>/*</url-pattern></filter-mapping>

控制台輸出:

Within SimpleFilter1:Filtering the Request...
Within SimpleFilter2:Filtering the Request...
Within SimpleFilter2:Filtering the Response...
Within SimpleFilter1:Filtering the Response...

結論:請求按配置順序正向傳遞(Filter1 → Filter2 → Servlet),響應按反向傳回(Servlet → Filter2 → Filter1)。chain.doFilter() 是分水嶺。

Filter 代碼模板

public class SimpleFilter1 implements Filter {
  private FilterConfig filterConfig;
  public void init(FilterConfig config) { this.filterConfig = config; }
  public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
    try {
      System.out.println("Within SimpleFilter1:Filtering the Request...");
      chain.doFilter(req, res);  // 必須調用,否則鏈路中斷
      System.out.println("Within SimpleFilter1:Filtering the Response...");
    } catch (IOException | ServletException e) { e.printStackTrace(); }
  }
  public void destroy() { this.filterConfig = null; }
}

報告型 Filter:記錄訪問主機與 URL

在 doFilter 中將 ServletRequest 強轉為 HttpServletRequest,獲取 getRemoteHost()、getRequestURL()、當前時間,輸出至標準流或日誌。

訪問時間過濾器:初始化參數 + ServletContext 日誌

web.xml 參數:

<init-param>
  <param-name>startTime</param-name><param-value>22</param-value>
</init-param>
<init-param>
  <param-name>endTime</param-name><param-value>6</param-value>
</init-param>

核心邏輯:

public void init(FilterConfig config) {
  this.config = config;
  context = config.getServletContext();
  formatter = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM);
  startTime = Integer.parseInt(config.getInitParameter("startTime"));
  endTime   = Integer.parseInt(config.getInitParameter("endTime"));
}

public void doFilter(...) {
  int currentHour = new GregorianCalendar().get(Calendar.HOUR_OF_DAY);
  if (isUnusualTime(currentHour, startTime, endTime)) {
    context.log("WARNING: " + req.getRemoteHost() + " accessed " 
        + req.getRequestURL() + " on " + formatter.format(new Date()));
  }
  chain.doFilter(req, res);
}

// 跨午夜判斷邏輯
private boolean isUnusualTime(int current, int start, int end) {
  if (start < end) return current >= start && current < end;      // 同一天
  else return !(current >= end && current < start);               // 跨午夜
}

Tomcat 日誌配置(server.xml):

<Logger className="org.apache.catalina.logger.FileLogger" 
        prefix="catalina_log." suffix=".txt" timestamp="true"/>

日誌文件生成於 <CATALINA_HOME>/logs/localhost_log.YYYY-MM-DD.txt,按天滾動。

關鍵提醒

  • FilterChain.doFilter() 必須調用,否則請求不會到達目標 Servlet/JSP。
  • 多 Filter 映射同一 url-pattern 時,web.xml 中聲明順序決定執行順序。
  • FilterConfig.getServletContext() 可訪問全局上下文,適合記錄審計日誌。
  • 初始化參數讀取時做好 NumberFormatException 容錯,提供默認值。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved