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

Java 設計模式精講:責任鏈模式與 Tomcat Filter 鏈實戰解析

     編輯:Java 相關知識

模式定義

責任鏈模式將請求的發送者與接收者解耦:多個處理者對象組成一條鏈,請求沿鏈傳遞,直到某個處理者處理它或到達鏈尾。發送者無需知道誰最終處理請求。

角色

角色說明
Handler (抽象處理者)定義處理請求接口 handleRequest(),持有 successor 引用
ConcreteHandler (具體處理者)實現處理邏輯:處理或轉發 successor.handleRequest()

純與不純責任鏈

  • 純:每個處理者要么全權處理,要么完全轉發,不允許部分處理後再轉發。請求必須被某處理者吸收。
  • 不純:允許部分處理後轉發,請求可能到達鏈尾無人處理。實際項目多為不純。

案例一:會餐費用審批流程

業務規則

  • 項目經理:審批 ≤ 500 元
  • 部門經理:審批 ≤ 1000 元
  • 總經理:審批任意金額

代碼實現

// 抽象處理者
public abstract class Handler {
    protected Handler successor;
    public void setSuccessor(Handler s) { this.successor = s; }
    public abstract String handleFeeRequest(String user, double fee);
}

// 具體處理者
public class ProjectManager extends Handler {
    @Override public String handleFeeRequest(String user, double fee) {
        if (fee < 500) {
            return "張三".equals(user) ?
                "成功:項目經理批准【" + user + "】" + fee + "元" :
                "失敗:項目經理駁回【" + user + "】" + fee + "元";
        }
        return successor != null ? successor.handleFeeRequest(user, fee) : "無人審批";
    }
}
public class DeptManager extends Handler {
    @Override public String handleFeeRequest(String user, double fee) {
        if (fee < 1000) {
            return "張三".equals(user) ?
                "成功:部門經理批准【" + user + "】" + fee + "元" :
                "失敗:部門經理駁回【" + user + "】" + fee + "元";
        }
        return successor != null ? successor.handleFeeRequest(user, fee) : "無人審批";
    }
}
public class GeneralManager extends Handler {
    @Override public String handleFeeRequest(String user, double fee) {
        if (fee >= 1000) {
            return "張三".equals(user) ?
                "成功:總經理批准【" + user + "】" + fee + "元" :
                "失敗:總經理駁回【" + user + "】" + fee + "元";
        }
        return successor != null ? successor.handleFeeRequest(user, fee) : "無人審批";
    }
}

// 客戶端組裝鏈
public class Client {
    public static void main(String[] args) {
        Handler pm = new ProjectManager();
        Handler dm = new DeptManager();
        Handler gm = new GeneralManager();
        pm.setSuccessor(dm);
        dm.setSuccessor(gm);

        System.out.println(pm.handleFeeRequest("張三", 300));  // 項目經理批准
        System.out.println(pm.handleFeeRequest("李四", 300));  // 項目經理駁回
        System.out.println(pm.handleFeeRequest("張三", 700));  // 部門經理批准
        System.out.println(pm.handleFeeRequest("張三", 1500)); // 總經理批准
    }
}

案例二:Tomcat Filter 鏈源碼深度解析

核心類

  • ApplicationFilterChain:責任鏈核心,實現 FilterChain 接口,持有 ApplicationFilterConfig[] filters 數組與位置指針 pos。
  • ApplicationFilterConfig:Filter 包裝器,持有 Filter 實例與配置元數據。
  • ApplicationFilterFactory:構建 Filter 鏈,從 StandardContext 讀取 web.xml 配置,實例化 Filter 並加入鏈。

鏈構建流程

  1. StandardWrapperValve.invoke() 調用 ApplicationFilterFactory.createFilterChain()。
  2. 工廠創建 ApplicationFilterChain,遍歷 FilterMap,匹配 URL/Servlet 名稱。
  3. 匹配成功則從 StandardContext 獲取 ApplicationFilterConfig,調用 filterChain.addFilter(config) 加入數組。
  4. 返回構建好的 filterChain,閥門調用 filterChain.doFilter(req, res) 啟動鏈。

doFilter 執行邏輯

// ApplicationFilterChain.internalDoFilter()
if (pos < n) {
    ApplicationFilterConfig config = filters[pos++];
    Filter filter = config.getFilter();
    // 安全管理器檢查...
    filter.doFilter(request, response, this); // 關鍵:傳遞 this (FilterChain) 讓 Filter 可繼續調用
}

用戶 Filter 實現:

public class MyFilter implements Filter {
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
        // 前置邏輯
        chain.doFilter(req, res); // 必須調用,否則鏈中斷
        // 後置邏輯
    }
}

調試驗證

在 StandardWrapperValve.invoke() 斷點可見調用棧:
invoke → createFilterChain → addFilter (多次) → doFilter → internalDoFilter → filter.doFilter → chain.doFilter → ...

優缺點總結

優點缺點
降低耦合:發送者無需知曉具體處理者性能開銷:請求需遍歷鏈,深鏈延遲明顯
靈活性:可動態增刪/重排處理者調試困難:邏輯分散在多個類,調用鏈長
單一職責:每個處理者只關注特定業務循環引用風險:誤配置可能導致死循環

最佳實踐

  1. 處理者盡量單一職責,避免大而全的 handleRequest。
  2. 提供建構器/工廠靈活組裝鏈,支援配置文件驅動(如 Tomcat)。
  3. 關鍵節點添加日誌/埋點,便於追蹤請求流向。
  4. 設置鏈長上限或超時機制,防止異常循環。
  5. 區分同步/異步處理者:耗時操作放入異步處理者,返回 CompletableFuture 或使用 Reactor 模式。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved