设计模式实战解读(九):责任链模式——流水线上层层把关的艺术

🔔 本文 5000+ 字深度原创,含完整代码示例和生产级落地方案。创作不易,如果对你有帮助,请点赞 👍 收藏 ⭐ 关注 🔥 三连支持,你的认可是我持续输出的最大动力!
本文是「设计模式实战解读」系列第九篇。系列文章统一按照 定义 → 痛点场景 → 模式结构 → 核心实现 → 真实应用 → 常见变种 → 优缺点 → 避坑指南 → FAQ 的结构展开,每篇聚焦一个模式讲透。


一句话定义

责任链模式(Chain of Responsibility):将请求沿着处理者链传递,每个处理者要么处理请求,要么传递给下一个处理者,实现请求发送者与处理者的解耦。

归属:行为型模式。


一、没有责任链时的痛点

假设你在做一个 API 网关的过滤器模块,一个请求进来后要经过多个处理步骤:

java 复制代码
public class GatewayService {

    public Response handle(Request request) {
        // 1. 参数校验
        if (request.getPath() == null || request.getMethod() == null) {
            return Response.badRequest("Missing required params");
        }

        // 2. 鉴权
        String token = request.getHeader("Authorization");
        if (!tokenValidator.validate(token)) {
            return Response.unauthorized("Invalid token");
        }

        // 3. 限流
        if (!rateLimiter.tryAcquire(request.getClientId())) {
            return Response.tooManyRequests("Rate limit exceeded");
        }

        // 4. 黑名单检查
        if (blacklistService.isBlocked(request.getClientId())) {
            return Response.forbidden("You are blocked");
        }

        // 5. 日志记录
        accessLog.record(request);

        // 6. 路由转发
        return routeService.forward(request);
    }
}

问题:

  1. 方法越来越长:每加一个处理步骤,方法就长一截
  2. 顺序硬编码:想调整处理顺序?只能手动挪代码
  3. 无法动态增减:想临时关掉限流、加个灰度判断?只能改代码重新发布
  4. 耦合度高:所有处理逻辑挤在一个类里,无法独立测试
  5. 违反开闭原则:新增处理步骤必须改已有方法

这就是经典的"管道式处理"问题------请求要经过 N 个步骤,每个步骤独立且可能有拦截(阻断请求)、放行(交给下一步)两种结果。


二、模式结构

复制代码
         Request
            │
            ↓
    ┌───────────────┐
    │  Handler 1    │ → 能处理?→ 处理完返回
    │  (参数校验)    │ → 不能?  → 传给下一个
    └───────┬───────┘
            │
            ↓
    ┌───────────────┐
    │  Handler 2    │ → 能处理?→ 处理完返回
    │  (鉴权)       │ → 不能?  → 传给下一个
    └───────┬───────┘
            │
            ↓
    ┌───────────────┐
    │  Handler 3    │ → 能处理?→ 处理完返回
    │  (限流)       │ → 不能?  → 传给下一个
    └───────┬───────┘
            │
            ↓
    ┌───────────────┐
    │  Handler N    │ → 最终处理
    └───────────────┘

三个角色:

  • Handler(处理者接口) :定义统一的 handle(context) 方法
  • ConcreteHandler(具体处理者):实现处理逻辑,决定"自己处理"还是"往下传"
  • Chain(链):管理处理者的顺序和传递逻辑

核心思想:每个 Handler 只关注自己的职责,通过链传递将责任解耦。


三、核心实现

3.1 基础版:链表式责任链

java 复制代码
// 处理者接口
public abstract class Handler<T> {
    private Handler<T> next;

    public Handler<T> setNext(Handler<T> next) {
        this.next = next;
        return next; // 链式构建
    }

    protected abstract boolean handle(T context);

    // 链传递逻辑
    public final void execute(T context) {
        boolean handled = handle(context);
        if (!handled && next != null) {
            next.execute(context);
        }
    }
}

// 具体处理者:参数校验
public class ParamValidationHandler extends Handler<ApiContext> {

    @Override
    protected boolean handle(ApiContext ctx) {
        if (ctx.getPath() == null) {
            ctx.setResponse(Response.badRequest("Missing path"));
            return true; // 已处理,不再传递
        }
        return false; // 未处理,继续传递
    }
}

