状态机-持久化

原创
2020/06/10 19:06
阅读数 2.7K

状态机为何持久化

每次用到的时候新创建一个状态机,太奢侈了,官方文档里面也提到过这点。而且创建出来的实例,其状态也跟当前订单的不符。Spring statemachine暂时不支持每次创建时指定当前状态(当然通过特殊手段能实现,后续解剖),所以对状态机引擎实例的持久化,就成了必须要考虑的问题。Spring statemachine并不支持随意指定初始状态,每次创建都是固定的初始化状态,其实也只是有好处的,标准版流程,而且可以保证安全,每个节点都是按照事先定义好的流程跑下来,而不是随意指定。所以,状态机引擎实例的持久化。

状态机持久化方式

状态机持久化目前分三种:

  • 基于内存持久化:主要存入内存,在Java中主要是集合中,如HashMap集合,这种做法不可取;
  • 基于数据库持久化:主要是将数据写入数据库中,这种做法可以用于实际开发中可取;
  • 基于缓存(redis做法要结合实际情况使用;

基于订单简单流程实战

如下图,本文示例一个简单的订单流程,基于数据库持久化方案

订单状态模型

订单状态枚举类OrderStatusEnum

    @ToString
    public enum OrderStatusEnum {
        /**
         * 待支付
         */
        WAIT_PAYMENT,
        /**
         * 待发货
         */
        WAIT_DELIVER,
        /**
         * 待收货
         */
        WAIT_RECEIVE,
        /**
         * 订单完成
         */
        FINISH;
    }

事件枚举类OrderStatusChangeEventEnum

    @ToString
    public enum OrderStatusChangeEventEnum {
        /**
         * 支付
         */
        PAYED,
        /**
         * 发货
         */
        DELIVERY,
        /**
         * 确认收货
         */
        RECEIVED;
    }

订单实体类OrderEnity

   	@Entity
    @Table(name = "t_order")
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @ToString
    public class OrderEnity implements Serializable {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "id",length =10,nullable = false)
        private Integer id;
    
        @NotNull
        @Column(name = "order_id",length = 10,nullable = false)
        private Integer orderId;
    
        @NotNull
        @Enumerated(EnumType.ORDINAL)
        @Column(name = "order_status",length = 2)
        private OrderStatusEnum status;
    } 

Repository类OrderRepository

    public interface OrderRepository extends JpaRepository<OrderEnity, Integer> {
        OrderEnity findByOrderId(Integer order);
    }

订单的状态集合初始化以及状态转移事件注册

应用在启动时候需要注册状态集合以及事件,主要会涉及如下两个类

  • StateMachineStateConfigurer<S, E> 配置状态集合以及初始状态,泛型参数S代表状态,E代表事件。

  • StateMachineTransitionConfigurer<S, E> 配置状态流的转移,可以定义状态转换接受的事件。

      @Configuration
      @EnableStateMachine(name = "orderStateMachine")
      public class OrderStateMachineConfig extends StateMachineConfigurerAdapter<OrderStatusEnum, OrderStatusChangeEventEnum> {
          /**
           * 配置初始事件以及状态集合
           * @param states 状态
           * @throws Exception
           */
          @Override
          public void configure(StateMachineStateConfigurer<OrderStatusEnum, OrderStatusChangeEventEnum> states) throws Exception {
              states.withStates().initial(OrderStatusEnum.WAIT_PAYMENT).states(EnumSet.allOf(OrderStatusEnum.class));
          }
    
          /**
           * 配置状态转换事件关系
           * @param transitions 事件
           * @throws Exception
           */
          @Override
          public void configure(StateMachineTransitionConfigurer<OrderStatusEnum,
                      OrderStatusChangeEventEnum> transitions) throws Exception {
              transitions.withExternal()
                      .source(OrderStatusEnum.WAIT_PAYMENT)
                      .target(OrderStatusEnum.WAIT_DELIVER)
                      .event(OrderStatusChangeEventEnum.PAYED)
                      .and()
                      .withExternal()
                      .source(OrderStatusEnum.WAIT_DELIVER).target(OrderStatusEnum.WAIT_RECEIVE)
                      .event(OrderStatusChangeEventEnum.DELIVERY)
                      .and()
                      .withExternal()
                      .source(OrderStatusEnum.WAIT_RECEIVE).target(OrderStatusEnum.FINISH)
                      .event(OrderStatusChangeEventEnum.RECEIVED);
          }
      }
    

状态转移的监听器

