责任链模式:从 Sentinel 流控到审批流程的链式处理

责任链模式:从 Sentinel 流控到审批流程的链式处理

一、模式核心:让请求在链条中自由流转

在企业审批系统中,员工请假需依次经过直属领导、部门经理、总经理审批;在流量控制场景中,请求需依次经过阈值校验、黑白名单过滤、熔断降级等处理。这类场景的共同特点是:请求处理需经过多个环节,且环节顺序可动态调整。** 责任链模式(Chain of Responsibility Pattern)** 通过将处理节点连成链条,使请求沿链传递直至被处理,核心解决:

  • 解耦请求与处理:发送者无需知晓具体处理节点,只需将请求提交到链上

  • 动态流程编排:可灵活添加、删除处理节点或调整处理顺序

核心思想与 UML 类图

责任链模式通过抽象处理者定义统一接口,具体处理者决定是否处理请求并决定是否传递给下一个节点,形成递归处理链条:

二、核心实现:构建可插拔的审批流程链

1. 定义请求对象(封装请求数据)

java 复制代码
public class LeaveRequest {
    private String employeeName;    // 申请人
    private int days;              // 请假天数
    private String reason;          // 请假原因

    // 构造器、getter/setter省略
}

2. 抽象处理者(定义处理接口与链条传递逻辑)

java 复制代码
public abstract class Approver {
    protected Approver nextApprover; // 下一个处理者

    public void setNextApprover(Approver approver) {
        this.nextApprover = approver;
    }

    // 处理请求的抽象方法
    public abstract void processRequest(LeaveRequest request);
}

3. 具体处理者(实现不同层级的审批逻辑)

直属领导(处理 1-3 天请假)
java 复制代码
public class TeamLeader extends Approver {
    @Override
    public void processRequest(LeaveRequest request) {
        if (request.getDays() <= 3) {
            System.out.println("直属领导批准:" + request.getEmployeeName() + " 请假" + request.getDays() + "天");
        } else if (nextApprover != null) {
            nextApprover.processRequest(request); // 传递给上级
        }
    }
}
部门经理(处理 4-7 天请假)
java 复制代码
public class DepartmentManager extends Approver {
    @Override
    public void processRequest(LeaveRequest request) {
        if (request.getDays() <= 7) {
            System.out.println("部门经理批准:" + request.getEmployeeName() + " 请假" + request.getDays() + "天");
        } else if (nextApprover != null) {
            nextApprover.processRequest(request);
        }
    }
}
总经理(处理 7 天以上请假)
java 复制代码
public class GeneralManager extends Approver {
    @Override
    public void processRequest(LeaveRequest request) {
        if (request.getDays() > 7) {
            System.out.println("总经理批准:" + request.getEmployeeName() + " 请假" + request.getDays() + "天");
        } else if (nextApprover != null) {
            nextApprover.processRequest(request);
        }
    }
}

4. 客户端组装链条并发起请求

java 复制代码
public class ClientDemo {
    public static void main(String[] args) {
        // 组装审批链条
        Approver leader = new TeamLeader();
        Approver manager = new DepartmentManager();
        Approver gm = new GeneralManager();
        leader.setNextApprover(manager);
        manager.setNextApprover(gm);

        // 发起不同天数的请假请求
        LeaveRequest req1 = new LeaveRequest("张三", 2, "病假");
        leader.processRequest(req1); // 直属领导处理
        
        LeaveRequest req2 = new LeaveRequest("李四", 5, "年假");
        leader.processRequest(req2); // 部门经理处理
        
        LeaveRequest req3 = new LeaveRequest("王五", 10, "婚假");
        leader.processRequest(req3); // 总经理处理
    }
}

三、进阶:构建动态可配置的责任链

1. 使用枚举定义处理顺序(避免硬编码)

java 复制代码
public enum HandlerType {
    VALIDATION_HANDLER,
    RATE_LIMIT_HANDLER,
    CIRCUIT_BREAKER_HANDLER
}

// 责任链工厂类
public class HandlerFactory {
    private static final Map<HandlerType, Handler> HANDLER_MAP = new EnumMap<>(HandlerType.class);
    
    static {
        HANDLER_MAP.put(HandlerType.VALIDATION_HANDLER, new ValidationHandler());
        HANDLER_MAP.put(HandlerType.RATE_LIMIT_HANDLER, new RateLimitHandler());
    }
    
    public static Handler buildChain() {
        Handler handler1 = HANDLER_MAP.get(HandlerType.VALIDATION_HANDLER);
        Handler handler2 = HANDLER_MAP.get(HandlerType.RATE_LIMIT_HANDLER);
        handler1.setNext(handler2);
        return handler1;
    }
}

2. 实现异步责任链(支持非阻塞处理)

java 复制代码
public abstract class AsyncHandler {
    protected AsyncHandler nextHandler;
    
    public void setNext(AsyncHandler handler) {
        this.nextHandler = handler;
    }
    
    public abstract CompletableFuture<Void> handleAsync(Request request);
}

