设计模式之责任链模式

设计模式之责任链模式(Java 架构师深度详解)

前言

在企业级 Java 开发中,请求处理的解耦、功能的模块化扩展、复杂流程的灵活编排是架构设计的核心诉求。行为型设计模式专注于对象间的职责分配与通信,而责任链模式(Chain of Responsibility Pattern) 是其中最具实战价值的模式之一。它通过将请求处理者串联成一条链式结构,让请求沿着链传递,直至被某个处理者处理(或全部处理完毕),彻底解决了请求发送者与接收者的强耦合问题

作为 Java 架构师,本文将从基础定义、核心结构、Java 代码实现、设计 7 大原则契合度、实战应用场景、框架源码落地、优势劣势、最佳实践全维度深度拆解责任链模式,结合海量可运行代码示例,覆盖企业级开发全场景,满足架构设计与工程落地的双重需求。


第一章 责任链模式基础认知

1.1 官方定义与通俗解读

GoF 官方定义:责任链模式是一种行为型设计模式,允许你将请求沿着处理者链进行传递。收到请求后,每个处理者均可对请求进行处理,或将其传递给链上的下个处理者。

通俗解读

我们可以把责任链类比为公司请假审批流程:员工提交请假申请 → 组长审批(3 天内)→ 经理审批(3-7 天)→ 总监审批(7-15 天)→ 总经理审批(15 天以上)。

  • 员工(客户端)只需要提交申请,无需知道具体由谁审批;
  • 每个审批人(处理者)只负责自己权限内的申请,超出权限则传递给上级;
  • 所有审批人形成一条责任链,请求沿着链自动流转。

核心本质解耦请求的发送方与处理方,让多个对象都有机会处理请求,且处理逻辑可灵活组合、扩展。

1.2 核心角色(固定结构)

责任链模式包含 3 个核心角色,是所有实现的基础:

角色 英文名称 职责 Java 实现形式
抽象处理者 Handler 定义处理请求的统一接口,持有下一个处理者的引用,规定责任传递规则 抽象类 / 接口
具体处理者 ConcreteHandler 实现抽象处理者,处理自身负责的请求,无权处理则传递给下一个节点 普通 Java 类
客户端 Client 创建责任链,组装处理者顺序,向链头提交请求 业务调用方

1.3 纯责任链 vs 不纯责任链

责任链分为两种实现形式,是工程落地的核心区分点:

  1. 纯责任链

    严格遵循规则:

    请求必须被且仅被一个处理者处理,处理完成后立即终止链的传递。

    适用场景:请假审批、权限审批(唯一处理方)。

  2. 不纯责任链

    灵活规则:

    请求可以被多个处理者处理,也可以不被任何处理者处理,链会完整执行所有节点。

    适用场景:请求过滤、日志处理、数据校验(全链路处理)。

1.4 模式结构(UML 核心逻辑)

  1. 抽象 Handler:定义handleRequest()处理方法,包含nextHandler成员变量;
  2. 具体 Handler:重写handleRequest(),判断自身是否能处理,能则处理,不能则调用nextHandler.handleRequest()
  3. 客户端:将多个具体 Handler 按顺序串联,形成完整责任链。

第二章 Java 代码实现(从基础到工程化)

我们以企业最经典的请假审批场景为例,逐步实现基础版→纯责任链→不纯责任链→链式调用优化版,覆盖所有工程化写法。

2.1 基础版实现(纯责任链:请假审批)

步骤 1:定义请求实体(封装请假信息)

/**
 * 请假请求实体类
 */
public class LeaveRequest {
    // 员工姓名
    private String employeeName;
    // 请假天数
    private int leaveDays;
    // 请假原因
    private String reason;

    // 构造器、getter/setter
    public LeaveRequest(String employeeName, int leaveDays, String reason) {
        this.employeeName = employeeName;
        this.leaveDays = leaveDays;
        this.reason = reason;
    }

    // getter/setter 省略
    public int getLeaveDays() { return leaveDays; }
    public String getEmployeeName() { return employeeName; }
}

步骤 2:定义抽象处理者(Handler)

/**
 * 抽象审批处理者
 */
public abstract class LeaveApprover {
    // 下一个处理者
    protected LeaveApprover nextApprover;
    // 处理者名称
    protected String name;