状态转移过程中,可以通过监听器(Listener)来处理一些持久化或者业务监控等任务。在需要持久化的场景中,可以在状态机模式中的监听器中添加持久化的处理操作。在此主要涉及如下几个:

  1. StateMachineListener事件监听器(通过Spring的event机制实现),监听stateEntered(进入状态)、stateExited(离开状态)、eventNotAccepted(事件无法响应)、transition(转换)、transitionStarted(转换开始)、transitionEnded(转换结束)、stateMachineStarted(状态机启动)、stateMachineStopped(状态机关闭)、stateMachineError(状态机异常)等事件,借助listener可以跟踪状态转移;
  2. StateChangeInterceptor 拦截器接口,不同于Listener,其可以改变状态转移链的变化主要在preEvent(事件预处理)、preStateChange(状态变更的前置处理)、postStateChange(状态变更的后置处理)、preTransition(转化的前置处理)、postTransition(转化的后置处理)、stateMachineError(异常处理)等执行点生效;
  3. StateMachine状态机实例,Spring statemachine支持单例、工厂模式两种方式创建,每个statemachine有一个独有的machineId用于标识machine实例;需要注意的是statemachine实例内部存储了当前状态机等上下文相关的属性,因此这个实例不能够被多线程共享。

为了方便拓展到更多的监听器以及管理监听器和拦截器, 定义可以管理两者的处理器Handler``PersistStateMachineHandler以及持久化监听器实体的监听器OrderPersistStateChangeListener

监听器的Handler以及接口定义PersistStateMachineHandler:

public class PersistStateMachineHandler extends LifecycleObjectSupport {

private final StateMachine<OrderStatusEnum, OrderStatusChangeEventEnum> stateMachine;

private final PersistingStateChangeInterceptor interceptor = new PersistingStateChangeInterceptor();

private final CompositePersistStateChangeListener listeners = new CompositePersistStateChangeListener();

/**
 * 实例化一个新的持久化状态机Handler
 *
 * @param stateMachine 状态机实例
 */
public PersistStateMachineHandler(StateMachine<OrderStatusEnum, OrderStatusChangeEventEnum> stateMachine) {
    Assert.notNull(stateMachine, "State machine must be set");
    this.stateMachine = stateMachine;
}

@Override
protected void onInit() throws Exception {
    stateMachine.getStateMachineAccessor().doWithAllRegions(p -> p.addStateMachineInterceptor(interceptor));
}


/**
 * 处理entity的事件
 *
 * @param event
 * @param state
 * @return 如果事件被接受处理,返回true
 */
public boolean handleEventWithState(Message<OrderStatusChangeEventEnum> event,
                                    OrderStatusEnum state) {
    stateMachine.stop();
    List<StateMachineAccess<OrderStatusEnum, OrderStatusChangeEventEnum>> withAllRegions =
            stateMachine.getStateMachineAccessor().withAllRegions();
    withAllRegions.forEach(p -> p.resetStateMachine(new DefaultStateMachineContext<>(state,
            null, null, null)));
    stateMachine.start();
    return stateMachine.sendEvent(event);
}

/**
 * 添加listener
 *
 * @param listener the listener
 */
public void addPersistStateChangeListener(PersistStateChangeListener listener) {
    listeners.register(listener);
}


/**
 * 可以通过 addPersistStateChangeListener,增加当前Handler的PersistStateChangeListener。
 * 在状态变化的持久化触发时,会调用相应的实现了PersistStateChangeListener的Listener实例。
 */
public interface PersistStateChangeListener {

    /**
     * 当状态被持久化,调用此方法
     *
     * @param state
     * @param message
     * @param transition
     * @param stateMachine 状态机实例
     */
    void onPersist(State<OrderStatusEnum, OrderStatusChangeEventEnum> state,
                   Message<OrderStatusChangeEventEnum> message, Transition<OrderStatusEnum,
            OrderStatusChangeEventEnum> transition,
                   StateMachine<OrderStatusEnum, OrderStatusChangeEventEnum> stateMachine);
}

/**
 * 状态拦截器
 */
private  class PersistingStateChangeInterceptor extends StateMachineInterceptorAdapter<OrderStatusEnum, OrderStatusChangeEventEnum> {
    /**
     * 状态预处理的拦截器方法
     * @param state
     * @param message
     * @param transition
     * @param stateMachine
     */
    @Override
    public void preStateChange(State<OrderStatusEnum, OrderStatusChangeEventEnum> state,
                               Message<OrderStatusChangeEventEnum> message,
                               Transition<OrderStatusEnum, OrderStatusChangeEventEnum> transition,
                               StateMachine<OrderStatusEnum,
            OrderStatusChangeEventEnum> stateMachine) {
        listeners.onPersist(state, message, transition, stateMachine);
    }
}

    private static class CompositePersistStateChangeListener extends AbstractCompositeListener<PersistStateChangeListener> implements
            PersistStateChangeListener {

        @Override
        public void onPersist(State<OrderStatusEnum, OrderStatusChangeEventEnum> state,
                              Message<OrderStatusChangeEventEnum> message,
                              Transition<OrderStatusEnum, OrderStatusChangeEventEnum> transition,
                              StateMachine<OrderStatusEnum,
                OrderStatusChangeEventEnum> stateMachine) {
            for (Iterator<PersistStateChangeListener> iterator = getListeners().reverse(); iterator.hasNext(); ) {
                PersistStateChangeListener listener = iterator.next();
                listener.onPersist(state, message, transition, stateMachine);
            }
        }
    }
}

持久化状态发生变化的订单实体OrderPersistStateChangeListener:

