设计模式—责任链模式(完整工程面试详解)

发布时间:2026/7/10 21:43:37
设计模式—责任链模式(完整工程面试详解) 本文目录如下1. 为什么需要责任链模式1.1 责任链模式解决的核心痛点1.2 典型使用场景1.3 不适合责任链模式的场景2. 责任链模式核心体系与角色2.1 核心特点2.2 三大标准角色3. 责任链标准实战实现同步基础版3.1 业务场景3.2 第一步封装请求实体3.3 第二步抽象处理器3.4 第三步多个具体处理器3.5 客户端组装链条并调用3.6 代码核心分析4. 企业级成熟方案SpringBoot 责任链容器自动装配、可配置顺序4.1 业务标识常量4.2 请求载体4.3 抽象处理器增加所属业务标识、执行顺序4.4 具体处理器4.5 链路工厂按业务类型分组、自动构建对应链条4.6 业务 Service 调用4.7 测试示例5. 责任链模式优缺点5.1 优点5.2 缺点6. 工程常见痛点与解决方案6.1 忘记调用下一级处理器链条断裂6.2 链条节点过多串行执行RT过高6.3 手动组装链条维护麻烦6.4 链路日志缺失线上难以定位拦截节点6.5 循环引用、死链问题7. 高频面试易混模式核心区分7.1 责任链 vs 装饰器模式7.2 责任链 vs 模板方法模式7.3 责任链 vs 观察者模式7.4 责任链 vs 策略模式8. 主流框架落地面试高频8.1 Servlet Filter 过滤器8.2 SpringMVC Interceptor 拦截器8.3 Mybatis Interceptor 插件链8.4 Spring Security 安全过滤器链9. 核心总结1. 为什么需要责任链模式责任链模式是行为型设计模式。核心目标将多个处理逻辑封装为独立处理器串联成一条处理链条请求依次经过链条上所有处理器每个处理器自主判断是否处理、是否放行请求实现请求发送者与请求处理者完全解耦。核心设计思想单一职责、链式流转、按需拦截、分层处理。每个处理器只专注自身单一校验 / 处理逻辑互不耦合新增、删除、调整处理顺序无需修改原有业务代码。换句话讲业务存在多层连续校验、多级处理流程且处理节点需要灵活增删、调整执行顺序时避免多层 if-else 嵌套、硬编码串行调用把每一层逻辑抽成独立处理器通过链条统一流转请求彻底实现流程分层解耦。1.1 责任链模式解决的核心痛点a.多层校验逻辑嵌套臃肿参数校验、权限校验、风控校验、签名校验层层 if 嵌套主流程代码庞大可读性极差b.新增处理节点需修改核心流程每增加一层校验就要改动主业务方法违反开闭原则c.处理逻辑高度耦合各层级处理代码写在同一方法内无法单独复用、单独单元测试d.处理顺序固化难调整硬编码串行执行如需调换校验顺序需要大面积改动代码e.职责混乱定位问题困难多层逻辑混在一起出现异常难以定位是哪一层拦截失败。1.2 典型使用场景a.多级请求校验场景接口入参校验、登录权限校验、接口签名校验、风控黑名单校验b.多层业务处理流程订单创建前置校验、审批流普通审批→主管审批→总经理审批c.框架拦截过滤场景Servlet Filter、Spring Interceptor、Mybatis 拦截器d.日志、报文多级加工场景报文解密、参数脱敏、日志埋点、报文加密链式处理 e. 可灵活增减处理节点的业务活动规则校验、支付前置安全校验。1.3 不适合责任链模式的场景a.处理节点永久固定、无需调整顺序仅固定 2-3 层逻辑无拓展需求直接顺序调用更简洁b.节点之间强依赖、执行顺序不可变更且永久不变c.单次处理、无分层校验逻辑极简d.需要并行处理所有节点责任链默认串行流转不适合并发并行场景。2. 责任链模式核心体系与角色2.1 核心特点链式串联每个处理器持有下一个处理器引用形成完整处理链路自主控制流转处理器可选择处理请求后放行、处理后直接终止链条解耦发送与处理发起请求的客户端完全不感知有多少处理器、处理顺序高度可拓展新增处理器只需新增类调整链路仅修改组装逻辑不改动业务处理代码。2.2 三大标准角色请求实体Request封装本次处理的全部业务数据在整条链条中流转抽象处理器Handler定义统一处理接口持有下一级处理器引用提供设置后继处理器的方法具体处理器ConcreteHandler实现抽象处理方法完成自身专属逻辑自主决定放行或终止链条。3. 责任链标准实战实现同步基础版3.1 业务场景下单接口前置三层校验参数校验 → 登录权限校验 → 风控黑名单校验任意一层校验失败直接拦截终止链条全部校验通过才允许创建订单。3.2 第一步封装请求实体/** * 请求实体链条流转的数据载体 */ public class OrderRequest { // 用户ID private Long userId; // 商品ID private Long goodsId; // 订单金额 private BigDecimal amount; // 校验结果信息 private String msg; // 是否校验通过 private boolean pass true; // getter/setter public Long getUserId() { return userId; } public void setUserId(Long userId) { this.userId userId; } public Long getGoodsId() { return goodsId; } public void setGoodsId(Long goodsId) { this.goodsId goodsId; } public BigDecimal getAmount() { return amount; } public void setAmount(BigDecimal amount) { this.amount amount; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg msg; } public boolean isPass() { return pass; } public void setPass(boolean pass) { this.pass pass; } }3.3 第二步抽象处理器/** * 抽象处理器 */ public abstract class AbstractOrderHandler { // 持有下一个处理器形成链条 protected AbstractOrderHandler nextHandler; // 设置后继处理器 public void setNextHandler(AbstractOrderHandler nextHandler) { this.nextHandler nextHandler; } // 统一处理方法 public abstract void handle(OrderRequest request); }3.4 第三步多个具体处理器/** * 第一层参数校验处理器 */ public class ParamHandler extends AbstractOrderHandler { Override public void handle(OrderRequest request) { // 自身处理逻辑 if (request.getUserId() null || request.getGoodsId() null || request.getAmount() null) { request.setPass(false); request.setMsg(参数缺失下单失败); // 校验失败直接终止链条不执行下一级 return; } System.out.println(参数校验通过流转下一层); // 校验通过存在下一级则继续执行 if (nextHandler ! null) { nextHandler.handle(request); } } } /** * 第二层登录权限校验 */ public class LoginAuthHandler extends AbstractOrderHandler { Override public void handle(OrderRequest request) { // 模拟未登录用户ID0 if (request.getUserId().equals(0L)) { request.setPass(false); request.setMsg(用户未登录请先登录); return; } System.out.println(登录权限校验通过流转下一层); if (nextHandler ! null) { nextHandler.handle(request); } } } /** * 第三层风控黑名单校验 */ public class RiskBlackHandler extends AbstractOrderHandler { Override public void handle(OrderRequest request) { // 模拟黑名单用户ID999 if (request.getUserId().equals(999L)) { request.setPass(false); request.setMsg(当前用户存在风控限制禁止下单); return; } System.out.println(风控校验通过校验全部完成); if (nextHandler ! null) { nextHandler.handle(request); } } }3.5 客户端组装链条并调用public class ChainClient { public static void main(String[] args) { // 1. 创建所有处理器 AbstractOrderHandler paramHandler new ParamHandler(); AbstractOrderHandler authHandler new LoginAuthHandler(); AbstractOrderHandler riskHandler new RiskBlackHandler(); // 2. 组装链条参数→权限→风控 paramHandler.setNextHandler(authHandler); authHandler.setNextHandler(riskHandler); // 3. 构造请求 OrderRequest request new OrderRequest(); request.setUserId(1001L); request.setGoodsId(10001L); request.setAmount(new BigDecimal(99.9)); // 4. 从链条头部发起请求 paramHandler.handle(request); // 5. 输出结果 if (request.isPass()) { System.out.println(全部校验通过执行下单逻辑); } else { System.out.println(下单拦截 request.getMsg()); } } }3.6 代码核心分析每个处理器仅负责单一校验逻辑单一职责可独立修改、单独测试链条组装与业务处理完全分离调换执行顺序仅修改组装代码校验失败可直接 return 终止链条减少无效执行新增校验层只需新增 Handler无需修改原有任何处理器符合开闭原则。4. 企业级成熟方案SpringBoot 责任链容器自动装配、可配置顺序基础手写链条存在缺陷手动组装处理器项目庞大后组装代码杂乱无法动态控制执行顺序。企业项目结合 Spring IOC 自动注入所有处理器通过注解排序自动构建链路无需手动 setNext。4.1 业务标识常量public class BizConstant { // 下单业务链路 public static final String BIZ_ORDER ORDER; // 退款业务链路 public static final String BIZ_REFUND REFUND; }4.2 请求载体import java.math.BigDecimal; public class BizRequest { // 业务标识用于匹配链路 private String bizType; private Long userId; private Long orderId; private BigDecimal amount; private boolean pass true; private String msg; // getter/setter public String getBizType() { return bizType; } public void setBizType(String bizType) { this.bizType bizType; } public Long getUserId() { return userId; } public void setUserId(Long userId) { this.userId userId; } public Long getOrderId() { return orderId; } public void setOrderId(Long orderId) { this.orderId orderId; } public BigDecimal getAmount() { return amount; } public void setAmount(BigDecimal amount) { this.amount amount; } public boolean isPass() { return pass; } public void setPass(boolean pass) { this.pass pass; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg msg; } }4.3 抽象处理器增加所属业务标识、执行顺序public abstract class AbstractBizHandler { // 下一个处理器 protected AbstractBizHandler nextHandler; public void setNextHandler(AbstractBizHandler nextHandler) { this.nextHandler nextHandler; } // 处理逻辑 public abstract void handle(BizRequest request); // 存储业务类型集合的方式是为了做到复用也就是说一个处理器可能被多个业务使用到 public abstract SetString supportBizTypeSet(); // 执行顺序数字越小越先执行 public abstract int getOrder(); }4.4 具体处理器通用参数校验下单、退款都需要import org.springframework.stereotype.Component; import java.util.HashSet; import java.util.Set; Component public class ParamCheckHandler extends AbstractBizHandler { Override public void handle(BizRequest request) { if (request.getUserId() null || request.getAmount() null) { request.setPass(false); request.setMsg(参数不能为空); return; } if (nextHandler ! null) { nextHandler.handle(request); } } Override public SetString supportBizTypeSet() { SetString set new HashSet(); set.add(BizConstant.BIZ_ORDER); set.add(BizConstant.BIZ_REFUND); return set; } Override public int getOrder() { return 1; } }下单专属风控校验import org.springframework.stereotype.Component; import java.util.HashSet; import java.util.Set; Component public class OrderRiskHandler extends AbstractBizHandler { Override public void handle(BizRequest request) { if (request.getUserId().equals(999L)) { request.setPass(false); request.setMsg(下单风控拦截); return; } if (nextHandler ! null) { nextHandler.handle(request); } } Override public SetString supportBizTypeSet() { SetString set new HashSet(); set.add(BizConstant.BIZ_ORDER); return set; } Override public int getOrder() { return 2; } }退款专属余额校验import org.springframework.stereotype.Component; import java.math.BigDecimal; import java.util.HashSet; import java.util.Set; Component public class RefundBalanceHandler extends AbstractBizHandler { Override public void handle(BizRequest request) { if (request.getAmount().compareTo(new BigDecimal(1000)) 0) { request.setPass(false); request.setMsg(退款金额超限); return; } if (nextHandler ! null) { nextHandler.handle(request); } } Override public SetString supportBizTypeSet() { SetString set new HashSet(); set.add(BizConstant.BIZ_REFUND); return set; } Override public int getOrder() { return 2; } }4.5 链路工厂按业务类型分组、自动构建对应链条import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; Component public class BizChainFactory { Resource private ListAbstractBizHandler allHandlerList; // 缓存各业务链路头节点 private final MapString, AbstractBizHandler bizChainCache new HashMap(); // 根据业务类型获取对应链路头部处理器 public AbstractBizHandler getChainByBizType(String bizType) { // 缓存命中直接返回 if (bizChainCache.containsKey(bizType)) { return bizChainCache.get(bizType); } // 使用HashSet精准匹配无模糊匹配问题查询效率O(1) ListAbstractBizHandler matchHandlers allHandlerList.stream() .filter(h - h.supportBizTypeSet().contains(bizType)) // 按顺序升序 .sorted(Comparator.comparingInt(AbstractBizHandler::getOrder)) .collect(Collectors.toList()); if (matchHandlers.isEmpty()) { throw new RuntimeException(无对应业务处理链路 bizType); } // 串联处理器 for (int i 0; i matchHandlers.size() - 1; i) { AbstractBizHandler curr matchHandlers.get(i); AbstractBizHandler next matchHandlers.get(i 1); curr.setNextHandler(next); } AbstractBizHandler head matchHandlers.get(0); bizChainCache.put(bizType, head); return head; } }4.6 业务 Service 调用import org.springframework.stereotype.Service; import javax.annotation.Resource; Service public class BizOrderService { Resource private BizChainFactory chainFactory; public String doBiz(BizRequest request) { // 传入业务标识自动匹配专属链路 AbstractBizHandler chainHead chainFactory.getChainByBizType(request.getBizType()); chainHead.handle(request); if (!request.isPass()) { return 处理失败 request.getMsg(); } return 业务处理完成; } }4.7 测试示例public class TestMain { public static void main(String[] args) { BizOrderService service new BizOrderService(); // 下单链路 BizRequest orderReq new BizRequest(); orderReq.setBizType(BizConstant.BIZ_ORDER); orderReq.setUserId(1001L); orderReq.setAmount(new BigDecimal(99)); System.out.println(service.doBiz(orderReq)); // 退款链路 BizRequest refundReq new BizRequest(); refundReq.setBizType(BizConstant.BIZ_REFUND); refundReq.setUserId(1001L); refundReq.setAmount(new BigDecimal(500)); System.out.println(service.doBiz(refundReq)); } }5. 责任链模式优缺点5.1 优点分层解耦单一职责每一个处理器只处理一件事代码清晰易维护完美符合开闭原则新增校验 / 处理节点仅新增 Handler原有代码零改动灵活调整链路修改执行顺序、临时移除节点仅改动链条组装逻辑请求与处理分离发起请求方不用关心内部有多少处理步骤支持中断流程任意节点校验失败可直接终止链条减少无效执行。5.2 缺点链条过长时性能损耗串行逐层执行链路节点极多会拉长接口 RT排查链路问题困难多层流转异常需要逐层打印日志定位存在链条断裂风险处理器忘记调用 nextHandler.handle () 会导致后续逻辑不执行会产生大量处理器类每一层逻辑对应一个类项目类文件增多。6. 工程常见痛点与解决方案6.1 忘记调用下一级处理器链条断裂解决方案抽象层封装统一流转逻辑模板方法固定流程子类只重写业务逻辑统一后置放行。6.2 链条节点过多串行执行RT过高解决方案无依赖的独立节点抽取异步线程池并行执行强依赖节点保留串行。6.3 手动组装链条维护麻烦解决方案结合 Spring 容器自动注入通过排序注解自动构建链路无需硬编码串联。6.4 链路日志缺失线上难以定位拦截节点解决方案抽象处理器统一打印进入、退出日志记录当前处理器名称与拦截信息。6.5 循环引用、死链问题解决方案统一在工厂构建链条禁止运行时动态修改 nextHandler避免循环持有。7. 高频面试易混模式核心区分7.1 责任链 vs 装饰器模式责任链多条独立处理节点串行流转请求可中途终止链条各节点职责独立无包装关系装饰器层层包装同一对象持续叠加功能无法中途终止必须完整执行内层逻辑。7.2 责任链 vs 模板方法模式责任链多个独立类分层处理可灵活增删、调整顺序模板方法单一父类固定完整流程骨架步骤不可随意移除、顺序固化。7.3 责任链 vs 观察者模式责任链单个请求串行依次处理可中断流程有先后顺序观察者一对多并行通知无先后强制顺序无法中途终止其他订阅者执行。7.4 责任链 vs 策略模式责任链多层依次校验处理链式流转策略模式单一算法动态切换一次仅执行一套逻辑无分层流转。8. 主流框架落地面试高频8.1 Servlet Filter 过滤器标准责任链实现FilterChain 串联多个 FilterdoFilter 放行进入下一层可拦截终止请求。8.2 SpringMVC Interceptor 拦截器多个拦截器有序执行preHandle 返回 false 直接终止链路典型责任链思想。8.3 Mybatis Interceptor 插件链多个拦截器串联处理 SQL 执行依次流转可拦截修改 SQL 逻辑。8.4 Spring Security 安全过滤器链大量校验过滤器串联组成责任链权限、登录、跨域分层校验可自由新增过滤器。9. 核心总结责任链模式核心本质拆分分层处理逻辑串联成可灵活调整的执行链路请求逐层流转分层拦截解耦是接口校验、审批流程、框架拦截体系最常用的行为型模式。工程落地选型规范多层连续校验、需要灵活增删处理节点优先使用责任链小型项目可手写组装链条中大型 Spring 项目采用容器自动装配排序每个处理器严格遵循单一职责不混合多层校验逻辑控制链条长度节点过多拆分异步执行避免接口 RT 升高区分装饰器、模板方法不要混淆链式流转与功能增强、固定流程的设计目标。