状态机是有限状态自动机的简称,是现实事物运行规则抽象而成的一个数学模型。
有限状态机一般都有以下特点:
一个状态机至少要包含两个状态,分为:现态(源状态)、次态(目标状态)
状态可以理解为一种结果,一种稳态形式,没有扰动会保持不变的。
状态命名形式:
副词+动词;例如:待审批、待支付、待收货
动词+结果;例如:审批完成、支付完成
已+动词形式;例如:已发货、已付款
事件(event)
又称为“条件”,就是某个操作动作的触发条件或者口令。当一个条件满足时,就会触发一个动作,或者执行一次状态迁徙。这个事件可以是外部调用、监听到消息、或者各种定时到期等触发的事件。
条件命名形式:动词+结果;例如:支付成功
事件发生以后要执行动作。例如:事件=“打开开关指令”,动作=“开灯”。一般就对应一个函数。
条件满足后执行动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。
动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。
即从一个状态变化到另外一个状态,例如:“开灯过程”就是一个变化
Spring Statemachine是Spring官方提供的一个框架,供应用程序开发人员在Spring应用程序中使用状态机。支持状态的嵌套(substate),状态的并行(parallel,fork,join)、子状态机等等。
官网地址:https://projects.spring.io/spring-statemachine/
为什么要选择spring- statemachine?
主要是考虑到学习成本,而且另外2个状态机都是基于spring- statemachine(状态机标杆)来做优化和简化,虽然后2者相对spring- statemachine会轻量级一些,但是spring- statemachine的结构更清晰,和状态机理论基本一致,功能齐全且相应的资料和文档也会更多一些。
org.springframework.statemachine
spring-statemachine-core
2.0.1.RELEASE
/**
* 订单状态定义
* @author
*/
@Getter
public enum OrderStatusEnum {
// 无状态 no_state 0
// 待支付 pay_wait 0
// 待发货 delivery_wait 10
// 待收货 receipt_wait 15
// 待评价 evaluate_wait 20
// 交易完成 complete 25
// 售后中 refund 40
// 交易关闭 closed 100
NO_STATE(0, "NO_STATE"),
PAY_WAIT(5, "PAY_WAIT"),
DELIVERY_WAIT(10, "DELIVERY_WAIT"),
RECEIPT_WAIT(15, "RECEIPT_WAIT"),
EVALUATE_WAIT(20, "EVALUATE_WAIT"),
COMPLETE(25, "COMPLETE"),
REFUND(40, "REFUND"),
CLOSED(100, "CLOSED"),;
private Integer code;
private String type;
OrderStatusEnum(Integer code, String type) {
this.code = code;
this.type = type;
}
public static OrderStatusEnum getByCode(Integer code){
for (OrderStatusEnum saleOrderStatusEnum : values()) {
if (saleOrderStatusEnum.getCode().equals(code)) {
return saleOrderStatusEnum;
}
}
return null;
}
/**
* 事件流转
*/
@Getter
public enum OrderEventsEnum {
//还有售后其他的售后事件,demo就不展示了
//正向:无状态 -> 待付款 用户提交订单
NO_STATE_TO_PAY_WAIT_EVENT(0),
//正向:待付款 -> 待发货 用户支付成功,等待商家发货
PAY_WAIT_TO_DELIVERY_WAIT_EVENT(5),
//反向:待付款 -> 交易关闭 用户取消订单或订单未支付超时
PAY_WAIT_TO_CLOSED_EVENT(5),
//正向:待发货 -> 待收货 商家已发货待用户收货
DELIVERY_WAIT_TO_RECEIPT_WAIT_EVENT(10),
//反向:待发货 -> 交易关闭 用户发起售后则商家直接退款
DELIVERY_WAIT_TO_CLOSED_EVENT(10),
//正向:待收货 -> 待评价 用户已收货或订单待发货后10天则系统自动确认收货
RECEIPT_WAIT_TO_EVALUATE_WAIT_EVENT(15),
//反向:待收货 -> 售后中 商家发货后用户售后(退货+退钱/换货)都需要用户承担邮费 商家待收货后才退钱
RECEIPT_WAIT_TO_REFUND_EVENT(15),
//反向:售后中 -> 交易结束 商家收到用户的货,确认后退款给用户
REFUND_TO_CLOSED_EVENT(40),
//正向:待评价 -> 交易完成 用户收货7天后系统自动结束售后操作
EVALUATE_WAIT_TO_COMPLETE_EVENT(20),;
/**
* 起始状态
*/
private Integer value;
OrderEventsEnum(Integer value){
this.value=value;
}
/**
* 校验事件的起始状态
* @param eventEnum 事件枚举
* @param status 状态
* @return
*/
public static boolean checkEventStatus(OrderEventsEnum eventEnum,Integer status){
if(eventEnum.getValue().equals(status)){
return true;
}
return false;
}
}
/**
* 状态机的流转配置
*/
@Configuration
@EnableStateMachine(name = "orderStatusMachine")
public class OrderStatusMachineConfig extends StateMachineConfigurerAdapter {
/**
* 初始化状态
* @param orderStatusMachineConfig:
* @throws Exception:
*/
public void configure(StateMachineStateConfigurer orderStatusMachineConfig) throws Exception {
orderStatusMachineConfig.withStates()
.initial(OrderStatusEnum.NO_STATE)
.states(EnumSet.allOf(OrderStatusEnum.class));
}
/**
* 配置状态转换事件关系
* @param transitions transitions
* @throws Exception:
*/
public void configure(StateMachineTransitionConfigurer transitions) throws Exception {
transitions
//无状态 -> 待付款 用户提交订单
.withExternal().source(OrderStatusEnum.NO_STATE).target(OrderStatusEnum.PAY_WAIT).event(OrderEventsEnum.NO_STATE_TO_PAY_WAIT_EVENT)
.and()
//待付款 -> 待发货
.withExternal().source(OrderStatusEnum.PAY_WAIT).target(OrderStatusEnum.DELIVERY_WAIT).event(OrderEventsEnum.PAY_WAIT_TO_DELIVERY_WAIT_EVENT)
.and()
//待付款 -> 交易关闭
.withExternal().source(OrderStatusEnum.PAY_WAIT).target(OrderStatusEnum.CLOSED).event(OrderEventsEnum.PAY_WAIT_TO_CLOSED_EVENT)
.and()
//待发货 -> 待收货
.withExternal().source(OrderStatusEnum.DELIVERY_WAIT).target(OrderStatusEnum.RECEIPT_WAIT).event(OrderEventsEnum.DELIVERY_WAIT_TO_RECEIPT_WAIT_EVENT)
.and()
//待发货 -> 交易关闭
.withExternal().source(OrderStatusEnum.DELIVERY_WAIT).target(OrderStatusEnum.CLOSED).event(OrderEventsEnum.DELIVERY_WAIT_TO_CLOSED_EVENT)
.and()
//待收货 -> 待评价
.withExternal().source(OrderStatusEnum.RECEIPT_WAIT).target(OrderStatusEnum.EVALUATE_WAIT).event(OrderEventsEnum.RECEIPT_WAIT_TO_EVALUATE_WAIT_EVENT)
.and()
//待收货 -> 售后中
.withExternal().source(OrderStatusEnum.RECEIPT_WAIT).target(OrderStatusEnum.REFUND).event(OrderEventsEnum.RECEIPT_WAIT_TO_REFUND_EVENT)
.and()
//售后中 -> 交易结束
.withExternal().source(OrderStatusEnum.REFUND).target(OrderStatusEnum.CLOSED).event(OrderEventsEnum.REFUND_TO_CLOSED_EVENT)
.and()
//待评价 -> 交易完成
.withExternal().source(OrderStatusEnum.EVALUATE_WAIT).target(OrderStatusEnum.COMPLETE).event(OrderEventsEnum.EVALUATE_WAIT_TO_COMPLETE_EVENT);
}
/**
* 持久化配置
* 实际使用中,可以配合redis等,进行持久化操作
* @return
*/
@Bean
public StateMachinePersister statusMachinePersister(){
return new DefaultStateMachinePersister<>(new StateMachinePersist() {
@Override
public void write(StateMachineContext context, Order order) throws Exception {
//1. 加入redis缓存中 key:order.id ; value: version (解决读一致)
//2. 记录推送本地日志 (解决 消息丢失)
//3. MQ消息推送 (广播模式 推送给 商户中心和运营中心)
//4. 本地持久化订单数据
System.out.println("订单推送..............."+order);
}
@Override
public StateMachineContext read(Order order) throws Exception {
//此处直接获取order中的状态,其实并没有进行持久化读取操作
return new DefaultStateMachineContext<>(OrderStatusEnum.getByCode(order.getStatus()), null, null, null, null);
}
});
}
}
定义状态机:1. 初始化状态、配置事件流转、配置持久化
持久化这里做了订单推送给其他端(运营中心、商户中心),详见上一篇的说明。
/**
* 状态业务类(事件触发)
*/
@Service
@Slf4j
public class OrderStatusMachineService {
@Autowired
private StateMachine orderStatusMachine;
@Resource(name = "statusMachinePersister")
private StateMachinePersister persister;
/**
* 状态机流转
* @param order 订单信息
* @param event 流转事件
* @return
*/
public synchronized boolean handle(Order order, OrderEventsEnum event) {
//synchronized 解决线程安全问题,如果是分布式多节点,则需要用分布式锁 order_id 维度
//默认为失败
boolean result = false;
//检查事件初始状态
boolean checkStatus = OrderEventsEnum.checkEventStatus(event,order.getStatus());
if (checkStatus) {
//触发事件流程
boolean isEvent = sendEvent(event, order);
if(!isEvent){
throw new RuntimeException("订单状态流转事件失败");
}
result = true;
//如果是分布式锁 需要在这里解锁释放资源
} else {
log.error("事件event:{},起始状态status:{},不匹配",event,order.getStatus());
}
return result;
}
/**
* 发送订单流转事件
* @param event 事件
* @param order 订单
* @return
*/
private boolean sendEvent(OrderEventsEnum event, Order order) {
boolean result = false;
try {
Message message = MessageBuilder.withPayload(event).setHeader("order", order).build();
orderStatusMachine.start();
// 尝试恢复状态机状态
persister.restore(orderStatusMachine, order);
System.out.println("发送事件...............");
result = orderStatusMachine.sendEvent(message);
// 持久化状态机状态
persister.persist(orderStatusMachine, order);
} catch (Exception e) {
e.printStackTrace();
} finally {
orderStatusMachine.stop();
}
return result;
}
}
注意状态机线程安全问题,分布式环境时需要用分布式锁。
@WithStateMachine(name = "orderStatusMachine")
public class OrderStatusListener {
private static final String STR_ORDER = "order";
//无状态 -> 待付款 用户提交订单
@OnTransition(source = "NO_STATE", target = "PAY_WAIT")
public void noStateToPayWaitEvent(Message message) {
Order order = (Order) message.getHeaders().get(STR_ORDER);
if (!Objects.isNull(order)
&& OrderStatusEnum.NO_STATE.getCode().equals(order.getStatus())) {
System.out.println("用户提交订单,触发相关事件");
order.setStatus(OrderStatusEnum.PAY_WAIT.getCode());
System.out.println("订单状态变更为待支付");
System.out.println("锁优惠券");
System.out.println("扣减商品库存");
System.out.println("发送30min失效的MQ消息");
}
}
// 待付款 -> 待发货
@OnTransition(source = "PAY_WAIT", target = "DELIVERY_WAIT")
public void payWaitToDeliveryWaitEvent(Message message) {
Order order = (Order) message.getHeaders().get(STR_ORDER);
if (!Objects.isNull(order)
&& OrderStatusEnum.PAY_WAIT.getCode().equals(order.getStatus())) {
System.out.println("用户支付成功,触发相关事件");
order.setStatus(OrderStatusEnum.DELIVERY_WAIT.getCode());
System.out.println("订单状态变更为待发货");
System.out.println("通知商家发货MQ");
System.out.println("订单拆单");
System.out.println("会员权益");
System.out.println("销毁优惠券");
}
}
//待付款 -> 交易关闭 用户取消订单或订单未支付超时
@OnTransition(source = "PAY_WAIT", target = "CLOSED")
public void payWaitToClosedEvent(Message message) {
Order order = (Order) message.getHeaders().get(STR_ORDER);
if (!Objects.isNull(order)
&& OrderStatusEnum.PAY_WAIT.getCode().equals(order.getStatus())) {
System.out.println("用户取消订单,触发相关事件");
order.setStatus(OrderStatusEnum.CLOSED.getCode());
System.out.println("订单状态变更为交易关闭");
System.out.println("释放优惠券");
System.out.println("释放商品库存");
}
}
//待发货 -> 待收货 商家已发货待用户收货
@OnTransition(source = "DELIVERY_WAIT", target = "RECEIPT_WAIT")
public void deliveryWaitToReceiptWaitEvent(Message message) {
Order order = (Order) message.getHeaders().get(STR_ORDER);
if (!Objects.isNull(order)
&& OrderStatusEnum.DELIVERY_WAIT.getCode().equals(order.getStatus())) {
System.out.println("商家已发货,触发相关事件");
System.out.println("商品包装");
System.out.println("订单分拣");
System.out.println("快递配送");
order.setStatus(OrderStatusEnum.RECEIPT_WAIT.getCode());
System.out.println("变更订单状态为已发货");
}
}
//待发货 -> 待收货 商家已发货待用户收货
@OnTransition(source = "DELIVERY_WAIT", target = "CLOSED")
public void deliveryWaitToCloseEvent(Message message) {
Order order = (Order) message.getHeaders().get(STR_ORDER);
if (!Objects.isNull(order)
&& OrderStatusEnum.DELIVERY_WAIT.getCode().equals(order.getStatus())) {
System.out.println("商家已发货,触发相关事件");
System.out.println("商品包装");
System.out.println("订单分拣");
System.out.println("快递配送");
order.setStatus(OrderStatusEnum.CLOSED.getCode());
System.out.println("变更订单状态为已发货");
}
}
//其他的和上面类似 先忽略掉
}
@SpringBootTest
class StateApplicationTests {
@Autowired
private OrderStatusMachineService orderStatusMachineService;
@Test
void contextLoads() {
Order order = new Order();
order.setStatus(OrderStatusEnum.NO_STATE.getCode());
order.setOrderNumber("n01");
order.setAmount(1000L);
//用户提交订单
orderStatusMachineService.handle(order, OrderEventsEnum.NO_STATE_TO_PAY_WAIT_EVENT);
//用户支付订单
orderStatusMachineService.handle(order, OrderEventsEnum.PAY_WAIT_TO_DELIVERY_WAIT_EVENT);
//商家发货
orderStatusMachineService.handle(order, OrderEventsEnum.DELIVERY_WAIT_TO_RECEIPT_WAIT_EVENT);
}
}
执行结果:
发送事件...............
用户提交订单,触发相关事件
订单状态变更为待支付
锁优惠券
扣减商品库存
发送30min失效的MQ消息
订单推送...............Order(status=5, orderNumber=n01, amount=1000)
发送事件...............
用户支付成功,触发相关事件
订单状态变更为待发货
通知商家发货MQ
订单拆单
会员权益
销毁优惠券
订单推送...............Order(status=10, orderNumber=n01, amount=1000)
发送事件...............
商家已发货,触发相关事件
商品包装
订单分拣
快递配送
变更订单状态为已发货
订单推送...............Order(status=15, orderNumber=n01, amount=1000)
由于Spring StateMachine是有状态的,且其单例模式是线程不安全的,在高并发时状态机会出现状态混乱问题,则不建议在生产环境下使用Spring StateMachine的单例模式。
Spring StateMachine支持2种模式:单例和工厂模式。刚刚谈到了单例模式问题,推荐使用工厂模式,它是线程安全的。
/**
* 订单状态机配置
*/
@Configuration
@EnableStateMachineFactory(name = "orderStateMachineFactory")
public class OrderStateMachineFactoryConfig extends EnumStateMachineConfigurerAdapter {
/**
* 主订单状态机
*/
public static final String masterStateMachine = "masterStateMachine";
/**
* 初始化状态
*
* @param orderStatusMachineConfig:
* @throws Exception:
*/
public void configure(StateMachineStateConfigurer orderStatusMachineConfig) throws Exception {
orderStatusMachineConfig.withStates()
.initial(OrderStatusEnum.NO_STATE)
.states(EnumSet.allOf(OrderStatusEnum.class));
}
/**
* 配置状态转换事件关系
*
* @param transitions transitions
* @throws Exception:
*/
public void configure(StateMachineTransitionConfigurer transitions) throws Exception {
transitions
//无状态 -> 待付款 用户提交订单
.withExternal().source(OrderStatusEnum.NO_STATE).target(OrderStatusEnum.PAY_WAIT).event(OrderEventsEnum.NO_STATE_TO_PAY_WAIT_EVENT)
.and()
//待付款 -> 待发货
.withExternal().source(OrderStatusEnum.PAY_WAIT).target(OrderStatusEnum.DELIVERY_WAIT).event(OrderEventsEnum.PAY_WAIT_TO_DELIVERY_WAIT_EVENT)
.and()
//待付款 -> 交易关闭
.withExternal().source(OrderStatusEnum.PAY_WAIT).target(OrderStatusEnum.CLOSED).event(OrderEventsEnum.PAY_WAIT_TO_CLOSED_EVENT)
.and()
//待发货 -> 待收货
.withExternal().source(OrderStatusEnum.DELIVERY_WAIT).target(OrderStatusEnum.RECEIPT_WAIT).event(OrderEventsEnum.DELIVERY_WAIT_TO_RECEIPT_WAIT_EVENT)
.and()
//待发货 -> 交易关闭
.withExternal().source(OrderStatusEnum.DELIVERY_WAIT).target(OrderStatusEnum.CLOSED).event(OrderEventsEnum.DELIVERY_WAIT_TO_CLOSED_EVENT)
.and()
//待收货 -> 待评价
.withExternal().source(OrderStatusEnum.RECEIPT_WAIT).target(OrderStatusEnum.EVALUATE_WAIT).event(OrderEventsEnum.RECEIPT_WAIT_TO_EVALUATE_WAIT_EVENT)
.and()
//待收货 -> 售后中
.withExternal().source(OrderStatusEnum.RECEIPT_WAIT).target(OrderStatusEnum.REFUND).event(OrderEventsEnum.RECEIPT_WAIT_TO_REFUND_EVENT)
.and()
//售后中 -> 交易结束
.withExternal().source(OrderStatusEnum.REFUND).target(OrderStatusEnum.CLOSED).event(OrderEventsEnum.REFUND_TO_CLOSED_EVENT)
.and()
//待评价 -> 交易完成
.withExternal().source(OrderStatusEnum.EVALUATE_WAIT).target(OrderStatusEnum.COMPLETE).event(OrderEventsEnum.EVALUATE_WAIT_TO_COMPLETE_EVENT);
}
/**
* 持久化配置
* 实际使用中,可以配合redis等,进行持久化操作
*
* @return
*/
@Bean
public StateMachinePersister statusMachinePersister() {
return new DefaultStateMachinePersister<>(new StateMachinePersist() {
@Override
public void write(StateMachineContext context, Order order) throws Exception {
//1. 加入redis缓存中 key:order.id ; value: version (解决读一致)
//2. 记录推送本地日志 (解决 消息丢失)
//3. MQ消息推送 (广播模式 推送给 商户中心和运营中心)
System.out.println("订单推送..............." + order);
}
@Override
public StateMachineContext read(Order order) throws Exception {
//此处直接获取order中的状态,其实并没有进行持久化读取操作
return new DefaultStateMachineContext<>(OrderStatusEnum.getByCode(order.getStatus()), null, null, null, null,masterStateMachine);
}
});
}
}
@Service
@Slf4j
public class OrderStatusMachineHandle {
@Autowired
private StateMachineFactory orderStateMachineFactory;
@Resource(name = "statusMachinePersister")
private StateMachinePersister persister;
/**
* 状态机流转
* @param order 订单信息
* @param event 流转事件
* @return
*/
public synchronized boolean handle(Order order, OrderEventsEnum event) {
//synchronized 解决线程安全问题,如果是分布式多节点,则需要用分布式锁 order_id 维度
//默认为失败
boolean result = false;
//检查事件初始状态
boolean checkStatus = OrderEventsEnum.checkEventStatus(event,order.getStatus());
if (checkStatus) {
//触发事件流程
boolean isEvent = sendEvent(event, order);
if(!isEvent){
throw new RuntimeException("订单状态流转事件失败");
}
result = true;
//如果是分布式锁 需要在这里解锁释放资源
} else {
log.error("事件event:{},起始状态status:{},不匹配",event,order.getStatus());
}
return result;
}
/**
* 发送订单流转事件
* @param event 事件
* @param order 订单
* @return
*/
private boolean sendEvent(OrderEventsEnum event, Order order) {
boolean result = false;
Message message = MessageBuilder.withPayload(event).setHeader("order", order).build();
//工厂中获取状态机
StateMachine orderStateMachine = orderStateMachineFactory.getStateMachine(OrderStateMachineFactoryConfig.masterStateMachine);
try {
orderStateMachine.start();
// 尝试恢复状态机状态
persister.restore(orderStateMachine, order);
System.out.println("发送事件...............");
result = orderStateMachine.sendEvent(message);
// 持久化状态机状态
persister.persist(orderStateMachine, order);
} catch (Exception e) {
e.printStackTrace();
} finally {
orderStateMachine.stop();
}
return result;
}
}
@WithStateMachine(id = OrderStateMachineFactoryConfig.masterStateMachine)
public class OrderStatusListener {
private static final String STR_ORDER = "order";
//无状态 -> 待付款 用户提交订单
@OnTransition(source = "NO_STATE", target = "PAY_WAIT")
public void noStateToPayWaitEvent(Message message) {
Order order = (Order) message.getHeaders().get(STR_ORDER);
if (!Objects.isNull(order)
&& OrderStatusEnum.NO_STATE.getCode().equals(order.getStatus())) {
System.out.println("用户提交订单,触发相关事件");
order.setStatus(OrderStatusEnum.PAY_WAIT.getCode());
System.out.println("订单状态变更为待支付");
System.out.println("锁优惠券");
System.out.println("扣减商品库存");
System.out.println("发送30min失效的MQ消息");
}
}
// 待付款 -> 待发货
@OnTransition(source = "PAY_WAIT", target = "DELIVERY_WAIT")
public void payWaitToDeliveryWaitEvent(Message message) {
Order order = (Order) message.getHeaders().get(STR_ORDER);
if (!Objects.isNull(order)
&& OrderStatusEnum.PAY_WAIT.getCode().equals(order.getStatus())) {
System.out.println("用户支付成功,触发相关事件");
order.setStatus(OrderStatusEnum.DELIVERY_WAIT.getCode());
System.out.println("订单状态变更为待发货");
System.out.println("通知商家发货MQ");
System.out.println("订单拆单");
System.out.println("会员权益");
System.out.println("销毁优惠券");
}
}
//待付款 -> 交易关闭 用户取消订单或订单未支付超时
@OnTransition(source = "PAY_WAIT", target = "CLOSED")
public void payWaitToClosedEvent(Message message) {
Order order = (Order) message.getHeaders().get(STR_ORDER);
if (!Objects.isNull(order)
&& OrderStatusEnum.PAY_WAIT.getCode().equals(order.getStatus())) {
System.out.println("用户取消订单,触发相关事件");
order.setStatus(OrderStatusEnum.CLOSED.getCode());
System.out.println("订单状态变更为交易关闭");
System.out.println("释放优惠券");
System.out.println("释放商品库存");
}
}
//待发货 -> 待收货 商家已发货待用户收货
@OnTransition(source = "DELIVERY_WAIT", target = "RECEIPT_WAIT")
public void deliveryWaitToReceiptWaitEvent(Message message) {
Order order = (Order) message.getHeaders().get(STR_ORDER);
if (!Objects.isNull(order)
&& OrderStatusEnum.DELIVERY_WAIT.getCode().equals(order.getStatus())) {
System.out.println("商家已发货,触发相关事件");
System.out.println("商品包装");
System.out.println("订单分拣");
System.out.println("快递配送");
order.setStatus(OrderStatusEnum.RECEIPT_WAIT.getCode());
System.out.println("变更订单状态为已发货");
}
}
//待发货 -> 待收货 商家已发货待用户收货
@OnTransition(source = "DELIVERY_WAIT", target = "CLOSED")
public void deliveryWaitToCloseEvent(Message message) {
Order order = (Order) message.getHeaders().get(STR_ORDER);
if (!Objects.isNull(order)
&& OrderStatusEnum.DELIVERY_WAIT.getCode().equals(order.getStatus())) {
System.out.println("商家已发货,触发相关事件");
System.out.println("商品包装");
System.out.println("订单分拣");
System.out.println("快递配送");
order.setStatus(OrderStatusEnum.CLOSED.getCode());
System.out.println("变更订单状态为已发货");
}
}
//其他的和上面类似 先忽略掉
}
@SpringBootTest
class StateApplicationTests {
@Autowired
private OrderStatusMachineHandle orderStatusMachineHandle;
@Test
void contextLoads() {
Order order = new Order();
order.setStatus(OrderStatusEnum.NO_STATE.getCode());
order.setOrderNumber("n01");
order.setAmount(1000L);
//用户提交订单
orderStatusMachineHandle.handle(order, OrderEventsEnum.NO_STATE_TO_PAY_WAIT_EVENT);
//用户支付订单
orderStatusMachineHandle.handle(order, OrderEventsEnum.PAY_WAIT_TO_DELIVERY_WAIT_EVENT);
//商家发货
orderStatusMachineHandle.handle(order, OrderEventsEnum.DELIVERY_WAIT_TO_RECEIPT_WAIT_EVENT);
}
}
执行结果:
发送事件...............
用户提交订单,触发相关事件
订单状态变更为待支付
锁优惠券
扣减商品库存
发送30min失效的MQ消息
订单推送...............Order(status=5, orderNumber=n01, amount=1000)
发送事件...............
用户支付成功,触发相关事件
订单状态变更为待发货
通知商家发货MQ
订单拆单
会员权益
销毁优惠券
订单推送...............Order(status=10, orderNumber=n01, amount=1000)
发送事件...............
商家已发货,触发相关事件
商品包装
订单分拣
快递配送
变更订单状态为已发货
订单推送...............Order(status=15, orderNumber=n01, amount=1000)
经过多次测试和学习发现了Spring StateMachine以下几个问题:
针对以上问题的方案:
同上一篇提到的状态机问题,在业务快速发展过程中,要满足的需求会越来越多
单个状态机很难满足需求的迭代,建议在设计初期就考虑到这个问题,推荐创建至少2个状态机来管理订单状态,即主订单状态机+子订单状态机(如果涉及到物流状态则需要再定义一个物流状态机,如果售后非常麻烦则需要定义一个售后状态机),主子状态机可以很好解决大部分订单状态的问题。
定义状态机少会导致业务耦合严重、扩展性差、状态膨胀等问题,定义状态机太多会导致业务离散、整合困难、维护成本高等问题,至于要如何选择需要契合你实际的业务,任何架构设计都是服务于业务的。
下篇再来分享SaaS订单的分片设计。