public class OrderPersistStateChangeListener implements    PersistStateMachineHandler.PersistStateChangeListener {
    
        @Autowired
        private OrderRepository orderRepository;
        /**
         * 当状态被持久化,调用此方法
         *
         * @param state
         * @param message
         * @param transition
         * @param stateMachine 状态机实例
         */
        @Override
        public void onPersist(State<OrderStatusEnum, OrderStatusChangeEventEnum> state, Message<OrderStatusChangeEventEnum> message, Transition<OrderStatusEnum, OrderStatusChangeEventEnum> transition, StateMachine<OrderStatusEnum, OrderStatusChangeEventEnum> stateMachine) {
            if (message != null && message.getHeaders().containsKey("order")) {
                Integer  order = message.getHeaders().get("order", Integer.class);
                OrderEnity o = orderRepository.findByOrderId(order);
                OrderStatusEnum status = state.getId();
                o.setStatus(status);
                orderRepository.save(o);
            }
         }
 }

注入监听器以及处理器

注入HandlerListener beanConfigurationOrderPersistHandlerConfig

        @Configuration
        public class OrderPersistHandlerConfig {
        
        @Autowired
        private StateMachine<OrderStatusEnum, OrderStatusChangeEventEnum> stateMachine;
        
        @Bean
        public OrderStateService persist() {
            PersistStateMachineHandler handler = persistStateMachineHandler();
            handler.addPersistStateChangeListener(persistStateChangeListener());
            return new OrderStateService(handler);
        }
    
        @Bean
        public PersistStateMachineHandler persistStateMachineHandler() {
            return new PersistStateMachineHandler(stateMachine);
        }
    
        @Bean
        public OrderPersistStateChangeListener persistStateChangeListener(){
            return new OrderPersistStateChangeListener();
        }
      }

订单服务类

在订单服务类中,即OrderStateService比较简单定义两个方法:

    @Component
    public class OrderStateService {
    
        private final PersistStateMachineHandler handler;
    
        public OrderStateService(PersistStateMachineHandler handler) {
            this.handler = handler;
        }
    
        @Autowired
        private OrderRepository orderRepository;
    
        public List<OrderEnity> getOrderList() {
            return orderRepository.findAll();
        }
    
        public boolean change(int order, OrderStatusChangeEventEnum event) {
            OrderEnity o = orderRepository.findByOrderId(order);
            return handler.handleEventWithState(MessageBuilder.withPayload(event)
                    .setHeader("order", order).build(), o.getStatus());
        }
    }

订单web

web入口,OrderController,如下:

    @RestController
    @RequestMapping("/order")
    public class OrderController {
        @Autowired
        private OrderStateService orderStateService;
    
        /**
         * 列出所有的订单列表
         *
         * @return
         */
        @GetMapping(value = "/orders")
        public ResponseEntity orders() {
           List<OrderEnity> orderList = orderStateService.getOrderList();
            return new ResponseEntity(orderList, HttpStatus.OK);
    
        }
    
        /**
         * 通过触发一个事件,改变一个订单的状态
         *
         * @param orderId
         * @param event
         * @return
         */
        @PostMapping(value = "/{orderId}")
        public ResponseEntity processOrderState(@PathVariable("orderId") Integer orderId,
                                                @RequestParam("event") OrderStatusChangeEventEnum event) {
            Boolean result = orderStateService.change(orderId, event);
            return new ResponseEntity(result, HttpStatus.OK);
        }
    }

验证状态转移逻辑

添加测试数据,添加4个订单,分别是WAIT_PAYMENT状态。

查询

request

http://localhost:8080/order/orders

response:

    [{
     "data": "Order{orderId=1, status=WAIT_PAYMENT},Order{orderId=2, status=WAIT_PAYMENT},Order{orderId=3, status=WAIT_PAYMENT},Order{orderId=4, status=WAIT_PAYMENT}",
    }]

变更状态

request

    http://localhost:8080/order/1?event=PAYED
    http://localhost:8080/order/2?event=PAYED
    http://localhost:8080/order/2?event=DELIVERY
    http://localhost:8089/order/2?event=DELIVERY

response:

    {
    "data": true
    }
    {
    "data": true
    }
    {
    "data": true
    }
    {
    "data": false
    }

验证持久化后的状态

request:

http://localhost:8080/order/orders

response:

    [{
     "data": "Order{orderId=1, status=WAIT_DELIVER},Order{orderId=2, status=WAIT_RECEIVE},Order{orderId=3, status=WAIT_PAYMENT},Order{orderId=4, status=WAIT_PAYMENT}",
    }]

本文主要是结合一个简单示例示范Spring-statemachine的集成抛砖引玉作用,在实际的业务实施中还会有更多复杂的情况,比如事务的处理,分布式事件消息,资源锁、异常时候状态不执行等系列问题,至此关于持久化状态机就分析到此。示例代码已经上传至码云上 https://gitee.com/ville/statemachine.git

展开阅读全文
加载中

作者的其它热门文章

打赏
1
1 收藏
分享
打赏
0 评论
1 收藏
1
分享
返回顶部
顶部