巧妙利用 SpringBoot 责任连模式,让编程事半功倍!

摘要:责任链模式(Chain of Responsibility Pattern),顾名思义,为请求者和接受者之间创建一条对象处理链路,避免请求发送者与接收者耦合在一起!

责任链模式(Chain of Responsibility Pattern),顾名思义,为请求者和接受者之间创建一条对象处理链路,避免请求发送者与接收者耦合在一起!

Apache Tomcat 对 Encoding 编码处理的处理SpringBoot ⾥⾯的拦截器、过滤器链netty 中的处理链支付风控的机制⽇志处理级别

在 SpringBoot 中,责任链模式的实践方式有好几种,今天我们主要抽三种实践方式给大家介绍。

我们以某下单流程为例,将其切成多个独立检查逻辑,可能会经过的数据验证处理流程如下:

采用责任链设计模式来编程,代码实践如下!

这或许是一个对你有用的开源项目,mall项目是一套基于 SpringBoot3 + Vue 的电商系统(Github标星60K),后端支持多模块和 2024最新微服务架构 ,采用Docker和K8S部署。包括前台商城项目和后台管理系统,能支持完整的订单流程!涵盖商品、订单、购物车、权限、优惠券、会员、支付等功能!

Boot项目:

Cloud项目:

视频教程:

首先,我们定义一个简易版的下单对象OrderContext。