// 具体处理者:鉴权
public class AuthHandler extends Handler<ApiContext> {

    @Override
    protected boolean handle(ApiContext ctx) {
        String token = ctx.getHeader("Authorization");
        if (!tokenValidator.validate(token)) {
            ctx.setResponse(Response.unauthorized("Invalid token"));
            return true;
        }
        return false;
    }
}

// 构建链
Handler<ApiContext> chain = new ParamValidationHandler();
chain.setNext(new AuthHandler())
     .setNext(new RateLimitHandler())
     .setNext(new BlacklistHandler())
     .setNext(new LoggingHandler())
     .setNext(new RoutingHandler());

chain.execute(context);

3.2 改进版:Spring 自动装配责任链

利用 Spring 的 List 注入 + @Order 排序,零手动维护链:

java 复制代码
// 处理者接口
public interface GatewayFilter {
    /**
     * 处理请求
     * @param context 请求上下文
     * @param chain 责任链,调用 chain.proceed() 传给下一个
     * @return true 表示已处理(阻断链),false 表示未处理(继续)
     */
    boolean doFilter(ApiContext context, FilterChain chain);

    default int getOrder() { return 0; }
}

// 具体处理者:参数校验
@Component
@Order(100)
public class ParamValidationFilter implements GatewayFilter {

    @Override
    public boolean doFilter(ApiContext context, FilterChain chain) {
        if (context.getPath() == null) {
            context.setResponse(Response.badRequest("Missing path"));
            return true; // 阻断
        }
        return chain.proceed(context); // 传递
    }
}

// 具体处理者:鉴权
@Component
@Order(200)
public class AuthFilter implements GatewayFilter {

    @Override
    public boolean doFilter(ApiContext context, FilterChain chain) {
        String token = context.getHeader("Authorization");
        if (!tokenValidator.validate(token)) {
            context.setResponse(Response.unauthorized("Invalid token"));
            return true;
        }
        return chain.proceed(context);
    }

    @Override
    public int getOrder() { return 200; }
}

// 具体处理者:限流
@Component
@Order(300)
public class RateLimitFilter implements GatewayFilter {

    @Autowired
    private RateLimiter rateLimiter;

    @Override
    public boolean doFilter(ApiContext context, FilterChain chain) {
        if (!rateLimiter.tryAcquire(context.getClientId())) {
            context.setResponse(Response.tooManyRequests("Rate limit exceeded"));
            return true;
        }
        return chain.proceed(context);
    }

    @Override
    public int getOrder() { return 300; }
}

// 责任链容器
@Component
public class FilterChain {

    private final List<GatewayFilter> filters;
    private int currentIndex = 0;

    public FilterChain(List<GatewayFilter> filters) {
        // Spring 自动按 @Order 排序注入
        this.filters = filters;
    }

    public boolean proceed(ApiContext context) {
        if (currentIndex < filters.size()) {
            GatewayFilter filter = filters.get(currentIndex++);
            return filter.doFilter(context, this);
        }
        return false; // 链结束
    }
}

// 使用
@Service
public class GatewayService {

    @Autowired
    private FilterChain filterChain;

    public Response handle(ApiContext context) {
        filterChain.proceed(context);
        return context.getResponse();
    }
}

新增一个过滤器 (比如灰度判断),只需加一个 @Component @Order(250) 的类------其他过滤器零改动。

3.3 函数式责任链(Java 8+)

java 复制代码
// 用 List<Function> 实现轻量级责任链
public class SimpleChain<T> {
    private final List<Predicate<T>> handlers = new ArrayList<>();

    public SimpleChain<T> addHandler(Predicate<T> handler) {
        handlers.add(handler);
        return this;
    }

    public void execute(T context) {
        for (Predicate<T> handler : handlers) {
            if (!handler.test(context)) {
                break; // handler 返回 false 表示阻断
            }
        }
    }
}

// 使用
new SimpleChain<ApiContext>()
    .addHandler(ctx -> ctx.getPath() != null)
    .addHandler(ctx -> tokenValidator.validate(ctx.getToken()))
    .addHandler(ctx -> rateLimiter.tryAcquire(ctx.getClientId()))
    .execute(context);

四、真实应用场景

4.1 框架级应用

