当前位置: 首页 > news >正文

Java 设计模式—— 责任链模式:从原理到 SpringBoot 最优实现

Java 设计模式—— 责任链模式:从原理到 SpringBoot 最优实现

责任链模式是解决 “请求需多步处理” 场景的核心设计模式,通过将多个处理节点连成链,让请求沿链传递直至被处理(或全部节点处理完毕),实现 “请求发送者” 与 “处理者” 的解耦。本文将从原理拆解、2 种实战写法(Spring 事件、抽象类)、场景对比、避坑指南四个维度,帮你掌握责任链模式在实际项目中的灵活应用,尤其是在复杂业务流程中的落地技巧。

文章目录

  • Java 设计模式—— 责任链模式:从原理到 SpringBoot 最优实现
    • 一、责任链模式核心认知:看透 “链” 的本质
      • 1. 传统流程调用的痛点
      • 2. 责任链模式的 “解耦” 逻辑
    • 二、2 种实战写法:从 Spring 生态到自定义链
      • 写法 1:基于 Spring 事件(自动注册 + 顺序可控)
        • 核心思路
        • 完整代码实现
          • 1. 定义业务数据类(事件载体)
          • 2. 定义事件类(Spring 事件规范)
          • 3. 定义事件发布器(发起事件)
          • 4. 定义具体监听器(责任链节点)
          • 5. 定义业务服务(实际业务逻辑)
          • 6. 测试类(客户端:发起请求)
          • 7. 测试结果(控制台输出)
        • 优缺点分析
        • 适用场景
      • 写法 2:基于抽象类(手动组装 + 灵活控制)
        • 核心思路
        • 完整代码实现
          • 1. 业务数据类(与写法 1 一致,复用 CancelOrderBO)
          • 2. 定义抽象处理者(责任链核心)
          • 3. 定义具体处理者(责任链节点)
          • 4. 定义责任链工厂(组装链,可选)
          • 5. 测试类(客户端:发起请求)
          • 6. 测试结果(正常流程,控制台输出)
          • 7. 异常流程测试(库存处理失败)
        • 优缺点分析
        • 适用场景
    • 三、关键对比:2 种写法与观察者模式的区别
      • 1. 责任链模式 2 种写法对比
      • 2. 责任链模式 vs 观察者模式
    • 四、避坑指南:责任链模式实战中的 5 个关键问题
      • 1. 避免 “链断裂”:确保节点正确传递请求
      • 2. 异常处理:统一捕获 vs 节点自行处理
      • 3. 链的复用:用工厂类封装组装逻辑
      • 4. 动态调整:支持运行时修改链
      • 5. 性能优化:避免链过长导致响应慢
    • 五、总结:从 “能用” 到 “用好” 责任链模式

一、责任链模式核心认知:看透 “链” 的本质

在深入代码前,先明确责任链模式的核心价值 —— 它不是简单的 “流程调用”,而是通过 “链式结构” 解决 “多处理节点灵活组合” 的痛点。

1. 传统流程调用的痛点

以 “订单取消” 场景为例,传统写法会将 “恢复库存”“退回余额”“归还优惠券” 等步骤硬编码在一个方法中:

public void cancelOrder(String orderNo) {// 1. 恢复库存storageService.restoreStock(orderNo);// 2. 退回用户余额accountService.refundBalance(orderNo);// 3. 归还优惠券couponService.returnCoupon(orderNo);
}

这种写法的问题会随业务扩展暴露:

  • 耦合严重:新增 “日志记录” 步骤需修改cancelOrder方法,违反开闭原则;

  • 顺序难调整:若业务要求 “先退余额再恢复库存”,需手动调整代码执行顺序;

  • 容错性差:一个步骤失败会导致后续步骤全部中断,且无法灵活控制 “是否继续执行”。

2. 责任链模式的 “解耦” 逻辑

责任链模式通过 “抽象处理节点 + 链式组装” 解决上述问题,核心包含 3 个角色:

  • 抽象处理者(Abstract Handler):定义处理请求的接口,包含 “设置下一个节点” 和 “处理请求” 的方法;

  • 具体处理者(Concrete Handler):实现抽象处理者,处理自身负责的业务,若需继续传递则调用下一个节点;

  • 客户端(Client):组装责任链,发起请求(无需关心具体处理节点)。

