Spring StateMachine个人小结
一、有关概念梳理
官方流程图:
二、简单demo实验
参考自:https://github.com/sunbufu/spring-state-machine-demo
依赖:
<dependency>
<groupId>org.springframework.statemachine</groupId>
<artifactId>spring-statemachine-core</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
- 定义两个枚举类 分别是订单状态和事件
public enum OrderStatus {
WAIT_PAYMAENT("等待支付"),
WAIT_DELIVER("待发货"),
WAIT_RECEIVE("待收货"),
FINISH("完成");
//状态描述
private String desc;
OrderStatus(String desc){
this.desc=desc;
}
}
//相关事件
public enum OrderStatusChangeEvent {
PAYED("支付"),
DELIVERY("发送"),
RECEIVED("接收");
//状态描述
private String desc;
OrderStatusChangeEvent(String desc){
this.desc=desc;
}
}
- 订单对象创建
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Order {
/** 订单id */
private Integer id;
/** 状态 */
private OrderStatus status;
}
@Component
public class OrderMapper {
private static Map<Integer, Order> dateBase=new HashMap<>();
private static int id=1;
/**
*
* @param order
* @return
*/
public Order save(Order order){
if(order.getId()==null){
order.setId(id++);
}
dateBase.put(order.getId(),order);
return order;
}
/**
* 查询
* @param id
* @return
*/
public Order select(int id){
return dateBase.get(id);
}
}
-
StateMachine配置
按照官方文档给出的说明,创建stateMachine有两种方法:1. 用Builder的形式 2.用JavaConfig的形式
这里使用状态机配置的形式去创建
StateMachineConfig 里面可以根据自己需要调整是否持久化存储,也提供了一些直接可以存储到redis的接口。另外也提供了一些listener根据自己需要去编写特定的监听器功能。
@Configuration @EnableStateMachine(name = "orderStateMachine") public class OrderStateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderStatus, OrderStatusChangeEvent> { // 配置状态 private Logger logger = LoggerFactory.getLogger(getClass()); /** * * @param states * @throws Exception */ @Override public void configure(StateMachineStateConfigurer<OrderStatus, OrderStatusChangeEvent> states) throws Exception { states.withStates() .initial(OrderStatus.WAIT_PAYMAENT) .states(EnumSet.allOf(OrderStatus.class)); } /** * 配置状态和事件之间的转换关系 * @param transitions * @throws Exception */ @Override public void configure(StateMachineTransitionConfigurer<OrderStatus, OrderStatusChangeEvent> transitions) throws Exception { transitions.withExternal().source(OrderStatus.WAIT_PAYMAENT).target(OrderStatus.WAIT_DELIVER).event(OrderStatusChangeEvent.PAYED).and() .withExternal().source(OrderStatus.WAIT_DELIVER).target(OrderStatus.WAIT_RECEIVE).event(OrderStatusChangeEvent.DELIVERY).and() .withExternal().source(OrderStatus.WAIT_RECEIVE).target(OrderStatus.FINISH).event(OrderStatusChangeEvent.RECEIVED); } /** * 制定状态机的处理监听器 * @param config * @throws Exception */ @Override public void configure(StateMachineConfigurationConfigurer<OrderStatus, OrderStatusChangeEvent> config) throws Exception { config.withConfiguration().listener(listener()); } /** * 可以持久化到redis里面 https://projects.spring.io/spring-statemachine/ */ /** 状态机持久化 */ @Bean public StateMachinePersister<OrderStatus, OrderStatusChangeEvent, Order> orderStateMachinePersister() { return new DefaultStateMachinePersister<>(new StateMachinePersist<OrderStatus, OrderStatusChangeEvent, Order>() { @Override public void write(StateMachineContext<OrderStatus, OrderStatusChangeEvent> context, Order order) { // 进行持久化操作 order.setStatus(context.getState()); } @Override public StateMachineContext<OrderStatus, OrderStatusChangeEvent> read(Order order) { // 读取状态并设置到context中 return new DefaultStateMachineContext<>(order.getStatus(), null, null, null); } }); } /** * 配置listener * @return */ @Bean public StateMachineListener<OrderStatus,OrderStatusChangeEvent> listener(){ return new StateMachineListenerAdapter<OrderStatus,OrderStatusChangeEvent>(){ @Override public void transition(Transition<OrderStatus, OrderStatusChangeEvent> transition) { if(transition.getTarget().getId()==OrderStatus.WAIT_PAYMAENT){ logger.info("用户订单创建,待支付"); return; } if(transition.getSource().getId()==OrderStatus.WAIT_PAYMAENT && transition.getTarget().getId()==OrderStatus.WAIT_DELIVER){ logger.info("用户已支付,待发货"); return; } if (transition.getSource().getId()==OrderStatus.WAIT_DELIVER && transition.getTarget().getId()==OrderStatus.WAIT_RECEIVE){ logger.info("商家已发货,待接收"); return; } if (transition.getSource().getId()==OrderStatus.WAIT_RECEIVE && transition.getTarget().getId()==OrderStatus.FINISH){ logger.info("用户已收货,订单完成"); return; } } }; } }
- orderService接口和实现类
public interface OrderService { /** * 创建订单 * @return Order */ Order create(); /** * 支付 * @param id * @return */ Order pay(int id); /** * 发货 * @param id * @return */ Order deliver(int id); /** * 接收 * @param id * @return */ Order receive(int id); }
@Slf4j @Service public class OrderServiceImpl implements OrderService { private final Logger logger = LoggerFactory.getLogger(OrderServiceImpl.class); @Resource private StateMachine<OrderStatus,OrderStatusChangeEvent> orderStateMachine; @Autowired private OrderMapper orderMapper; @Autowired private StateMachinePersister<OrderStatus,OrderStatusChangeEvent,Order> persister; @Override public Order create() { Order order = new Order(); order.setStatus(OrderStatus.WAIT_PAYMAENT); return orderMapper.save(order); } @Override public Order pay(int id) { Order order = orderMapper.select(id); if (!sendEvent(OrderStatusChangeEvent.PAYED, order)) { throw new RuntimeException(" 等待支付 -> 等待发货 失败, 状态异常 order=" + order); } return order; } @Override public Order deliver(int id) { Order order = orderMapper.select(id); if (!sendEvent(OrderStatusChangeEvent.DELIVERY, order)) { throw new RuntimeException(" 等待发货 -> 等待收货 失败,状态异常 order=" + order); } return order; } @Override public Order receive(int id) { Order order = orderMapper.select(id); if (!sendEvent(OrderStatusChangeEvent.RECEIVED, order)) { throw new RuntimeException(" 等待收货 -> 完成 失败,状态异常 order=" + order); } return order; } /** * 发送订单状态转换事件 * * @param event 事件 * @param order 订单 * @return 执行结果 */ private boolean sendEvent(OrderStatusChangeEvent event, Order order) { boolean result = false; try { orderStateMachine.start(); // 设置状态机状态 persister.restore(orderStateMachine, order); result = orderStateMachine.sendEvent(MessageBuilder.withPayload(event).setHeader("order", order).build()); // 保存状态机状态 persister.persist(orderStateMachine, order); } catch (Exception e) { e.printStackTrace(); } finally { orderStateMachine.stop(); } return result; } }
@Resource private StateMachine<OrderStatus,OrderStatusChangeEvent> orderStateMachine;
在编写过程中 一开始仿照官网的写法,用的@Autowired 这里会报错,显示找不到对应注入的Statemachine,但是对运行结果没啥影响,后来看到别的文章用的@Resource 这里就不会再报错了。
- 测试
@SpringBootTest class SpringStateMachineDemoApplicationTests { @Autowired private OrderService orderService; @Test public void testSuccess(){ Order order = orderService.create(); orderService.pay(order.getId()); orderService.deliver(order.getId()); orderService.receive(order.getId()); assertTrue(OrderStatus.FINISH == order.getStatus()); } @Test public void testError(){ Order order = orderService.create(); // orderService.pay(order.getId()); // 少这一步 测试一下出现意外的状况 orderService.deliver(order.getId()); orderService.receive(order.getId()); assertTrue(OrderStatus.FINISH == order.getStatus()); } }
测试结果: 成功时
失败时:
三、其他实验扩展
可以参考:多个状态机以及多种状态机共存的情况
多个状态机,多种状态机以及各种持久化的相关测试暂时没完成,以后有时间再做。