    public LeaveApprover(String name) {
        this.name = name;
    }

    // 设置下一个处理者(核心:组装责任链)
    public void setNextApprover(LeaveApprover nextApprover) {
        this.nextApprover = nextApprover;
    }

    // 抽象处理方法:子类实现具体审批逻辑
    public abstract void handleRequest(LeaveRequest request);
}

步骤 3:定义具体处理者(组长、经理、总监)

/**
 * 具体处理者1:组长(审批≤3天的请假)
 */
public class GroupLeader extends LeaveApprover {
    public GroupLeader(String name) {
        super(name);
    }

    @Override
    public void handleRequest(LeaveRequest request) {
        if (request.getLeaveDays() <= 3) {
            System.out.printf("组长【%s】审批通过:员工【%s】请假%d天,原因:%s%n",
                    super.name, request.getEmployeeName(), request.getLeaveDays(), request.getReason());
        } else {
            // 无权处理,传递给下一个处理者
            System.out.printf("组长【%s】无权审批,传递给上级%n", super.name);
            if (nextApprover != null) {
                nextApprover.handleRequest(request);
            }
        }
    }
}

/**
 * 具体处理者2:经理(审批3-7天的请假)
 */
public class Manager extends LeaveApprover {
    public Manager(String name) {
        super(name);
    }

    @Override
    public void handleRequest(LeaveRequest request) {
        if (request.getLeaveDays() > 3 && request.getLeaveDays() <= 7) {
            System.out.printf("经理【%s】审批通过:员工【%s】请假%d天%n",
                    super.name, request.getEmployeeName(), request.getLeaveDays());
        } else {
            System.out.printf("经理【%s】无权审批,传递给上级%n", super.name);
            if (nextApprover != null) {
                nextApprover.handleRequest(request);
            }
        }
    }
}

/**
 * 具体处理者3:总监(审批7-15天的请假)
 */
public class Director extends LeaveApprover {
    public Director(String name) {
        super(name);
    }

    @Override
    public void handleRequest(LeaveRequest request) {
        if (request.getLeaveDays() > 7 && request.getLeaveDays() <= 15) {
            System.out.printf("总监【%s】审批通过:员工【%s】请假%d天%n",
                    super.name, request.getEmployeeName(), request.getLeaveDays());
        } else {
            System.out.printf("总监【%s】无权审批,传递给总经理%n", super.name);
            // 纯责任链:兜底处理(无上级则拒绝)
            System.out.println("请假天数超出权限,审批拒绝!");
        }
    }
}

步骤 4:客户端组装责任链并调用

/**
 * 客户端:创建责任链,提交请求
 */
public class Client {
    public static void main(String[] args) {
        // 1. 创建处理者
        LeaveApprover groupLeader = new GroupLeader("张三");
        LeaveApprover manager = new Manager("李四");
        LeaveApprover director = new Director("王五");

        // 2. 组装责任链:组长→经理→总监
        groupLeader.setNextApprover(manager);
        manager.setNextApprover(director);

        // 3. 提交请假请求
        LeaveRequest request1 = new LeaveRequest("小明", 2, "生病");
        LeaveRequest request2 = new LeaveRequest("小红", 5, "回家探亲");
        LeaveRequest request3 = new LeaveRequest("小刚", 10, "结婚");

        // 4. 从链头发起请求
        System.out.println("===== 请求1 =====");
        groupLeader.handleRequest(request1);
        System.out.println("===== 请求2 =====");
        groupLeader.handleRequest(request2);
        System.out.println("===== 请求3 =====");
        groupLeader.handleRequest(request3);
    }
}

运行结果

===== 请求1 =====
组长【张三】审批通过:员工【小明】请假2天,原因:生病
===== 请求2 =====
组长【张三】无权审批,传递给上级
经理【李四】审批通过:员工【小红】请假5天
===== 请求3 =====
组长【张三】无权审批,传递给上级
经理【李四】无权审批,传递给上级
总监【王五】审批通过:员工【小刚】请假10天

2.2 不纯责任链实现(日志过滤)

不纯责任链:请求会被所有匹配的处理者处理,适用于日志、过滤、校验场景。

// 抽象处理者
public abstract class LogFilter {
    protected LogFilter nextFilter;
    public void setNextFilter(LogFilter nextFilter) { this.nextFilter = nextFilter; }
    public abstract void doFilter(String logLevel, String message);
}

