管道流创建订单
随着现在的电商平台的日新月异,对于其下单流程来说,订单类型众多,且链路非常长。比如有解析购物车、获取用户地址信息、出仓、拆单、合单、计算运费、使用优惠券、组装订单信息、插入数据库...等等操作链路。
由于三月份的时候公司需要做B2C的需求,相当于一套新的生态链。而原先公司的基础设施实在不敢恭维。比如创建订单接口。所有类型的创建订单都由这个接口实现(里面大量的if else)。算上抽出来的代码,整个流程有上万行代码。如果要在上面强行接入B2C创建订单逻辑,无疑会牵一发而动全身。
所以急需准备一套低耦合的创建订单代码。主要目的是将每种类型的订单分开,并且能共用的共用(比如所有类型的订单都会有插入OrderDO这个操作)。
一开始我的想法是用策略模式+模板方法来做。策略模式用来路由订单类型,而模板方法用来提取公共方法或者重写自己特定的逻辑。然而这样做,底层的抽象类包含了所有订单类型的方法合集,严重耦合。且基本所有方法都需要重写,并且只能按底层执行方法提供的顺序来执行(除非你重写执行方法)。这种策略模式+模板方法其实只适用于比较简单的多类型业务。
通过请教以前老大。并在他的指引下,最终采用了策略模式+模板方法+责任链模式的设计思想。责任链模式借鉴了netty中的pipiline。
https://github.com/chenshengyue/pipeline
1.核心组件类型(core包)
1.1 AbstractPipe(抽象管道)
每个具体的管道都继承它。
每个管道所经历的流程
-
根据入参判断是否被过滤
-
执行具体业务
-
调用下一个管道
public void invoke(InvocationChain<T, S> invocationChain) { T parameter = invocationChain.getParameter(); S context = invocationChain.getContext(); //判断是否过滤此管道 if (isFilter(parameter, context)) { log.info("{} ---> filter pipe : {}", invocationChain.getKey(), this.getClass().getSimpleName()); } else { rollbackAdd(invocationChain); //执行具体业务 bizHandler(parameter, context); successAdd(invocationChain); } //调用下一个管道 invocationChain.invokeNext();
}
1.2 Success && RollBack (这点不是主要组件)
成功接口和回滚接口。两个接口都作用于pipe。
在整个pipeline执行过程中:
每个pipe执行前都会记录到InvocationChain.rollBackList。
每个pipe成功执行后都会记录到InvocationChain.successList
若整个pipeline执行失败,会遍历rollBackList并执行rollBack方法
无论pipeline执行是否成功,都会会遍历successList并执行success方法
1.3 Pipeline(管道流)&& InvocationChain(执行链)
PipelineImpl
-
属性pipeList: 存储这个管道流所加载的管道
-
内部私有类InvocationChainImpl: 一个PipeLine实例对应一个InvocationChain执行链。用于递归执行各个管道
/** * 管道流执行入口 */ @Override public void invoke() { executedIndex = -1; log.info("{} : begin invoke...request = {}", key, JSON.toJSONString(this.getParameter())); invokeNext(); } /** * 递归调用管道 */ @Override public void invokeNext() { executedIndex++; if (executedIndex < pipeList.size()) { Pipe pipe = pipeList.get(executedIndex); pipe.invoke(this); } }
1.4 AbstractEngineExecutor(抽象引擎执行器)
每个业务引擎都应继承AbstractEngineExecutor。
实现了InitializingBean,初始化pipeline。
运行时调用doPipeline方法
- 校验入参
- 实例化一个执行链
- 执行管道流入口方法(invoke)
1.5EngineResolver
通过策略模式找到对应的引擎执行器。
策略模式参考我的这篇文章:https://www.cnblogs.com/chenshengyue/p/10826087.html
2.运行
启动项目。输入http://localhost:8080/swagger-ui.html#/
选择对应的controller,输入入参(创建订单类型为1的订单)
{ "addressId": 0, "bargainInfoId": 0, "cartId": 0, "orderType": 1, "skuInfoList": [ { "num": 0, "skuId": 0 } ], "userId": 0 }
看到运行结果
结合代码debug一下就能看懂!