设计模式-责任链模式

什么是责任链模式

责任链模式(Chain of Responsibility)将多个处理者连成一条链,请求沿链依次传递,每个处理者决定是否处理、是否继续向后传递。

核心思想:消灭多层 if-else 判断"谁来处理"的代码,将每个处理逻辑封装为独立的处理者,通过链式组合替代硬编码的分支判断。

适用场景

  • 订单风控(黑名单 → 金额限制 → 频率限制 → 实名认证)
  • 参数校验链(非空 → 格式 → 业务规则)
  • 审批流(组长 → 经理 → 总监 → CEO)
  • 敏感词过滤(关键词 → 正则 → AI 审核)
  • Web 过滤器 / 拦截器链

传统写法的问题

public Result riskCheck(Order order) {
    // 第一关:黑名单
    if (blackListService.isBlocked(order.getUserId())) {
        return Result.fail("用户在黑名单中");
    }
    // 第二关:金额上限
    if (order.getAmount().compareTo(new BigDecimal("50000")) > 0) {
        return Result.fail("单笔金额超限");
    }
    // 第三关:频率限制
    if (frequencyService.isOverLimit(order.getUserId())) {
        return Result.fail("操作过于频繁");
    }
    // 第四关:实名认证
    if (!kycService.isPassed(order.getUserId())) {
        return Result.fail("未完成实名认证");
    }
    return Result.ok();
}

问题

  1. 每新增一道风控规则,必须修改此方法,违反开闭原则
  2. 规则顺序写死在代码中,调整顺序需要改动核心逻辑
  3. 各规则无法单独测试和复用

Spring 最佳实践

1. 定义处理者接口

public interface RiskHandler {

    /**
     * 执行顺序,数值越小越先执行
     */
    int order();

    /**
     * 执行风控校验,返回 null 表示通过,继续向后传递
     */
    Result handle(Order order);
}

关键设计:接口中包含 order() 方法,链的构建顺序完全由各处理者自身声明,无需外部配置。

2. 实现各处理者(交给 Spring 管理)

@Component
public class BlackListHandler implements RiskHandler {

    private final BlackListService blackListService;

    @Override
    public int order() { return 1; }

    @Override
    public Result handle(Order order) {
        if (blackListService.isBlocked(order.getUserId())) {
            return Result.fail("用户在黑名单中");
        }
        return null; // 通过,继续向后
    }
}
@Component
public class AmountLimitHandler implements RiskHandler {

    private static final BigDecimal MAX_AMOUNT = new BigDecimal("50000");

    @Override
    public int order() { return 2; }

    @Override
    public Result handle(Order order) {
        if (order.getAmount().compareTo(MAX_AMOUNT) > 0) {
            return Result.fail("单笔金额超限");
        }
        return null;
    }
}
@Component
public class FrequencyHandler implements RiskHandler {

    private final FrequencyService frequencyService;

    @Override
    public int order() { return 3; }

    @Override
    public Result handle(Order order) {
        if (frequencyService.isOverLimit(order.getUserId())) {
            return Result.fail("操作过于频繁");
        }
        return null;
    }
}
@Component
public class KycHandler implements RiskHandler {

    private final KycService kycService;

    @Override
    public int order() { return 4; }

    @Override
    public Result handle(Order order) {
        if (!kycService.isPassed(order.getUserId())) {
            return Result.fail("未完成实名认证");
        }
        return null;
    }
}

3. 构建责任链(核心:Spring 自动注入 List)

@Component
public class RiskHandlerChain {

    private final List<RiskHandler> handlers;

    /**
     * Spring 自动将所有 RiskHandler 实现注入为 List
     * 在构造器中按 order() 排序,确保执行顺序正确
     */
    public RiskHandlerChain(List<RiskHandler> handlers) {
        this.handlers = handlers.stream()
                .sorted(Comparator.comparingInt(RiskHandler::order))
                .collect(Collectors.toUnmodifiableList());
    }

    /**
     * 沿链执行,遇到第一个不通过的处理者立即返回(短路)
     */
    public Result execute(Order order) {
        for (RiskHandler handler : handlers) {
            Result result = handler.handle(order);
            if (result != null) {
                return result;  // 被拦截,直接返回失败原因
            }
        }
        return Result.ok();
    }
}

List<RiskHandler> 注入时 Spring 会收集容器中所有实现。新增一道风控规则只需新建一个 @Component,无需修改任何现有代码。

4. 服务层调用(零 if-else)