最终实现 “新增节点不改旧代码、调整顺序只需重组链、失败控制灵活” 的理想状态。

二、2 种实战写法:从 Spring 生态到自定义链

根据项目是否依赖 Spring 框架,责任链模式有 2 种主流实现方式,适用场景和灵活性各不相同。

写法 1:基于 Spring 事件(自动注册 + 顺序可控)

核心思路

利用 Spring 的 事件驱动模型:将 “订单取消” 封装为事件,各处理步骤(恢复库存、退余额)作为事件监听器;通过@Order注解控制监听器执行顺序,Spring 自动将监听器按顺序执行,本质是 “隐式责任链”。

完整代码实现
1. 定义业务数据类(事件载体)
package com.boke.desginpattern.bo;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;/*** 取消订单业务数据:包含订单号、用户ID、商品ID等核心信息*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CancelOrderBO {private String orderNo;      // 订单号private Long userId;         // 用户IDprivate String productId;    // 商品Iprivate Integer quantity;    // 商品数量private BigDecimal amount;   // 订单金额
}
2. 定义事件类(Spring 事件规范)
package com.boke.desginpattern.chainspring.event;import com.boke.desginpattern.bo.CancelOrderBO;import org.springframework.context.ApplicationEvent;/*** 取消订单事件:继承Spring ApplicationEvent,用于传递业务数据*/
public class CancelOrderEvent extends ApplicationEvent {// 构造方法:传入业务数据(事件源)public CancelOrderEvent(CancelOrderBO cancelOrderBO) {super(cancelOrderBO);}// 简化获取业务数据的方法(避免强制类型转换)public CancelOrderBO getCancelOrderBO() {return (CancelOrderBO) super.getSource();}
}
3. 定义事件发布器(发起事件)
package com.boke.desginpattern.chainspring.publisher;import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Component;/*** 事件发布器:实现ApplicationEventPublisherAware,注入Spring事件发布器*/
@Component
public class CancelOrderEventPublisher implements ApplicationEventPublisherAware {// Spring自动注入的事件发布器private ApplicationEventPublisher applicationEventPublisher;// 实现接口方法:注入发布器@Overridepublic void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {this.applicationEventPublisher = applicationEventPublisher;}// 自定义发布方法:对外提供发布取消订单事件的入口public void publishCancelOrderEvent(CancelOrderBO cancelOrderBO) {applicationEventPublisher.publishEvent(new CancelOrderEvent(cancelOrderBO));System.out.printf("取消订单事件发布成功:订单号[%s]%n", cancelOrderBO.getOrderNo());}
}
4. 定义具体监听器(责任链节点)

通过@Order注解控制执行顺序(value 值越小,执行越靠前),每个监听器负责一个业务步骤。