框架 责任链实现 处理者
Servlet FilterChain Filter(编码/登录/跨域)
Spring MVC HandlerInterceptor 拦截器(鉴权/日志/权限)
Spring Security FilterChainProxy SecurityFilter(认证/授权/CSRF)
Netty ChannelPipeline ChannelHandler(编解码/业务处理)
MyBatis Interceptor 插件(分页/缓存/SQL改写)
APISIX / Nginx Plugin Chain 请求处理插件

4.2 Servlet FilterChain------最经典的工业级责任链

java 复制代码
// Servlet 规范定义的责任链
public interface FilterChain {
    void doFilter(ServletRequest request, ServletResponse response);
}

public interface Filter {
    void doFilter(ServletRequest request, ServletResponse response, FilterChain chain);
}

// 你的过滤器
public class EncodingFilter implements Filter {
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) {
        req.setCharacterEncoding("UTF-8");
        resp.setCharacterEncoding("UTF-8");
        chain.doFilter(req, resp); // 关键:传递给下一个
    }
}

chain.doFilter() 就是责任链的"传递信号"------调用它,请求继续往下走;不调用,请求在此阻断。

4.3 Netty ChannelPipeline------高性能责任链

java 复制代码
public class ServerInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel ch) {
        ChannelPipeline pipeline = ch.pipeline();

        // 按顺序添加 Handler,形成责任链
        pipeline.addLast("decoder", new HttpRequestDecoder());
        pipeline.addLast("encoder", new HttpResponseEncoder());
        pipeline.addLast("aggregator", new HttpObjectAggregator(65536));
        pipeline.addLast("auth", new AuthHandler());
        pipeline.addLast("business", new BusinessHandler());
    }
}

每个 Handler 处理完后调用 ctx.fireChannelRead(msg) 传递给下一个------Netty 高性能网络模型的核心设计。

4.4 iPaaS 流程执行的责任链

在 iPaaS 平台中,一个流程实例执行时,请求要经过多个中间件处理:

java 复制代码
// 流程执行上下文
public class FlowExecutionContext {
    private String instanceId;
    private FlowDefinition flow;
    private Map<String, Object> variables;
    private List<NodeResult> nodeResults;
    private boolean terminated = false;
}

// 流程执行责任链
public interface FlowExecutionFilter {
    boolean doFilter(FlowExecutionContext context, ExecutionChain chain);
}

// 处理者1:流程状态检查
@Component
@Order(100)
public class FlowStateCheckFilter implements FlowExecutionFilter {
    @Override
    public boolean doFilter(FlowExecutionContext context, ExecutionChain chain) {
        if (context.getFlow().getState() != FlowState.ACTIVE) {
            context.setTerminated(true);
            log.warn("流程未激活,跳过执行: {}", context.getInstanceId());
            return true;
        }
        return chain.proceed(context);
    }
}

// 处理者2:并发锁控制
@Component
@Order(200)
public class ConcurrentLockFilter implements FlowExecutionFilter {
    @Autowired
    private DistributedLockService lockService;

    @Override
    public boolean doFilter(FlowExecutionContext context, ExecutionChain chain) {
        String lockKey = "flow:lock:" + context.getInstanceId();
        try {
            if (!lockService.tryLock(lockKey, 30, TimeUnit.SECONDS)) {
                context.setTerminated(true);
                log.warn("获取执行锁失败: {}", context.getInstanceId());
                return true;
            }
            return chain.proceed(context);
        } finally {
            lockService.unlock(lockKey);
        }
    }
}

// 处理者3:幂等检查
@Component
@Order(300)
public class IdempotentCheckFilter implements FlowExecutionFilter {
    @Autowired
    private RedisTemplate<String, String> redis;

    @Override
    public boolean doFilter(FlowExecutionContext context, ExecutionChain chain) {
        String idempotentKey = "flow:idempotent:" + context.getInstanceId();
        if (Boolean.TRUE.equals(redis.hasKey(idempotentKey))) {
            log.warn("重复执行,跳过: {}", context.getInstanceId());
            context.setTerminated(true);
            return true;
        }
        redis.opsForValue().set(idempotentKey, "1", 1, TimeUnit.HOURS);
        return chain.proceed(context);
    }
}