@Service
@RequiredArgsConstructor
public class OrderService {

    private final RiskHandlerChain riskChain;

    public OrderVO createOrder(OrderRequest request) {
        Order order = Order.from(request);

        Result riskResult = riskChain.execute(order);
        if (!riskResult.isSuccess()) {
            throw new BusinessException(riskResult.getMessage());
        }

        // 风控通过,继续业务逻辑
        return doCreate(order);
    }
}

两种执行模式

责任链有两种执行语义,核心区别在于:处理者失败后是立即中断还是继续向后传递

拦截链(遇到处理者拦截即短路,上面的风控就是这种):

请求 → Handler1 通过 → Handler2 通过 → Handler3 拦截 ✗ → 返回失败

管道链(所有处理者都执行,常用于数据加工):

处理者返回带状态的 ProcessResult,链根据结果决定是中断还是继续。

public interface DataProcessor {
    int order();
    // 返回 ProcessResult,包含加工后的数据和是否成功
    ProcessResult process(OrderData data);
}

@Value
public class ProcessResult {
    boolean success;
    OrderData data;
    String errorMsg;

    public static ProcessResult ok(OrderData data) {
        return new ProcessResult(true, data, null);
    }

    public static ProcessResult fail(String errorMsg) {
        return new ProcessResult(false, null, errorMsg);
    }
}
@Component
public class DataProcessChain {

    private final List<DataProcessor> processors;

    public DataProcessChain(List<DataProcessor> processors) {
        this.processors = processors.stream()
                .sorted(Comparator.comparingInt(DataProcessor::order))
                .collect(Collectors.toUnmodifiableList());
    }

    public ProcessResult process(OrderData data) {
        for (DataProcessor processor : processors) {
            ProcessResult result = processor.process(data);
            if (!result.isSuccess()) {
                // 快速失败:某一步加工失败,立即中断
                log.error("[管道链] 处理失败 processor={} msg={}",
                        processor.getClass().getSimpleName(), result.getErrorMsg());
                return result;
            }
            data = result.getData();  // 加工结果传给下一个处理者
        }
        return ProcessResult.ok(data);
    }
}

管道链失败策略:

  • Fail-Fast(快速失败):某步失败立即 return,适合上游结果是下游输入的强依赖场景
  • Best-Effort(容错继续):某步失败记录日志后 continue,适合各步骤相互独立、允许部分失败的场景(如异步通知、数据同步)

两者代码差异只有一行:return result 换成 continue,按业务选择即可。

框架中的责任链

Spring 和 Java 生态中责任链随处可见,理解模式本质后再看这些框架实现会非常清晰。

Servlet Filter(标准管道链):

@Component
@Order(1)
public class AuthFilter implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        // 前置处理
        if (!isAuthenticated(req)) {
            ((HttpServletResponse) res).sendError(401);
            return;  // 短路,不调用 chain.doFilter 即中断链
        }
        chain.doFilter(req, res);  // 调用才继续向后传递
        // 后置处理(响应返回时执行)
    }
}

Spring HandlerInterceptor:

@Component
public class RateLimitInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        if (isOverLimit(request)) {
            response.setStatus(429);
            return false;  // 返回 false 中断链
        }
        return true;  // 返回 true 继续向后
    }
}

FilterChain.doFilter()HandlerInterceptor.preHandle() 的返回值,本质上都是"是否继续向后传递"的控制开关,与我们手写的责任链逻辑完全一致。

进阶:用 @Order 注解替代 order() 方法

如果不想在接口中定义 order() 方法,可以直接用 Spring 的 @Order 注解,Spring 注入 List 时会自动按 @Order 值排序:

public interface RiskHandler {
    Result handle(Order order);
}

@Component
@Order(1)
public class BlackListHandler implements RiskHandler { ... }

@Component
@Order(2)
public class AmountLimitHandler implements RiskHandler { ... }

@Component
public class RiskHandlerChain {

    // Spring 注入时已按 @Order 排好序,无需手动排序
    private final List<RiskHandler> handlers;

    public RiskHandlerChain(List<RiskHandler> handlers) {
        this.handlers = List.copyOf(handlers);
    }
}

推荐在接口中定义 order() 方法而非依赖 @Order,因为 order() 是接口契约的一部分,实现类必须显式声明优先级,不会因漏加注解而导致顺序错乱。

本文作者:
本文链接: https://hgnulb.github.io/blog/2026/37198628
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!