// 监听器1:恢复库存(顺序1,最先执行)
package com.boke.desginpattern.chainspring.listener;import com.boke.desginpattern.chainspring.event.CancelOrderEvent;
import com.boke.desginpattern.service.StorageService;
import org.springframework.context.ApplicationListener;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;@Component
@Order(1)  // 执行顺序:1(最先处理)
public class StorageCancelListener implements ApplicationListener<CancelOrderEvent> {@Resourceprivate StorageService storageService;// 处理事件:恢复库存@Overridepublic void onApplicationEvent(CancelOrderEvent event) {CancelOrderBO bo = event.getCancelOrderBO();System.out.printf("开始处理库存恢复:订单号[%s],商品[%s],数量[%d]%n",bo.getOrderNo(), bo.getProductId(), bo.getQuantity());// 调用库存服务恢复库存(实际业务需包含数据库操作、异常处理)storageService.restoreStock(bo.getProductId(), bo.getQuantity());System.out.printf("库存恢复完成:订单号[%s]%n", bo.getOrderNo());}
}// 监听器2:退回用户余额(顺序2,库存之后执行)
package com.boke.desginpattern.chainspring.listener;import com.boke.desginpattern.chainspring.event.CancelOrderEvent;
import com.boke.desginpattern.service.AccountService;
import org.springframework.context.ApplicationListener;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;@Component
@Order(2)  // 执行顺序:2(库存之后)
public class AccountRefundListener implements ApplicationListener<CancelOrderEvent> {@Resourceprivate AccountService accountService;@Overridepublic void onApplicationEvent(CancelOrderEvent event) {CancelOrderBO bo = event.getCancelOrderBO();System.out.printf("开始处理余额退回:订单号[%s],用户[%d],金额[%s]%n",bo.getOrderNo(), bo.getUserId(), bo.getAmount());// 调用账户服务退回余额accountService.refundBalance(bo.getUserId(), bo.getAmount());System.out.printf("余额退回完成:订单号[%s]%n", bo.getOrderNo());}
}// 监听器3:归还优惠券(顺序3,最后执行)
package com.boke.desginpattern.chainspring.listener;import com.boke.desginpattern.chainspring.event.CancelOrderEvent;
import com.boke.desginpattern.service.CouponService;
import org.springframework.context.ApplicationListener;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;@Component
@Order(3)  // 执行顺序:3(最后处理)
public class CouponReturnListener implements ApplicationListener<CancelOrderEvent> {@Resourceprivate CouponService couponService;@Overridepublic void onApplicationEvent(CancelOrderEvent event) {CancelOrderBO bo = event.getCancelOrderBO();System.out.printf("开始处理优惠券归还:订单号[%s],用户[%d]%n",bo.getOrderNo(), bo.getUserId());// 调用优惠券服务归还优惠券(假设通过订单号查询关联的优惠券)couponService.returnCouponByOrderNo(bo.getOrderNo());System.out.printf("优惠券归还完成:订单号[%s]%n", bo.getOrderNo());}
}
5. 定义业务服务(实际业务逻辑)
// 库存服务
package com.boke.desginpattern.service;import org.springframework.stereotype.Service;@Service
public class StorageService {// 恢复库存(实际需操作数据库,此处简化)public void restoreStock(String productId, Integer quantity) {// 模拟数据库操作:update storage set stock = stock + #{quantity} where product_id = #{productId}}
}// 账户服务
package com.boke.desginpattern.service;import java.math.BigDecimal;
import org.springframework.stereotype.Service;@Service
public class AccountService {// 退回余额(实际需操作数据库,此处简化)public void refundBalance(Long userId, BigDecimal amount) {// 模拟数据库操作:update account set balance = balance + #{amount} where user_id = #{userId}}
}// 优惠券服务
package com.boke.desginpattern.service;import org.springframework.stereotype.Service;@Service
public class CouponService {// 按订单号归还优惠券(实际需操作数据库,此处简化)public void returnCouponByOrderNo(String orderNo) {// 模拟数据库操作:update coupon set status = 'UNUSED' where order_no = #{orderNo}}
}
6. 测试类(客户端:发起请求)
package com.boke.desginpattern.chainspring.controller;import com.boke.desginpattern.bo.CancelOrderBO;
import com.boke.desginpattern.chainspring.publisher.CancelOrderEventPublisher;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;/*** 订单控制器:发起取消订单请求,组装责任链(Spring自动完成)*/
@RestController
@RequestMapping("/api/order")
public class OrderController {@Resourceprivate CancelOrderEventPublisher eventPublisher;/*** 取消订单接口*/@PostMapping("/cancel")public String cancelOrder(@RequestBody CancelOrderBO cancelOrderBO) {// 发布取消订单事件:Spring自动调用所有监听器(按@Order顺序)eventPublisher.publishCancelOrderEvent(cancelOrderBO);return "订单取消请求已提交,订单号:" + cancelOrderBO.getOrderNo();}
}
7. 测试结果(控制台输出)
取消订单事件发布成功:订单号[TEST_20240601001]
开始处理库存恢复:订单号[TEST_20240601001],商品[PROD_001],数量[2]
库存恢复完成:订单号[TEST_20240601001]
开始处理余额退回:订单号[TEST_20240601001],用户[1001],金额[199.80]
余额退回完成:订单号[TEST_20240601001]
开始处理优惠券归还:订单号[TEST_20240601001],用户[1001]
优惠券归还完成:订单号[TEST_20240601001]
优缺点分析
优点缺点
Spring 自动注册监听器,无需手动组装责任链监听器间无直接依赖,无法控制 “前一个失败后是否继续执行”(默认继续)
通过@Order轻松调整执行顺序,维护成本低本质是 “广播式执行”,非严格意义的 “链传递”(每个监听器都接收完整事件)
符合 Spring 生态习惯,集成便捷,无需额外代码不支持动态增减节点(需新增 / 删除监听器类)
适用场景
  • SpringBoot 项目,处理步骤无强依赖(如日志记录、通知发送等辅助步骤);

