Spring Statemachine

Spring StateMachine个人小结

一、有关概念梳理

Spring Statemachine_第1张图片

官方流程图:
Spring Statemachine_第2张图片

二、简单demo实验

Spring Statemachine_第3张图片

参考自:https://github.com/sunbufu/spring-state-machine-demo

依赖:

        <dependency>
            <groupId>org.springframework.statemachinegroupId>
            <artifactId>spring-statemachine-coreartifactId>
            <version>2.0.1.RELEASEversion>
        dependency>
  1. 定义两个枚举类 分别是订单状态和事件
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;
    }
}
  1. 订单对象创建
@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);
    }
}

  1. 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;
                    }
                }
            };
        }
    }
    
    1. 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 orderStateMachine;
    

    在编写过程中 一开始仿照官网的写法,用的@Autowired 这里会报错,显示找不到对应注入的Statemachine,但是对运行结果没啥影响,后来看到别的文章用的@Resource 这里就不会再报错了。

    1. 测试
    @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());
        }
    }
    
    

    测试结果: 成功时

Spring Statemachine_第4张图片

失败时:
失败时

三、其他实验扩展

可以参考:多个状态机以及多种状态机共存的情况

多个状态机,多种状态机以及各种持久化的相关测试暂时没完成,以后有时间再做。

你可能感兴趣的:(SpringBoot,spring,java)