// 异步处理者示例
public class AsyncValidationHandler extends AsyncHandler {
    @Override
    public CompletableFuture<Void> handleAsync(Request request) {
        return CompletableFuture.runAsync(() -> {
            // 异步校验逻辑
            if (nextHandler != null) {
                nextHandler.handleAsync(request);
            }
        });
    }
}

3. 可视化责任链流程(Mermaid 流程图)

四、框架与源码中的责任链实践

1. Sentinel 流量控制(SlotChain 责任链)

  • 核心原理:请求通过多个 Slot(处理节点)依次处理,包括:
    1. NodeSelectorSlot(节点选择)
    1. ClusterBuilderSlot(集群统计)
    1. StatisticSlot(指标统计)
    1. AuthoritySlot(权限校验)
    1. FlowSlot(流量控制)
  • 源码关键类
java 复制代码
// SlotChainBuilder构建责任链
public class DefaultSlotChainBuilder implements SlotChainBuilder {
    @Override
    public SlotChain build() {
        SlotChain chain = new DefaultSlotChain();
        chain.addFirst(new NodeSelectorSlot());
        chain.addAfter(NodeSelectorSlot.class, new ClusterBuilderSlot());
        // 按顺序添加各个Slot
        return chain;
    }
}

2. Spring Security 过滤器链

  • FilterChainProxy管理多个Filter,请求依次经过:

    • SecurityContextPersistenceFilter
    • UsernamePasswordAuthenticationFilter
    • FilterSecurityInterceptor
  • 动态配置:通过http.addFilter()灵活添加自定义过滤器到链中

3. Servlet Filter 机制

  • 多个 Filter 组成责任链,通过FilterChain.doFilter()传递请求
java 复制代码
public interface Filter {
    void doFilter(ServletRequest request, ServletResponse response, FilterChain chain);
}

五、避坑指南:正确使用责任链的 4 个要点

1. 确保链有终止条件

  • ❌ 反模式:链条未设置最终处理者,导致请求无人处理

  • ✅ 最佳实践:添加默认处理者(如NoSupportHandler)

java 复制代码
public class NoSupportHandler extends Handler {
    @Override
    public void handleRequest(Request request) {
        System.out.println("无人处理此请求");
    }
}

2. 控制链的长度(避免性能损耗)

  • 过长的链条会增加方法调用栈深度,建议:

    • 使用@SuppressWarnings("PMD.LawOfDemeter")注解允许合理的链式调用
    • 对处理者进行分组(如校验组、限流组、熔断组)

3. 避免循环引用

  • 组装链条时确保nextHandler不会指向之前的节点
java 复制代码
// 错误示例:形成环
handlerA.setNext(handlerB);
handlerB.setNext(handlerA); 

4. 日志与调试支持

  • 在每个处理者中添加日志记录,方便排查请求处理路径
java 复制代码
public class ValidationHandler extends Handler {
    @Override
    public void handleRequest(Request request) {
        System.out.println("进入校验处理器:" + request.getType());
        // 处理逻辑
        if (nextHandler != null) {
            nextHandler.handleRequest(request);
        }
    }
}

六、总结:何时该用责任链模式?

适用场景 核心特征 典型案例
请求处理需多环节协作 处理步骤可动态组合,且顺序影响结果 审批流程、流控系统、日志处理
解耦请求发送与处理 发送者不关心具体处理者,只需提交请求到链上 中间件消息处理、异常处理链
流程可扩展性要求高 需要灵活添加、删除处理环节 工作流引擎、规则引擎

责任链模式通过「请求链式传递 + 处理者解耦」的设计,将复杂流程拆解为可独立维护的处理节点,使系统在面对流程变更时更具灵活性。下一篇我们将深入探讨命令模式,解析从撤销操作到分布式调度的命令封装实践,敬请期待!

扩展思考:责任链模式 vs 中介者模式

两者都用于解耦对象间交互,但核心差异在于:

模式 交互方式 结构特点 典型应用
责任链模式 链式传递,处理者间隐式关联 线性结构,处理者有序排列 审批流程、过滤器链
中介者模式 通过中介者集中调度 星型结构,中介者知晓所有对象 GUI 组件交互、微服务网关

理解这些差异,能帮助我们在设计复杂交互系统时做出更优选择。

相关推荐
东阳马生架构4 小时前
Sentinel源码—6.熔断降级和数据统计的实现二
java·sentinel
东阳马生架构1 天前
Sentinel源码—6.熔断降级和数据统计的实现
sentinel
东阳马生架构1 天前
Sentinel源码—2.Context和处理链的初始化一
sentinel
东阳马生架构1 天前
Sentinel源码—3.ProcessorSlot的执行过程一
sentinel
东阳马生架构1 天前
Sentinel源码—5.FlowSlot借鉴Guava的限流算法二
算法·sentinel·guava
东阳马生架构1 天前
Sentinel源码—5.FlowSlot借鉴Guava的限流算法
sentinel
东阳马生架构4 天前
Sentinel源码—4.FlowSlot实现流控的原理一
sentinel
东阳马生架构4 天前
Sentinel源码—4.FlowSlot实现流控的原理
sentinel