  • 无需灵活控制 “失败后是否继续” 的场景;

  • 追求开发效率,不想手动管理责任链组装。

写法 2:基于抽象类(手动组装 + 灵活控制)

核心思路

自定义 抽象处理者 + 具体处理者:抽象类定义 “设置下一个节点” 和 “处理请求” 的方法,具体处理者实现自身业务逻辑;客户端手动组装责任链,支持 “前一个节点失败后中断链”“动态增减节点”,是 “严格意义的责任链”。

完整代码实现
1. 业务数据类(与写法 1 一致,复用 CancelOrderBO)
2. 定义抽象处理者(责任链核心)
package com.boke.desginpattern.chainabstract.handler;import com.boke.desginpattern.bo.CancelOrderBO;/*** 取消订单抽象处理者:定义责任链的核心方法*/
public abstract class AbstractCancelOrderHandler {// 下一个处理节点(责任链的关键)protected AbstractCancelOrderHandler nextHandler;/*** 设置下一个处理节点*/public void setNextHandler(AbstractCancelOrderHandler nextHandler) {this.nextHandler = nextHandler;}/*** 处理请求(抽象方法,由具体处理者实现)* @return true:处理成功,可继续传递;false:处理失败,中断传递*/public abstract boolean handle(CancelOrderBO cancelOrderBO);/*** 传递请求到下一个节点(封装通用逻辑,避免具体处理者重复代码)*/protected void passToNext(CancelOrderBO cancelOrderBO) {if (nextHandler != null) {System.out.printf("当前节点处理完成,传递至下一个节点:%s%n",nextHandler.getClass().getSimpleName());nextHandler.handle(cancelOrderBO);} else {System.out.println("所有节点处理完成,责任链执行结束");}}
}
3. 定义具体处理者(责任链节点)

每个处理者实现handle方法,处理自身业务,通过passToNext传递请求(或中断)。

// 具体处理者1:恢复库存
package com.boke.desginpattern.chainabstract.handler.impl;import com.boke.desginpattern.bo.CancelOrderBO;
import com.boke.desginpattern.chainabstract.handler.AbstractCancelOrderHandler;
import com.boke.desginpattern.service.StorageService;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;@Component
public class StorageCancelHandler extends AbstractCancelOrderHandler {@Resourceprivate StorageService storageService;@Overridepublic boolean handle(CancelOrderBO cancelOrderBO) {try {System.out.printf("库存节点开始处理:订单号[%s],商品[%s],数量[%d]%n",cancelOrderBO.getOrderNo(), cancelOrderBO.getProductId(), cancelOrderBO.getQuantity());// 核心业务:恢复库存(若失败抛异常)storageService.restoreStock(cancelOrderBO.getProductId(), cancelOrderBO.getQuantity());System.out.printf("库存节点处理成功:订单号[%s]%n", cancelOrderBO.getOrderNo());// 处理成功,传递至下一个节点passToNext(cancelOrderBO);return true;} catch (Exception e) {System.err.printf("库存节点处理失败:订单号[%s],原因:%s%n",cancelOrderBO.getOrderNo(), e.getMessage());// 处理失败,中断责任链return false;}}
}// 具体处理者2:退回余额
package com.boke.desginpattern.chainabstract.handler.impl;import com.boke.desginpattern.bo.CancelOrderBO;
import com.boke.desginpattern.chainabstract.handler.AbstractCancelOrderHandler;
import com.boke.desginpattern.service.AccountService;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.math.BigDecimal;@Component
public class AccountRefundHandler extends AbstractCancelOrderHandler {@Resourceprivate AccountService accountService;@Overridepublic boolean handle(CancelOrderBO cancelOrderBO) {try {System.out.printf("余额节点开始处理:订单号[%s],用户[%d],金额[%s]%n",cancelOrderBO.getOrderNo(), cancelOrderBO.getUserId(), cancelOrderBO.getAmount());// 核心业务:退回余额accountService.refundBalance(cancelOrderBO.getUserId(), cancelOrderBO.getAmount());System.out.printf("余额节点处理成功:订单号[%s]%n", cancelOrderBO.getOrderNo());// 传递至下一个节点passToNext(cancelOrderBO);return true;} catch (Exception e) {System.err.printf("余额节点处理失败:订单号[%s],原因:%s%n",cancelOrderBO.getOrderNo(), e.getMessage());// 失败中断return false;}}
}// 具体处理者3:归还优惠券
package com.boke.desginpattern.chainabstract.handler.impl;import com.boke.desginpattern.bo.CancelOrderBO;
import com.boke.desginpattern.chainabstract.handler.AbstractCancelOrderHandler;
import com.boke.desginpattern.service.CouponService;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;@Component
public class CouponReturnHandler extends AbstractCancelOrderHandler {@Resourceprivate CouponService couponService;@Overridepublic boolean handle(CancelOrderBO cancelOrderBO) {try {System.out.printf("优惠券节点开始处理:订单号[%s],用户[%d]%n",cancelOrderBO.getOrderNo(), cancelOrderBO.getUserId());// 核心业务:归还优惠券couponService.returnCouponByOrderNo(cancelOrderBO.getOrderNo());System.out.printf("优惠券节点处理成功:订单号[%s]%n", cancelOrderBO.getOrderNo());// 传递至下一个节点(若无则结束)passToNext(cancelOrderBO);return true;} catch (Exception e) {System.err.printf("优惠券节点处理失败:订单号[%s],原因:%s%n",cancelOrderBO.getOrderNo(), e.getMessage());// 失败中断return false;}}
}
4. 定义责任链工厂(组装链,可选)

为避免控制器中手动组装链的代码冗余,可新增工厂类封装组装逻辑:

package com.boke.desginpattern.chainabstract.factory;import com.boke.desginpattern.chainabstract.handler.AbstractCancelOrderHandler;
import com.boke.desginpattern.chainabstract.handler.impl.AccountRefundHandler;
import com.boke.desginpattern.chainabstract.handler.impl.CouponReturnHandler;
import com.boke.desginpattern.chainabstract.handler.impl.StorageCancelHandler;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;/*** 责任链工厂:封装链的组装逻辑,对外提供完整的责任链*/
@Component
public class CancelOrderChainFactory {@Resourceprivate StorageCancelHandler storageCancelHandler;@Resourceprivate AccountRefundHandler accountRefundHandler;@Resourceprivate CouponReturnHandler couponReturnHandler;/*** 构建取消订单责任链:库存 → 余额 → 优惠券*/public AbstractCancelOrderHandler buildChain() {// 组装顺序:库存节点 → 余额节点 → 优惠券节点storageCancelHandler.setNextHandler(accountRefundHandler);accountRefundHandler.setNextHandler(couponReturnHandler);// 返回链的第一个节点(入口)return storageCancelHandler;}/*** 构建自定义顺序的责任链(支持动态调整)*/public AbstractCancelOrderHandler buildCustomChain(AbstractCancelOrderHandler... handlers) {if (handlers == null || handlers.length == 0) {throw new IllegalArgumentException("责任链节点不能为空");}// 按数组顺序组装链for (int i = 0; i < handlers.length - 1; i++) {handlers[i].setNextHandler(handlers[i + 1]);}return handlers[0];}
}
5. 测试类(客户端:发起请求)
package com.boke.desginpattern.chainabstract.controller;import com.boke.desginpattern.bo.CancelOrderBO;
import com.boke.desginpattern.chainabstract.factory.CancelOrderChainFactory;
import com.boke.desginpattern.chainabstract.handler.AbstractCancelOrderHandler;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;/*** 订单控制器:通过工厂获取责任链,发起请求*/
@RestController
@RequestMapping("/api/order")
public class OrderController {@Resourceprivate CancelOrderChainFactory chainFactory;/*** 取消订单接口(使用默认责任链)*/@PostMapping("/cancel")public String cancelOrder(@RequestBody CancelOrderBO cancelOrderBO) {// 1. 从工厂获取组装好的责任链AbstractCancelOrderHandler chain = chainFactory.buildChain();// 2. 发起请求:调用链的第一个节点boolean result = chain.handle(cancelOrderBO);// 3. 根据结果返回响应if (result) {return "订单取消成功(所有节点处理完成),订单号:" + cancelOrderBO.getOrderNo();} else {return "订单取消失败(部分节点处理异常),订单号:" + cancelOrderBO.getOrderNo();}}/*** 取消订单接口(使用自定义顺序的责任链,示例:先退余额再恢复库存)*/@PostMapping("/cancel/custom")public String cancelOrderCustom(@RequestBody CancelOrderBO cancelOrderBO) {// 1. 获取所有节点(实际项目可通过Spring注入)AbstractCancelOrderHandler storageHandler = chainFactory.getStorageCancelHandler();AbstractCancelOrderHandler accountHandler = chainFactory.getAccountRefundHandler();AbstractCancelOrderHandler couponHandler = chainFactory.getCouponReturnHandler();// 2. 自定义组装顺序:余额 → 库存 → 优惠券AbstractCancelOrderHandler customChain = chainFactory.buildCustomChain(accountHandler, storageHandler, couponHandler);// 3. 发起请求boolean result = customChain.handle(cancelOrderBO);return result ? "自定义顺序取消成功" : "自定义顺序取消失败";}
}
6. 测试结果(正常流程,控制台输出)
库存节点开始处理:订单号[TEST_20240601002],商品[PROD_002],数量[1]
库存节点处理成功:订单号[TEST_20240601002]
当前节点处理完成,传递至下一个节点:AccountRefundHandler
余额节点开始处理:订单号[TEST_20240601002],用户[1002],金额[99.90]
余额节点处理成功:订单号[TEST_20240601002]
当前节点处理完成,传递至下一个节点:CouponReturnHandler
优惠券节点开始处理:订单号[TEST_20240601002],用户[1002]
优惠券节点处理成功:订单号[TEST_20240601002]
当前节点处理完成,传递至下一个节点:null
所有节点处理完成,责任链执行结束
7. 异常流程测试(库存处理失败)
库存节点开始处理:订单号[TEST_20240601003],商品[PROD_003],数量[3]
库存节点处理失败:订单号[TEST_20240601003],原因:商品不存在

(余额、优惠券节点未执行,链中断)

优缺点分析
优点缺点
手动组装链,支持动态调整顺序、增减节点,灵活性极高需手动维护链的组装逻辑(可通过工厂类优化)
支持 “前一个节点失败后中断链”,容错性强代码量略多(需定义抽象类、具体处理者)
节点间通过 “下一个节点” 强关联,符合严格的责任链定义非 Spring 项目需手动管理节点的创建(如 new 对象)
适用场景
  • 中大型项目,处理步骤有强依赖(如 “必须恢复库存后才能退余额”);

