参考自:https://github.com/sunbufu/spring-state-machine-demo
依赖:
<dependency>
<groupId>org.springframework.statemachinegroupId>
<artifactId>spring-statemachine-coreartifactId>
<version>2.0.1.RELEASEversion>
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;
}
}
};
}
}
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 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());
}
}
测试结果: 成功时
可以参考:多个状态机以及多种状态机共存的情况
多个状态机,多种状态机以及各种持久化的相关测试暂时没完成,以后有时间再做。