// 具体处理者1:Debug日志
public class DebugLogFilter extends LogFilter {
    @Override
    public void doFilter(String logLevel, String message) {
        if ("DEBUG".equals(logLevel)) {
            System.out.println("[DEBUG] " + message);
        }
        // 无论是否处理,都传递给下一个节点(不纯责任链核心)
        if (nextFilter != null) nextFilter.doFilter(logLevel, message);
    }
}

// 具体处理者2:Info日志
public class InfoLogFilter extends LogFilter {
    @Override
    public void doFilter(String logLevel, String message) {
        if ("INFO".equals(logLevel)) {
            System.out.println("[INFO] " + message);
        }
        if (nextFilter != null) nextFilter.doFilter(logLevel, message);
    }
}

// 客户端调用
public class LogClient {
    public static void main(String[] args) {
        LogFilter debug = new DebugLogFilter();
        LogFilter info = new InfoLogFilter();
        debug.setNextFilter(info);

        // 不纯责任链:全链路执行
        debug.doFilter("INFO", "用户登录成功");
        debug.doFilter("DEBUG", "查询用户信息");
    }
}

2.3 工程化优化:链式调用(Java8 优雅写法)

实际项目中,我们会结合建造者模式实现链式调用,简化责任链组装:

// 抽象处理者增加链式方法
public abstract class LeaveApprover {
    // ... 原有代码 ...
    // 链式组装:返回自身,支持连续调用
    public LeaveApprover appendNext(LeaveApprover nextApprover) {
        this.nextApprover = nextApprover;
        return nextApprover;
    }
}

// 客户端链式组装
public class OptimizeClient {
    public static void main(String[] args) {
        // 一行代码组装责任链:组长→经理→总监
        LeaveApprover chain = new GroupLeader("张三")
                .appendNext(new Manager("李四"))
                .appendNext(new Director("王五"));

        // 提交请求
        chain.handleRequest(new LeaveRequest("小李", 6, "旅游"));
    }
}

第三章 责任链模式与设计模式 7 大原则深度契合

设计模式 7 大原则是架构设计的黄金准则,责任链模式是最贴合 7 大原则的设计模式之一。作为架构师,必须理解其底层设计哲学:

3.1 单一职责原则(SRP)

原则定义:一个类 / 方法只负责一项职责,降低代码复杂度,提升可维护性。

责任链契合点

  • 每个具体处理者只负责单一的处理逻辑:组长只批 3 天内请假,经理只批 3-7 天,日志过滤器只过滤对应级别;

  • 处理逻辑完全解耦,一个节点的修改不会影响其他节点。

    GroupLeader类仅实现≤3 天的审批逻辑,无任何冗余代码。

3.2 开闭原则(OCP)

原则定义:对扩展开放,对修改关闭;新增功能不修改原有代码,仅通过扩展实现。

责任链契合点

  • 新增处理者无需修改任何原有处理者代码,仅需新增一个具体 Handler 类,重新组装链即可;
  • 完美支持业务迭代:比如请假审批新增「总经理」节点,只需新增GeneralManager类,无需修改组长、经理代码。
// 新增总经理处理者,完全不修改原有代码
public class GeneralManager extends LeaveApprover {
    @Override
    public void handleRequest(LeaveRequest request) {
        if (request.getLeaveDays() > 15) {
            System.out.println("总经理审批通过");
        }
    }
}

3.3 里氏替换原则(LSP)

原则定义:子类必须能替换父类 / 接口,且不破坏原有功能逻辑。

责任链契合点

  • 所有具体处理者都继承 / 实现抽象 Handler,严格遵循父类定义的契约(handleRequest方法);

  • 任意替换链中的处理者,责任链的执行逻辑不会崩溃。

    GroupLeaderManager都继承LeaveApprover,可互相替换,链的传递逻辑不变。

3.4 依赖倒置原则(DIP)

原则定义:依赖抽象,不依赖具体实现;高层模块不依赖低层模块,二者都依赖抽象。

责任链契合点

  • 客户端、责任链仅依赖抽象LeaveApprover,不依赖具体的GroupLeaderManager
  • 处理者之间的传递也依赖抽象,彻底解耦具体实现。