  • 需要灵活控制 “失败后是否继续执行” 的场景(如支付失败需中断后续步骤);

  • 需动态调整处理顺序或增减节点的业务(如活动期间新增 “赠送积分” 步骤)。

三、关键对比:2 种写法与观察者模式的区别

1. 责任链模式 2 种写法对比

对比维度基于 Spring 事件基于抽象类
链的组装Spring 自动完成(监听器注册)手动组装(工厂类封装)
执行顺序控制@Order注解,简单直观手动setNextHandler,灵活
失败控制无法中断(默认所有监听器执行)可中断(返回 false 或不调用passToNext
节点依赖无依赖(各监听器独立接收事件)强依赖(前一个节点决定是否传递)
适用场景辅助步骤、无强依赖核心步骤、有强依赖

2. 责任链模式 vs 观察者模式

很多人会混淆这两种模式,核心区别在于 “节点关系” 和 “执行逻辑”:

  • 观察者模式:“一对多广播”,观察者间无顺序、无依赖,发布者发送事件后所有观察者都会执行(如订单创建后,日志、通知、统计同时执行);

  • 责任链模式:“链式传递”,节点间有顺序、有依赖,请求沿链传递,可中断(如订单取消需按 “库存→余额→优惠券” 顺序执行,前一步失败则中断)。

四、避坑指南:责任链模式实战中的 5 个关键问题

1. 避免 “链断裂”:确保节点正确传递请求

问题:具体处理者忘记调用passToNext,导致链中断(非预期)。

解决方案:

  • 在抽象类中封装passToNext方法,强制具体处理者调用(或明确中断);

  • 新增 “链完整性校验”:工厂类组装链后,检查是否存在 “最后一个节点未设置为 null” 的情况。

2. 异常处理:统一捕获 vs 节点自行处理

问题:某个节点抛出未捕获异常,导致整个链中断且无法定位问题。

解决方案:

  • 每个具体处理者的handle方法中捕获异常,记录日志后返回false(明确中断);

  • 抽象类中新增handleException抽象方法,统一异常处理逻辑(如告警、重试)。

3. 链的复用:用工厂类封装组装逻辑

问题:多个客户端需要使用相同的责任链,重复组装代码冗余。

解决方案:

  • 新增责任链工厂类(如CancelOrderChainFactory),封装组装逻辑,对外提供buildChain方法;

  • 支持自定义链(如buildCustomChain),满足不同场景的需求。

4. 动态调整:支持运行时修改链

问题:需要根据业务条件动态增减节点(如 VIP 用户取消订单需新增 “赠送积分” 步骤)。

解决方案:

  • 工厂类中新增addHandler/removeHandler方法,支持运行时调整节点;

  • 结合配置中心(如 Nacos),通过配置决定是否启用某节点(如pay.strategy.coupon.enabled=true)。

5. 性能优化:避免链过长导致响应慢

问题:责任链节点过多(如超过 10 个),每个节点处理耗时,导致整体响应慢。

解决方案:

  • 拆分长链为多个短链(如 “核心步骤链”+“辅助步骤链”),核心步骤同步执行,辅助步骤异步执行;

  • 节点处理逻辑异步化(如用@Async注解,需注意异步后的异常处理)。

五、总结:从 “能用” 到 “用好” 责任链模式

责任链模式的核心不是 “链式调用”,而是 “灵活组合处理节点,解耦请求与处理”。选择哪种写法,需根据业务场景判断:

  • 若用 SpringBoot 且处理步骤无强依赖,选 “基于 Spring 事件”(开发快、维护简单);

  • 若处理步骤有强依赖或需灵活控制失败,选 “基于抽象类”(灵活、容错性强)。

在实际项目中,责任链模式常与其他模式结合使用:

  • 责任链 + 工厂模式:封装链的组装逻辑,提高复用性;

  • 责任链 + 模板方法:抽象类中定义处理流程模板,具体处理者实现差异化逻辑;

  • 责任链 + 观察者模式:核心步骤用责任链(同步),辅助步骤用观察者(异步)。

掌握这些技巧,才能在复杂业务中真正发挥责任链模式的价值,写出 “易扩展、易维护、高容错” 的代码。

http://www.dtcms.com/a/486948.html

相关文章:

  • Linux中快速部署Minio(基础TLS配置)
  • 大型小说网站开发语言望野博物馆
  • 做早餐烧菜有什么网站零基础搭建网站
  • SAP PCE生产订单组件不能更改物料编码和工厂
  • Aosp14系统壁纸的启动和加载流程
  • 电压源和电流源学习理解
  • 刘洋洋《魔法派对Magic Party》童话重启,温柔守护每颗童心
  • 东莞长安网站设计搞网站开发的程序员属于哪一类
  • 运维领域核心概念的专有名词解释-详解
  • 【AIGC】语音识别ASR:火山引擎大模型技术实践
  • 如何在AutoCAD中加载大型影像文件?
  • 爬虫调试技巧:如何用浏览器开发者工具找接口?
  • Linux 页缓存(Page Cache)与回写(Writeback)机制详解
  • 【NI测试方案】基于ARM+FPGA的整车仿真与电池标定
  • JavaScript将url转为blob和file,三种方法
  • 电商营销型网站建设中国菲律宾关系现状
  • 英文网站建设 飞沐wordpress公众号文章分类
  • 怎么做qq靓号网站岳阳网站设计公司
  • Unity 通过Texture生成的Sprite存在边缘黑线问题 Image黑边问题
  • 计算机方向如何才能更好的找到工作?(成长心得)
  • 大连市城市建设投资集团网站网站怎么做文件上传
  • 织梦网站转跳手机站盐城网盐城网站建设站建设
  • Spring AOP 中@annotation的两种写法详解
  • Linux设备模型
  • Linux fg命令使用教程
  • 微博爬虫流程解析——session的使用
  • 企业网站建设的核心是专业手机建站公司
  • Vllm Semantic-router MoM 架构
  • LLMs-from-scratch :KV 缓存
  • dshot协议数据帧格式