// 处理者4:执行日志记录
@Component
@Order(400)
public class ExecutionLogFilter implements FlowExecutionFilter {
    @Override
    public boolean doFilter(FlowExecutionContext context, ExecutionChain chain) {
        long start = System.currentTimeMillis();
        log.info("开始执行流程: {}", context.getInstanceId());
        boolean result = chain.proceed(context);
        long cost = System.currentTimeMillis() - start;
        log.info("流程执行完成: {}, 耗时: {}ms", context.getInstanceId(), cost);
        return result;
    }
}

// 处理者5:实际执行
@Component
@Order(9999)
public class ActualExecutionFilter implements FlowExecutionFilter {
    @Override
    public boolean doFilter(FlowExecutionContext context, ExecutionChain chain) {
        // 真正的流程执行逻辑
        flowEngine.execute(context.getFlow(), context.getVariables());
        return false;
    }
}

这个链的优势:新增一个全局处理逻辑(比如灰度放量),只需加一个 @Component @Order(350) 的 Filter------流程引擎核心代码零改动。


五、常见变种

5.1 纯责任链(全部执行)vs 拦截型(可阻断)

java 复制代码
// 纯责任链:所有 Handler 都执行
public void execute(Context ctx) {
    for (Handler handler : handlers) {
        handler.handle(ctx);
    }
}

// 拦截型:某个 Handler 可以阻断链
public void execute(Context ctx) {
    for (Handler handler : handlers) {
        if (handler.handle(ctx)) {
            break; // 阻断
        }
    }
}

实际项目中拦截型更常见------鉴权失败直接返回,不执行后续逻辑。

5.2 责任链 + 策略模式

java 复制代码
// 责任链决定"谁来处理",策略模式决定"怎么处理"
public class RoutingFilter implements GatewayFilter {
    @Override
    public boolean doFilter(ApiContext context, FilterChain chain) {
        // 根据路径选择后端服务(策略)
        String backend = routeStrategy.select(context.getPath());
        context.setTargetBackend(backend);
        return chain.proceed(context);
    }
}

5.3 责任链 + 观察者模式

java 复制代码
// 责任链处理完后,发布事件通知观察者
public class ExecutionLogFilter implements FlowExecutionFilter {
    @Autowired
    private ApplicationEventPublisher eventPublisher;

    @Override
    public boolean doFilter(FlowExecutionContext context, ExecutionChain chain) {
        boolean result = chain.proceed(context);
        // 链执行完后发布事件
        eventPublisher.publishEvent(new FlowExecutionEvent(context.getInstanceId(), result));
        return result;
    }
}

六、优缺点

优点 缺点
处理者解耦,各自独立 链路过长时性能损耗
符合开闭原则(新增处理者不改已有代码) 调试困难(断点要打在链的每个节点)
处理顺序可动态调整(@Order) 责任链设计不当会导致请求在链中空转
可动态增减处理者 链路过长时堆栈深,异常难追踪
支持拦截和纯执行两种模式 责任链本身不解决"谁该处理"的问题,需要每个 Handler 自己判断

七、避坑指南

坑 1:忘记传递------Handler 处理完不调用 chain.proceed()

java 复制代码
// ❌ 处理完忘记传递,链在此中断
public class AuthFilter implements GatewayFilter {
    public boolean doFilter(ApiContext ctx, FilterChain chain) {
        if (!validate(ctx.getToken())) {
            ctx.setResponse(Response.unauthorized());
            return true;
        }
        // 忘记调 chain.proceed(ctx),后续过滤器全部不执行!
        return false;
    }
}

// ✓ 正确:处理完后继续传递
public class AuthFilter implements GatewayFilter {
    public boolean doFilter(ApiContext ctx, FilterChain chain) {
        if (!validate(ctx.getToken())) {
            ctx.setResponse(Response.unauthorized());
            return true;
        }
        return chain.proceed(ctx); // 关键:传递给下一个
    }
}

坑 2:Handler 顺序错误

java 复制代码
// ❌ 限流放在鉴权前面 → 未登录用户也能消耗限流配额
@Order(100) RateLimitFilter
@Order(200) AuthFilter

// ✓ 正确:先鉴权,再限流
@Order(100) AuthFilter
@Order(200) RateLimitFilter

原则:越基础、越应该靠前的检查放前面(参数校验 → 鉴权 → 限流 → 业务)。

坑 3:责任链中有状态