// 客户端依赖抽象,不依赖具体类
LeaveApprover nextApprover; // 抽象类型

3.5 接口隔离原则(ISP)

原则定义:客户端不依赖不需要的接口;接口粒度细化,避免冗余方法。

责任链契合点

  • 抽象 Handler 仅定义核心处理方法handleRequest),无任何多余方法;

  • 具体处理者只需实现必要逻辑,无需实现无用接口。

    代码佐证:

    LeaveApprover仅包含handleRequestsetNextApprover两个核心方法。

3.6 迪米特法则(最少知道原则,LOD)

原则定义:一个对象应尽可能少地了解其他对象,只与直接朋友通信。

责任链契合点

  1. 客户端:只知道链头处理者,无需知道链中其他节点,更无需知道处理逻辑;

  2. 处理者:只知道下一个处理者,无需知道链的全貌;

  3. 彻底降低对象间的耦合度。

    代码佐证:客户端仅调用groupLeader.handleRequest(),不知道经理、总监的存在。

3.7 合成复用原则(CRP)

原则定义:优先使用组合 / 聚合,而非继承实现代码复用。

责任链契合点

  • 责任链通过组合(持有下一个 Handler 的引用) 实现链的组装,而非继承;

  • 组合的灵活性远高于继承:可动态修改链的顺序、增删节点,继承无法实现。

    代码佐证:

// 组合复用:持有下一个处理者的引用
protected LeaveApprover nextApprover;

第四章 责任链模式的变体与扩展(企业级核心)

基础责任链无法满足所有企业场景,实际开发中会衍生出4 种核心变体,是架构设计的必备知识:

4.1 静态责任链 vs 动态责任链

  1. 静态责任链

    链的顺序、节点在代码中写死,运行时无法修改。

    适用:固定流程(如基础日志过滤)。

  2. 动态责任链

    链的顺序、节点通过配置文件 / 数据库 / 注解动态配置,运行时可修改。

    适用:OA 审批、网关过滤(核心企业场景)。

4.2 同步责任链 vs 异步责任链

  1. 同步责任链:请求按顺序同步执行,阻塞等待结果(默认实现);

  2. 异步责任链:通过线程池异步执行链节点,提升高并发场景性能。

    异步实现核心:

// 异步处理者
public abstract class AsyncHandler {
    protected AsyncHandler next;
    private static final ExecutorService EXECUTOR = Executors.newFixedThreadPool(5);

    public void setNext(AsyncHandler next) { this.next = next; }

    // 异步处理
    public void asyncHandle(Object request) {
        EXECUTOR.submit(() -> {
            doHandle(request);
            if (next != null) next.asyncHandle(request);
        });
    }

    protected abstract void doHandle(Object request);
}

4.3 拦截器模式(责任链经典变体)

Spring、MyBatis 中最常用的变体,核心是在请求前后增加拦截逻辑,结构:

preHandle→核心逻辑→postHandle→afterCompletion

4.4 过滤器模式(责任链 Web 场景变体)

Servlet、Spring Cloud Gateway 的核心实现,专注于请求 / 响应的过滤、修改


第五章 责任链模式实际项目应用场景(Java 企业级全场景)

责任链模式是Java 生态中应用最广泛的设计模式,几乎所有主流框架、企业级系统都有它的身影。作为架构师,必须掌握以下 8 大核心场景:

5.1 OA 系统工作流审批(最经典场景)

业务背景:企业 OA 系统包含请假、报销、采购、合同等审批流程,每个流程的审批人、权限、顺序不同。

痛点:传统 if-else 嵌套代码臃肿,新增流程需修改核心代码,违反开闭原则。

责任链落地

  • 抽象ApprovalHandler,具体实现LeaveHandlerReimburseHandler

  • 动态配置审批链(数据库存储流程节点);

  • 客户端仅提交申请,自动流转。

    优势:流程灵活配置,代码零修改,支持千级流程扩展。

5.2 权限校验责任链(微服务核心)

业务背景:用户请求接口需经过:登录校验→Token 校验→角色校验→资源权限校验→数据权限校验。

痛点:校验逻辑耦合在 Controller 中,代码冗余,难以维护。

责任链落地

// 抽象权限校验器
public interface AuthCheck {
    boolean check(HttpServletRequest request);
    AuthCheck setNext(AuthCheck next);
}

