网站首页 > java教程 正文
一、什么是责任链模式?
责任链模式(Chain of Responsibility Pattern),顾名思义,为请求者和接受者之间创建一条对象处理链路,避免请求发送者与接收者耦合在一起!
责任链模式,是一种实用性非常强的设计模式,比较典型的应用场景有:
- Apache Tomcat 对 Encoding 编码处理的处理
- SpringBoot ??的拦截器、过滤器链
- netty 中的处理链
- 支付风控的机制
- ?志处理级别
尤其是当程序的处理流程很长的时候,采用责任链设计模式,不仅实现优雅,而且易复用可扩展!
今天我们就一起来了解一下在 SpringBoot 中如何应用责任链模式!
二、代码实践
在 SpringBoot 中,责任链模式的实践方式有好几种,今天我们主要抽三种实践方式给大家介绍。
我们以某下单流程为例,将其切成多个独立检查逻辑,可能会经过的数据验证处理流程如下:
采用责任链设计模式来编程,代码实践如下!
这或许是一个对你有用的开源项目,mall项目是一套基于 SpringBoot3 + Vue 的电商系统(Github标星60K),后端支持多模块和 2024最新微服务架构 ,采用Docker和K8S部署。包括前台商城项目和后台管理系统,能支持完整的订单流程!涵盖商品、订单、购物车、权限、优惠券、会员、支付等功能!
Boot项目:https://github.com/macrozheng/mall
Cloud项目:https://github.com/macrozheng/mall-swarm
视频教程:https://www.macrozheng.com/video/
项目演示:
2.1、方式一
首先,我们定义一个简易版的下单对象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:用于检查客户账户余额是否充足
@Component
public class RepeatOrderHandleInterceptService implements OrderHandleIntercept {
@Override
public int sort() {
//用于重复下单的逻辑验证,在执行顺序为1
return 1;
}
@Override
public OrderAddContext handle(OrderAddContext context) {
System.out.println("通过seqId,检查客户是否重复下单");
return context;
}
}
@Component
public class ValidOrderHandleInterceptService implements OrderHandleIntercept {
@Override
public int sort() {
//用于验证请求参数是否合法,执行顺序为2
return 2;
}
@Override
public OrderAddContext handle(OrderAddContext context) {
System.out.println("检查请求参数,是否合法,并且获取客户的银行账户");
return context;
}
}
@Component
public class BankOrderHandleInterceptService implements OrderHandleIntercept {
@Override
public int sort() {
//用于检查客户账户余额是否充足,在执行顺序为3
return 3;
}
@Override
public OrderAddContext handle(OrderAddContext context) {
System.out.println("检查银行账户是否合法,调用银行系统检查银行账户余额是否满足下单金额");
return context;
}
}
再然后,我们还需要创建一个订单数据验证管理器OrderHandleChainService,用于管理这些实现类。
@Component
public class OrderHandleChainService implements ApplicationContextAware {
private List<OrderHandleIntercept> handleList = new ArrayList<>();
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
//获取指定的接口实现类,并按照sort进行排序,放入List中
Map<String, OrderHandleIntercept> 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)
@SpringBootTest
public class CalculatorServiceTest {
@Autowired
private OrderHandleChainService orderHandleChainService;
@Test
public void test(){
orderHandleChainService.execute(new OrderAddContext());
}
}
执行结果如下:
通过seqId,检查客户是否重复下单
检查请求参数,是否合法,并且获取客户的银行账户
检查银行账户是否合法,调用银行系统检查银行账户余额是否满足下单金额
如果需要继续加验证流程或者处理流程,只需要重新实现OrderHandleIntercept接口就行,其他的代码无需改动!
当然,有的同学可能觉得这种方法用的不习惯,不喜欢通过sort()来指定顺序,也可以通过如下方式进行手动add排序。
@Component
public class OrderHandleChainService {
private List<OrderHandleIntercept> 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;
}
}
2.2、方式二
第二种实现方式,就更简单了,我们通过注解@Order来指定排序,代替手动方法排序sort(),操作方式如下:
/**
* 指定注入顺序为1
*
*/
@Order(1)
@Component
public class RepeatOrderHandleInterceptService implements OrderHandleIntercept {
//...省略
}
/**
* 指定注入顺序为2
*
*/
@Order(2)
@Component
public class ValidOrderHandleInterceptService implements OrderHandleIntercept {
//...省略
}
/**
* 指定注入顺序为3
*
*/
@Order(3)
@Component
public class BankOrderHandleInterceptService implements OrderHandleIntercept {
//...省略
}
@Component
public class OrderHandleChainService {
@Autowired
private List<OrderHandleIntercept> handleList;
/**
* 执行处理
* @param context
* @return
*/
public OrderAddContext execute(OrderAddContext context){
for (OrderHandleIntercept handleIntercept : handleList) {
context =handleIntercept.handle(context);
}
return context;
}
}
运行单元测试,你会发现结果与上面运行的结果一致,原因Spring的ioc容器,支持通过Map或者List来直接注入对象,省去自己排序。
2.3、方式三
通过定义抽象类来实现责任链设计模式,还是以上面的案例为例,我们需要先定义一个抽象类,比如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)
@Component
public class RepeatOrderHandle extends AbstractOrderHandle {
@Override
public OrderAddContext handle(OrderAddContext context) {
System.out.println("通过seqId,检查客户是否重复下单");
return context;
}
}
@Order(2)
@Component
public class ValidOrderHandle extends AbstractOrderHandle {
@Override
public OrderAddContext handle(OrderAddContext context) {
System.out.println("检查请求参数,是否合法,并且获取客户的银行账户");
return context;
}
}
@Order(3)
@Component
public class BankOrderHandle extends AbstractOrderHandle {
@Override
public OrderAddContext handle(OrderAddContext context) {
System.out.println("检查银行账户是否合法,调用银行系统检查银行账户余额是否满足下单金额");
return context;
}
}
接着,创建一个责任链管理器,比如OrderHandleManager。
@Component
public class OrderHandleManager {
@Autowired
private List<AbstractOrderHandle> orderHandleList;
@PostConstruct
public void init(){
//如果List没有按照@Order注解方式排序,可以通过如下方式手动排序
Collections.sort(orderHandleList, AnnotationAwareOrderComparator.INSTANCE);
int size = orderHandleList.size();
for (int i = 0; i < size; i++) {
if(i == size -1){
orderHandleList.get(i).setNext(null);
} else {
orderHandleList.get(i).setNext(orderHandleList.get(i + 1));
}
}
}
/**
* 执行处理
* @param context
* @return
*/
public OrderAddContext execute(OrderAddContext context){
context = orderHandleList.get(0).execute(context);
return context;
}
}
最后,我们编写单元测试,来看看效果。
@RunWith(SpringRunner.class)
@SpringBootTest
public class CalculatorServiceTest {
@Autowired
private OrderHandleManager orderHandleManager;
@Test
public void test(){
orderHandleManager.execute(new OrderAddContext());
}
}
运行结果与预期一致!
通过seqId,检查客户是否重复下单
检查请求参数,是否合法,并且获取客户的银行账户
检查银行账户是否合法,调用银行系统检查银行账户余额是否满足下单金额
三、小结
本文主要围绕在 SpringBoot 中如何引入责任链设计模式,介绍了三种玩法,其中第二种用法最多,其次就是第一种,第三种用的比较少,第三种本质是一种链式写法,可能理解上不如第一种直观,但是效果是一样的。
有效的使用责任链设计模式,可以显著降低业务代码的复杂度,可读性更好,更容易扩展,希望对大家有帮助!
猜你喜欢
- 2024-12-23 新疆军区某边防团河源边防连采访见闻
- 2024-12-23 还在自己实现责任链?我建议你造轮子之前先看看这个开源项目
- 2024-12-23 风雪边关!一起走近新疆军区某边防团河源边防连
- 2024-12-23 基于Sentinel自研组件的系统限流、降级、负载保护最佳实践探索
- 2024-12-23 入连!授枪! 授枪仪式上连长的讲话
- 2024-12-23 MapStruct架构设计 mapstruct-processor
- 2024-12-23 # 利刃出鞘_Tomcat 核心原理解析(三)
- 2024-12-23 责任链 + 工厂 + 模板方法 + 享元 模式结合业务 - 实践
- 2024-12-23 Spring 框架底层用到的设计模式都有哪些?
- 2024-12-23 聊聊如何实现一个特别的责任链 如何实现负责任创新
你 发表评论:
欢迎- 04-27微服务部署架构设计详解(图文全面总结)
- 04-27Java微服务架构选型与对比:一场技术流派的巅峰对决
- 04-27微服务架构下Java的最佳实践
- 04-27Java微服务架构选型:优雅拆分与高效整合
- 04-27微服务架构下的Java代码拆分策略:像拼图一样构建系统
- 04-27微服务架构下的Java最佳实践
- 04-27微服务架构下Java的挑战与机遇
- 04-27微服务架构下Java事务管理的艺术
- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)