java 复制代码
// ❌ FilterChain 实例有状态(currentIndex),多线程并发会乱
@Component
@Scope("prototype") // 必须每次请求新建
public class FilterChain {
    private int currentIndex = 0;
    ...
}

// ✓ 无状态链:每次执行时创建新实例
@Service
public class GatewayService {
    @Autowired
    private List<GatewayFilter> filters;

    public Response handle(ApiContext context) {
        FilterChain chain = new FilterChain(filters); // 每次请求新建
        chain.proceed(context);
        return context.getResponse();
    }
}

坑 4:链路过长,性能损耗

如果责任链有 20 个 Handler,每个 Handler 都执行一遍,即使大部分是"检查后放行",也有性能损耗。

缓解方案

  • 控制链长度(≤ 10 个 Handler)
  • 合并相似的 Handler(多个参数校验合并为一个)
  • 对高频检查做缓存(鉴权结果缓存)

八、常见问题(FAQ)

Q:责任链模式和策略模式有什么区别?

A:核心意图不同:

  • 责任链:请求沿着链传递,每个处理者决定"是否处理"和"是否继续"
  • 策略:直接选择一个策略执行,策略之间互不干扰

责任链是"流水线",策略是"选择题"。

Q:责任链模式和装饰器模式有什么区别?

A:两者都是链式结构,但目的不同:

  • 责任链 :请求在链上传递,某个节点可能阻断
  • 装饰器 :请求一定会传递到最内层,每层装饰器都做增强

责任链可以"拦截",装饰器只会"增强"。

Q:Servlet Filter 和 Spring Interceptor 都是责任链吗?

A:是的。两者都实现了责任链模式:

  • Filter:Servlet 规范定义,在 DispatcherServlet 之前执行
  • Interceptor:Spring MVC 定义,在 Controller 之前执行

Filter 粒度更粗(请求级别),Interceptor 粒度更细(方法级别)。

Q:责任链中的 Handler 可以有依赖关系吗?

A:可以有,但不推荐。Handler 之间如果有依赖(比如 B 依赖 A 的处理结果),会导致链的顺序被隐式约束,维护困难。推荐通过 Context 对象传递数据,Handler 之间不直接依赖。

Q:什么时候该用责任链,什么时候该用 if-else?

A:

  • 用责任链:处理步骤多(≥ 3 个)、可能动态增减、需要独立测试
  • 用 if-else:处理步骤少(1-2 个)、逻辑简单、不会扩展

九、小结

责任链模式的核心价值:将多个处理步骤解耦为独立的处理者,通过链传递实现流水线式处理。

三个实践要点:

  1. Spring 项目用 List 注入 + @Order 排序------零手动维护链,新增 Handler 自动生效
  2. Handler 只关注自己的职责 ------处理完记得调用 chain.proceed(),除非你要阻断链
  3. 链顺序很重要------基础检查(参数/鉴权)放前面,业务处理放后面

下一篇我们聊建造者模式------当你需要构建一个复杂对象,且构建过程需要多个可选参数时,如何让代码既清晰又灵活。


标签:#设计模式 #责任链模式 #ChainOfResponsibility #行为型模式 #Java #Spring #Filter #Interceptor #网关过滤器 #流程引擎 #面向对象 #软件工程

相关推荐
basketball6161 小时前
C++进阶:2. std::move 和 std::forward 函数
java·开发语言·c++
霸道流氓气质1 小时前
Maven 批处理脚本与 Qoder 配置使用指南
java·maven
架构源启1 小时前
Spring AI进阶系列(14)- 2026 可观测性最佳实践:从链路追踪到企业级 AI 治理落地
java·人工智能·spring
码上有光1 小时前
c++: 继承(下)
android·java·c++·多继承·菱形继承·虚继承
JAVA9651 小时前
JAVA面试-并发篇 02-synchronized 锁可以重入吗
java·面试
RemainderTime1 小时前
Spring Boot脚手架集成Sa-Token实现生产级RBAC权限管理
java·spring boot·后端·系统架构
韦胖漫谈IT1 小时前
选语言不是站队,是选适合问题的工具
java·python·ai·rust·go·技术落地
lpd_lt1 小时前
AI生成Spring Boot + Vue 3 + MySQL + MyBatis-Plus的项目实战
java·spring boot·vue·ai编程
JAVA面经实录9171 小时前
Kafka 全套学习知识手册
java·kafka