// 具体校验器:登录→Token→角色→资源
public class LoginCheck implements AuthCheck {/**/}
public class TokenCheck implements AuthCheck {/**/}
public class RoleCheck implements AuthCheck {/**/}

// 客户端:执行校验链
boolean pass = loginCheck.check(request);

优势:校验逻辑模块化,可按需开启 / 关闭校验节点,适配多端权限需求。

5.3 SpringMVC 拦截器(Web 框架核心)

框架落地:SpringMVC 的HandlerInterceptor是标准责任链实现:

  1. 抽象接口:HandlerInterceptor(preHandle/postHandle/afterCompletion);

  2. 具体拦截器:自定义登录拦截、日志拦截;

  3. 责任链容器:

    HandlerExecutionChain(组装所有拦截器)。

    执行流程:请求→拦截器 preHandle→Controller→拦截器 postHandle→视图渲染→afterCompletion。

5.4 Servlet 过滤器(Web 请求过滤)

Java Web 原生标准Filter+FilterChain是责任链的官方实现:

  • 抽象:Filter接口;
  • 链容器:FilterChain(传递请求给下一个 Filter);
  • 应用:跨域处理、编码转换、XSS 防护、请求日志。

5.5 Spring Cloud Gateway 网关过滤(微服务网关)

业务背景:网关需要对请求做鉴权、限流、日志、路由、跨域、请求头修改。

框架落地:Gateway 的GlobalFilter+GatewayFilterChain是异步责任链:

  • 所有全局过滤器形成一条链,请求进入网关后依次执行;
  • 支持动态配置过滤器顺序、禁用过滤器。

5.6 MyBatis 插件(ORM 框架核心)

框架落地:MyBatis 的插件机制是责任链 + 动态代理的结合:

  1. 抽象:Interceptor接口;
  2. 链容器:InterceptorChain
  3. 应用:SQL 监控、分页插件、数据脱敏、SQL 优化。

5.7 数据校验责任链(接口参数校验)

业务背景:接口参数需经过:非空校验→格式校验→业务规则校验→数据库唯一性校验。

责任链落地:每个校验器独立,失败直接返回错误信息,无需执行后续校验。

5.8 日志框架过滤(Logback/Log4j2)

框架落地:日志框架的过滤器链是不纯责任链:

  • 日志级别过滤、关键词过滤、输出格式过滤;
  • 所有过滤器依次执行,决定日志是否输出。

第六章 责任链模式的核心优势(架构设计核心价值)

责任链模式之所以成为企业级开发的首选模式,核心是它解决了传统代码的耦合、臃肿、难扩展三大痛点,带来 8 大核心优势:

6.1 彻底解耦请求发送者与处理者(核心优势)

  • 传统方式:客户端需要知道所有处理者,硬编码调用(if-else 嵌套);
  • 责任链:客户端仅提交请求给链头,无需知道谁处理、如何处理
  • 价值:请求方与处理方完全解耦,代码架构更清晰。

6.2 完美遵循开闭原则,极致扩展性

  • 新增处理逻辑无需修改任何原有代码,仅需新增具体 Handler;
  • 支持动态增删、调整链节点,适配业务快速迭代;
  • 价值:架构具备长期演进能力,降低维护成本。

6.3 单一职责,代码模块化、易维护

  • 每个处理者只负责一项逻辑,代码粒度细、职责清晰;
  • 单个节点故障不影响整个链,问题定位极快;
  • 价值:团队协作更高效,新人可快速接手代码。

6.4 灵活编排复杂业务流程

  • 支持静态 / 动态、同步 / 异步、纯 / 不纯多种链形式;
  • 可通过配置文件、数据库编排流程,无需重启服务;
  • 价值:适配 OA、微服务、网关等所有复杂流程场景。

6.5 简化客户端调用逻辑

  • 客户端仅需对接链头,一行代码发起请求;
  • 无需关心链的长度、顺序、处理逻辑;
  • 价值:调用方代码极简,降低出错概率。

6.6 责任明确,便于业务管控

  • 每个处理节点的职责、权限、边界清晰定义;
  • 可记录每个节点的处理日志,实现流程可追溯;
  • 价值:满足企业审计、合规需求。