public class OrderContext { /** * 请求唯一序列ID */ private String seqId; /** * 用户ID */ private String userId; /** * 产品skuId */ private Long skuId; /** * 下单数量 */ private Integer amount; /** * 用户收货地址ID */ private String userAddressId; //..set、get}

然后,我们定义一个数据处理接口OrderHandleIntercept,用于标准化执行!

public interface OrderHandleIntercept { /** * 指定执行顺序 * @return */ int sort; /** * 对参数进行处理 * @param context * @return */ OrderAddContext handle(OrderAddContext context);}

接着,我们分别创建三个不同的接口实现类,并指定执行顺序,内容如下:

RepeatOrderHandleInterceptService:用于重复下单的逻辑验证ValidOrderHandleInterceptService:用于验证请求参数是否合法BankOrderHandleInterceptService:用于检查客户账户余额是否充足@Componentpublic class RepeatOrderHandleInterceptService implements OrderHandleIntercept { @Override public int sort { //用于重复下单的逻辑验证,在执行顺序为1 return 1; } @Override public OrderAddContext handle(OrderAddContext context) { System.out.println("通过seqId,检查客户是否重复下单"); return context; }}@Componentpublic class ValidOrderHandleInterceptService implements OrderHandleIntercept { @Override public int sort { //用于验证请求参数是否合法,执行顺序为2 return 2; } @Override public OrderAddContext handle(OrderAddContext context) { System.out.println("检查请求参数,是否合法,并且获取客户的银行账户"); return context; }}@Componentpublic class BankOrderHandleInterceptService implements OrderHandleIntercept { @Override public int sort { //用于检查客户账户余额是否充足,在执行顺序为3 return 3; } @Override public OrderAddContext handle(OrderAddContext context) { System.out.println("检查银行账户是否合法,调用银行系统检查银行账户余额是否满足下单金额"); return context; }}

再然后,我们还需要创建一个订单数据验证管理器OrderHandleChainService,用于管理这些实现类。

@Componentpublic class OrderHandleChainService implements ApplicationContextAware { private List handleList = new ArrayList; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { //获取指定的接口实现类,并按照sort进行排序,放入List中 Map serviceMap = applicationContext.getBeansOfType(OrderHandleIntercept.class); handleList = serviceMap.values.stream .sorted(Comparator.comparing(OrderHandleIntercept::sort)) .collect(Collectors.toList); } /** * 执行处理 * @param context * @return */ public OrderAddContext execute(OrderAddContext context){ for (OrderHandleIntercept handleIntercept : handleList) { context =handleIntercept.handle(context); } return context; }}

最后,我们编写单元测试来看看效果如何!

@RunWith(SpringRunner.class)@SpringBootTestpublic class CalculatorServiceTest { @Autowired private OrderHandleChainService orderHandleChainService; @Test public void test{ orderHandleChainService.execute(new OrderAddContext); }}

执行结果如下:

通过seqId,检查客户是否重复下单检查请求参数,是否合法,并且获取客户的银行账户检查银行账户是否合法,调用银行系统检查银行账户余额是否满足下单金额

如果需要继续加验证流程或者处理流程,只需要重新实现OrderHandleIntercept接口就行,其他的代码无需改动!

当然,有的同学可能觉得这种方法用的不习惯,不喜欢通过sort来指定顺序,也可以通过如下方式进行手动add排序。

@Componentpublic class OrderHandleChainService { private List handleList = new ArrayList; @Autowired private ValidOrderHandleInterceptService validOrderHandleInterceptService; @Autowired private RepeatOrderHandleInterceptService repeatOrderHandleInterceptService; @Autowired private BankOrderHandleInterceptService bankOrderHandleInterceptService; @PostConstruct public void init{ //依次手动add对象 handleList.add(repeatOrderHandleInterceptService); handleList.add(validOrderHandleInterceptService); handleList.add(bankOrderHandleInterceptService); } /** * 执行处理 * @param context * @return */ public OrderAddContext execute(OrderAddContext context){ for (OrderHandleIntercept handleIntercept : handleList) { context =handleIntercept.handle(context); } return context; }}

第二种实现方式,就更简单了,我们通过注解@Order来指定排序,代替手动方法排序sort,操作方式如下:

/** * 指定注入顺序为1 * */@Order(1)@Componentpublic class RepeatOrderHandleInterceptService implements OrderHandleIntercept { //...省略}/** * 指定注入顺序为2 * */@Order(2)@Componentpublic class ValidOrderHandleInterceptService implements OrderHandleIntercept { //...省略}/** * 指定注入顺序为3 * */@Order(3)@Componentpublic class BankOrderHandleInterceptService implements OrderHandleIntercept { //...省略}@Componentpublic class OrderHandleChainService { @Autowired private List handleList; /** * 执行处理 * @param context * @return */ public OrderAddContext execute(OrderAddContext context){ for (OrderHandleIntercept handleIntercept : handleList) { context =handleIntercept.handle(context); } return context; }}

运行单元测试,你会发现结果与上面运行的结果一致,原因Spring的ioc容器,支持通过Map或者List来直接注入对象,省去自己排序。

通过定义抽象类来实现责任链设计模式,还是以上面的案例为例,我们需要先定义一个抽象类,比如abstractOrderHandle。

public abstract class AbstractOrderHandle { /** * 责任链,下一个链接节点 */ private AbstractOrderHandle next; /** * 执行入口 * @param context * @return */ public OrderAddContext execute(OrderAddContext context){ context = handle(context); // 判断是否还有下个责任链节点,没有的话,说明已经是最后一个节点 if(getNext != null){ getNext.execute(context); } return context; } /** * 对参数进行处理 * @param context * @return */ public abstract OrderAddContext handle(OrderAddContext context); public AbstractOrderHandle getNext { return next; } public void setNext(AbstractOrderHandle next) { this.next = next; }}

然后,分别创建三个处理类,并排好序号。

@Order(1)@Componentpublic class RepeatOrderHandle extends AbstractOrderHandle { @Override public OrderAddContext handle(OrderAddContext context) { System.out.println("通过seqId,检查客户是否重复下单"); return context; }}@Order(2)@Componentpublic class ValidOrderHandle extends AbstractOrderHandle { @Override public OrderAddContext handle(OrderAddContext context) { System.out.println("检查请求参数,是否合法,并且获取客户的银行账户"); return context; }}@Order(3)@Componentpublic class BankOrderHandle extends AbstractOrderHandle { @Override public OrderAddContext handle(OrderAddContext context) { System.out.println("检查银行账户是否合法,调用银行系统检查银行账户余额是否满足下单金额"); return context; }}

接着,创建一个责任链管理器,比如OrderHandleManager。

@Componentpublic class OrderHandleManager { @Autowired private List orderHandleList; @PostConstruct public void init{ //如果List没有按照@Order注解方式排序,可以通过如下方式手动排序 Collections.sort(orderHandleList, AnnotationAwareOrderComparator.INSTANCE); int size = orderHandleList.size; for (int i = 0; i

最后,我们编写单元测试,来看看效果。

@RunWith(SpringRunner.class)@SpringBootTestpublic class CalculatorServiceTest { @Autowired private OrderHandleManager orderHandleManager; @Test public void test{ orderHandleManager.execute(new OrderAddContext); }}

运行结果与预期一致!

本文主要围绕在 SpringBoot 中如何引入责任链设计模式,介绍了三种玩法,其中第二种用法最多,其次就是第一种,第三种用的比较少,第三种本质是一种链式写法,可能理解上不如第一种直观,但是效果是一样的。

有效的使用责任链设计模式,可以显著降低业务代码的复杂度,可读性更好,更容易扩展,希望对大家有帮助!

来源:散文随风想一点号

相关推荐