6.7 支持请求的灵活处理

  • 纯责任链:唯一处理,终止传递;
  • 不纯责任链:全链路处理,无遗漏;
  • 价值:覆盖所有请求处理场景。

6.8 与其他设计模式完美融合

  • 可结合建造者模式实现链式调用;
  • 结合代理模式实现框架插件(MyBatis);
  • 结合策略模式实现动态处理逻辑;
  • 价值:架构设计更灵活,复合模式解决复杂问题。

第七章 责任链模式的劣势与解决方案(架构避坑)

7.1 核心劣势

  1. 性能损耗:链过长时,请求层层传递,同步执行会增加响应时间;
  2. 调试困难:请求在链中流转,难以定位处理节点;
  3. 循环引用风险:链组装错误会导致死循环;
  4. 请求丢失风险:纯责任链无兜底节点时,请求可能未被处理。

7.2 架构级解决方案

  1. 性能优化:异步责任链 + 线程池,缩短响应时间;限制链节点数量(≤10 个);
  2. 调试优化:增加链路日志,打印每个节点的入参、出参、处理结果;
  3. 循环引用防护:增加链校验逻辑,自动检测循环引用;
  4. 请求兜底:纯责任链必须增加兜底处理者,确保所有请求都被处理;
  5. 链路监控:结合 SkyWalking、Pinpoint 等 APM 工具,监控链执行耗时。

第八章 Java 主流框架源码中的责任链模式(架构师进阶)

8.1 Servlet Filter 源码解析

// 抽象处理者
public interface Filter {
    void doFilter(ServletRequest request, ServletResponse response, FilterChain chain);
}

// 责任链容器
public interface FilterChain {
    void doFilter(ServletRequest request, ServletResponse response);
}

核心逻辑:容器遍历所有 Filter,调用doFilterchain.doFilter()传递给下一个 Filter。

8.2 SpringMVC HandlerInterceptor 源码解析

// 抽象拦截器
public interface HandlerInterceptor {
    boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler);
}

// 责任链
public class HandlerExecutionChain {
    private final List<HandlerInterceptor> interceptors;
    // 依次执行所有拦截器
    boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) {
        for (HandlerInterceptor interceptor : interceptors) {
            if (!interceptor.preHandle(request, response, this.handler)) {
                return false;
            }
        }
        return true;
    }
}

8.3 MyBatis Interceptor 源码解析

// 抽象插件
public interface Interceptor {
    Object intercept(Invocation invocation) throws Throwable;
    // 组装责任链
    static Object pluginAll(Object target, InterceptorChain interceptorChain) {
        for (Interceptor interceptor : interceptorChain.interceptors) {
            target = interceptor.plugin(target);
        }
        return target;
    }
}

第九章 责任链模式最佳实践(企业级开发规范)

作为 Java 架构师,落地责任链模式必须遵循以下规范:

  1. 细粒度拆分节点:每个处理者只做一件事,符合单一职责;
  2. 动态配置链:优先使用配置文件 / 数据库管理链顺序,不硬编码;
  3. 兜底处理:纯责任链必须增加兜底节点,避免请求丢失;
  4. 链路日志:每个节点打印日志,便于调试;
  5. 控制链长度:节点数量≤10 个,避免性能损耗;
  6. 异步优化:高并发场景使用异步责任链;
  7. 异常处理:节点异常需捕获,避免链中断。

第十章 总结

责任链模式是行为型设计模式的巅峰之作,它以解耦、扩展、灵活为核心,完美契合设计模式 7 大原则,是 Java 企业级架构设计的必备技能

从工程落地角度:

  • 简单流程用静态同步责任链
  • 复杂流程用动态异步责任链
  • Web 场景用过滤器 / 拦截器(责任链变体);
  • 微服务网关、OA 审批、权限校验是其核心应用场景。

从架构价值角度:

责任链模式彻底解决了传统代码的耦合、臃肿、难扩展问题,让系统具备高内聚、低耦合、易维护、可演进的核心特性,是支撑企业级系统长期迭代的关键设计模式。

作为 Java 架构师,熟练掌握责任链模式,不仅能写出优雅、健壮的代码,更能设计出适配业务发展的弹性架构。

posted @ 2026-04-09 20:38  bright_ye  阅读(13)  评论(0)    收藏  举报