Spring状态机

发布时间 2023-12-14 11:09:35作者: lwx_R

1.依赖

<!--状态机-->
<dependency>
    <groupId>org.springframework.statemachine</groupId>
    <artifactId>spring-statemachine-core</artifactId>
    <version>2.0.1.RELEASE</version>
</dependency>

2.状态枚举类

public enum OrderStatus {
    //
    DELETE(0,"逻辑删除"),
    WAIT_PAYMENT(1,"待支付"),
    WAIT_TAKING(2,"待接单"),
    WAIT_DELIVER(3,"待发货"),
    WAIT_RECEIVE(4,"待收货"),
    FINISH(5,"订单结束"),
    CONSUMER_CANCEL(6,"消费者取消"),
    SHOP_CANCEL(7,"商家取消"),
    REFUND(8,"退款");

    private Integer value;
    private String name;

    OrderStatus(Integer value, String name) {
        this.value = value;
        this.name = name;
    }
    public Integer getValue(){
        return value;
    }

    public String getName(){
        return name;
    }

    /**
     * 根据value获得对应Enum对象
     * @param key
     * @return
     */
    public static OrderStatus getByKey(Integer key) {
        for (OrderStatus e : values()) {
            if (e.getValue().equals(key)) {
                return e;
            }
        }
        throw new RuntimeException("enum not exists.");
    }
}

3.状态事件枚举类

public enum OrderStatusChangeEvent {
    //支付,商家接单,骑手配送,确认收货
    PAYED,TAKING,DELIVERY, RECEIVED,CANCEL,UNTAKING,REFUND;
}

4.状态机配置

/**
 * 订单状态机配置
 */
@Configuration
@EnableStateMachine(name = "orderStateMachine")
public class OrderStateMachineConfig extends StateMachineConfigurerAdapter<OrderStatus, OrderStatusChangeEvent> {

    @Override
    public void configure(StateMachineConfigurationConfigurer<OrderStatus, OrderStatusChangeEvent> config) throws Exception {
        config.withConfiguration()
                .autoStartup(true)
                .listener(listener());
    }

    @Bean
    public StateMachineListener<OrderStatus, OrderStatusChangeEvent> listener() {
        return new StateMachineListenerAdapter<>() {
            @Override
            public void stateChanged(State<OrderStatus, OrderStatusChangeEvent> from, State<OrderStatus, OrderStatusChangeEvent> to) {
                System.out.println("State change to " + to.getId());
            }
        };
    }

    /**
     * 配置状态
     * @param states
     * @throws Exception
     */
    @Override
    public void configure(StateMachineStateConfigurer<OrderStatus, OrderStatusChangeEvent> states) throws Exception {
        states
                .withStates()
                .initial(OrderStatus.WAIT_PAYMENT)
                .states(EnumSet.allOf(OrderStatus.class));
    }

    /**
     * 配置状态转换事件关系
     * @param transitions
     * @throws Exception
     */
    @Override
    public void configure(StateMachineTransitionConfigurer<OrderStatus, OrderStatusChangeEvent> transitions) throws Exception {
        transitions
                .withExternal().source(OrderStatus.WAIT_PAYMENT).target(OrderStatus.WAIT_TAKING)
                .event(OrderStatusChangeEvent.PAYED)
                .and()
                .withExternal().source(OrderStatus.WAIT_TAKING).target(OrderStatus.WAIT_DELIVER)
                .event(OrderStatusChangeEvent.TAKING)
                .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)
                // 消费者取消
                .source(OrderStatus.WAIT_PAYMENT)
                .target(OrderStatus.CONSUMER_CANCEL)
                .event(OrderStatusChangeEvent.CANCEL)
                .and().withExternal()
                .source(OrderStatus.WAIT_TAKING)
                .target(OrderStatus.CONSUMER_CANCEL)
                .event(OrderStatusChangeEvent.CANCEL)
                .and().withExternal()
                .source(OrderStatus.WAIT_DELIVER)
                .target(OrderStatus.CONSUMER_CANCEL)
                .event(OrderStatusChangeEvent.CANCEL)
                .and().withExternal()
                .source(OrderStatus.WAIT_RECEIVE)
                .target(OrderStatus.CONSUMER_CANCEL)
                .event(OrderStatusChangeEvent.CANCEL)
                // 商家取消
                .and().withExternal()
                .source(OrderStatus.WAIT_TAKING)
                .target(OrderStatus.SHOP_CANCEL)
                .event(OrderStatusChangeEvent.UNTAKING)
                // 消费者退款
                .and().withExternal()
                .source(OrderStatus.FINISH)
                .target(OrderStatus.REFUND)
                .event(OrderStatusChangeEvent.REFUND);
    }

    /**
     * 持久化配置
     * 在实际使用中,可以配合Redis等进行持久化操作
     * @return
     */
    @Bean
    public DefaultStateMachinePersister persister(){
        return new DefaultStateMachinePersister<>(new StateMachinePersist<Object, Object, OrderInfo>() {

            @Override
            public void write(StateMachineContext<Object, Object> context, OrderInfo order) throws Exception {
                //此处并没有进行持久化操作
            }

            @Override
            public StateMachineContext<Object, Object> read(OrderInfo order) throws Exception {
                //此处直接获取Order中的状态,其实并没有进行持久化读取操作,通过这一步获取状态
                return new DefaultStateMachineContext<>(OrderStatus.getByKey(order.getStatus()), null, null, null);
            }
        });
    }
}

5.状态转变监听类

@Component("orderStateListener")
@WithStateMachine(name = "orderStateMachine")
@Slf4j
public class OrderStateListenerImpl{
    /**
     * 订单基本信息数据库操作
     */
    @Autowired
    private OrderInfoMapper orderInfoMapper;

    /**
     * 订单状态数据库操作
     */
    @Autowired
    private OrderStatusMapper orderStatusMapper;

    /**
     * 支付
     * @param message
     * @return
     */
    @OnTransition(source = "WAIT_PAYMENT", target = "WAIT_TAKING")
    public boolean payTransition(Message<OrderStatusChangeEvent> message) {
        OrderInfo order = (OrderInfo) message.getHeaders().get("order");
        try {
            // 修改状态
            order.setStatus(OrderStatus.WAIT_TAKING.getValue());
            orderInfoMapper.updateById(order);
            // 保存订单状态流转信息
            OrderStatusDomain orderStatus = new OrderStatusDomain();
            orderStatus.setStatus(OrderStatus.WAIT_TAKING.getValue());
            orderStatus.setName("消费者支付");
            orderStatus.setStatusTime(LocalDateTime.now());
            orderStatus.setOrderId(order.getId());
            orderStatusMapper.insert(orderStatus);
            System.out.println("支付,状态机反馈信息:" + message.getHeaders().toString());
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 商家接单
     * @param message
     * @return
     */
    @OnTransition(source = "WAIT_TAKING", target = "WAIT_DELIVER")
    public boolean takingTransition(Message<OrderStatusChangeEvent> message) {
        OrderInfo order = (OrderInfo) message.getHeaders().get("order");
        try {
            // 分配给附近骑手
            order.setRiderId("1");
            // 修改状态
            order.setStatus(OrderStatus.WAIT_DELIVER.getValue());
            orderInfoMapper.updateById(order);
            // 保存订单状态流转信息
            OrderStatusDomain orderStatus = new OrderStatusDomain();
            orderStatus.setStatus(OrderStatus.WAIT_DELIVER.getValue());
            orderStatus.setName("商家接单");
            orderStatus.setStatusTime(LocalDateTime.now());
            orderStatus.setOrderId(order.getId());
            orderStatusMapper.insert(orderStatus);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    @OnTransition(source = "WAIT_DELIVER", target = "WAIT_RECEIVE")
    public boolean deliverTransition(Message<OrderStatusChangeEvent> message) {
        OrderInfo order = (OrderInfo) message.getHeaders().get("order");
        try {
            // 修改状态

            order.setStatus(OrderStatus.WAIT_RECEIVE.getValue());
            orderInfoMapper.updateById(order);
            // 保存订单状态流转信息
            OrderStatusDomain orderStatus = new OrderStatusDomain();
            orderStatus.setStatus(OrderStatus.WAIT_RECEIVE.getValue());
            orderStatus.setName("骑手配送");
            orderStatus.setStatusTime(LocalDateTime.now());
            orderStatus.setOrderId(order.getId());
            orderStatusMapper.insert(orderStatus);
            System.out.println("支付,状态机反馈信息:" + message.getHeaders().toString());
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    @OnTransition(source = "WAIT_RECEIVE", target = "FINISH")
    public boolean receiveTransition(Message<OrderStatusChangeEvent> message){
        OrderInfo order = (OrderInfo) message.getHeaders().get("order");
        try {
            // 修改状态
            order.setStatus(OrderStatus.FINISH.getValue());
            orderInfoMapper.updateById(order);
            // 保存订单状态流转信息
            OrderStatusDomain orderStatus = new OrderStatusDomain();
            orderStatus.setStatus(OrderStatus.FINISH.getValue());
            orderStatus.setName("消费者收货");
            orderStatus.setStatusTime(LocalDateTime.now());
            orderStatus.setOrderId(order.getId());
            orderStatusMapper.insert(orderStatus);
            System.out.println("支付,状态机反馈信息:" + message.getHeaders().toString());
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    @OnTransition(source = "WAIT_TAKING", target = "SHOP_CANCEL")
    public boolean untakingTransition(Message<OrderStatusChangeEvent> message){
        OrderInfo order = (OrderInfo) message.getHeaders().get("order");
        try {
            // 修改状态
            order.setStatus(OrderStatus.SHOP_CANCEL.getValue());
            orderInfoMapper.updateById(order);
            // 保存订单状态流转信息
            OrderStatusDomain orderStatus = new OrderStatusDomain();
            orderStatus.setStatus(OrderStatus.SHOP_CANCEL.getValue());
            orderStatus.setName("商家拒绝接单");
            orderStatus.setStatusTime(LocalDateTime.now());
            orderStatus.setOrderId(order.getId());
            orderStatusMapper.insert(orderStatus);
            System.out.println("支付,状态机反馈信息:" + message.getHeaders().toString());
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    @OnTransition(source = {"WAIT_PAYMENT","WAIT_TAKING","WAIT_DELIVER","WAIT_RECEIVE"},target = "CONSUMER_CANCEL")
    public boolean cancelTransition(Message<OrderStatusChangeEvent> message){
        OrderInfo order = (OrderInfo) message.getHeaders().get("order");
        try {
            // 修改状态
            order.setStatus(OrderStatus.CONSUMER_CANCEL.getValue());
            orderInfoMapper.updateById(order);
            // 保存订单状态流转信息
            OrderStatusDomain orderStatus = new OrderStatusDomain();
            orderStatus.setStatus(OrderStatus.CONSUMER_CANCEL.getValue());
            orderStatus.setName("消费者取消订单");
            orderStatus.setStatusTime(LocalDateTime.now());
            orderStatus.setOrderId(order.getId());
            orderStatusMapper.insert(orderStatus);
            System.out.println("支付,状态机反馈信息:" + message.getHeaders().toString());
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    @OnTransition(source = "FINISH",target = "REFUND")
    public boolean refundTransition(Message<OrderStatusChangeEvent> message){
        OrderInfo order = (OrderInfo) message.getHeaders().get("order");
        try {
            // 修改状态
            order.setStatus(OrderStatus.REFUND.getValue());
            orderInfoMapper.updateById(order);
            // 保存订单状态流转信息
            OrderStatusDomain orderStatus = new OrderStatusDomain();
            orderStatus.setStatus(OrderStatus.REFUND.getValue());
            orderStatus.setName("消费者退款");
            orderStatus.setStatusTime(LocalDateTime.now());
            orderStatus.setOrderId(order.getId());
            orderStatusMapper.insert(orderStatus);
            System.out.println("支付,状态机反馈信息:" + message.getHeaders().toString());
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
}

6.service类

public interface OrderStateService {

    //发起支付
    Boolean pay(OrderInfo orderInfo);

    Boolean taking(OrderInfo orderInfo) throws Exception;

    //订单发货
    Boolean deliver(OrderInfo orderInfo);

    //订单收货
    Boolean receive(OrderInfo orderInfo);
    Boolean orderUntaking(OrderInfo orderInfo);
    Boolean orderCancel(OrderInfo orderInfo);
    Boolean orderRefund(OrderInfo orderInfo);
    
}

7.serviceImpl类

@Service
public class OrderStateServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderStateService {

    @Resource
    private StateMachine<OrderStatus, OrderStatusChangeEvent> orderStateMachine;

    @Autowired
    private StateMachinePersister<OrderStatus, OrderStatusChangeEvent, OrderInfo> persister;

    /**
     * 发送订单支付事件
     */
    @Override
    public Boolean pay(OrderInfo orderInfo) {
        // 获得订单信息
        System.out.println("线程名称:" + Thread.currentThread().getName() + " 尝试支付,订单号:" + orderInfo.getId());
        // 发送支付事件
        Boolean result = sendEvent(OrderStatusChangeEvent.PAYED, orderInfo);
        if (!result) {
            System.out.println("线程名称:" + Thread.currentThread().getName() + " 接单失败, 状态异常,订单号:" + orderInfo.getId());
        }
        return result;
    }

    /**
     * 商家接单
     * @param order
     * @return
     */
    @Override
    public Boolean taking(OrderInfo order) throws Exception {
        System.out.println("线程名称:" + Thread.currentThread().getName() + " 尝试商家接单,订单号:" + order.getId());
        // 发送接单事件
        Boolean result = sendEvent(OrderStatusChangeEvent.TAKING, order);
        if (!result) {
            System.out.println("线程名称:" + Thread.currentThread().getName() + " 接单失败, 状态异常,订单号:" + order.getId());
        }
        return result;
    }

    /**
     * 骑手配送
     * @param order
     * @return
     */
    @Override
    public Boolean deliver(OrderInfo order) {
        System.out.println("线程名称:" + Thread.currentThread().getName() + " 尝试发货,订单号:" + order.getId());
        Boolean result = sendEvent(OrderStatusChangeEvent.DELIVERY, order);
        if (!result) {
            System.out.println("线程名称:" + Thread.currentThread().getName() + " 接单失败, 状态异常,订单号:" + order.getId());
        }
        return result;
    }

    @Override
    public Boolean receive(OrderInfo order) {
        System.out.println("线程名称:" + Thread.currentThread().getName() + " 尝试收货,订单号:" +  order.getId());
        Boolean result = sendEvent(OrderStatusChangeEvent.RECEIVED, order);
        if (!result) {
            System.out.println("线程名称:" + Thread.currentThread().getName() + " 接单失败, 状态异常,订单号:" + order.getId());
        }
        return result;
    }

    @Override
    public Boolean orderUntaking(OrderInfo order) {
        System.out.println("线程名称:" + Thread.currentThread().getName() + " 尝试收货,订单号:" +  order.getId());
        Boolean result = sendEvent(OrderStatusChangeEvent.UNTAKING, order);
        if (!result) {
            System.out.println("线程名称:" + Thread.currentThread().getName() + " 接单失败, 状态异常,订单号:" + order.getId());
        }
        return result;
    }

    @Override
    public Boolean orderCancel(OrderInfo order) {
        System.out.println("线程名称:" + Thread.currentThread().getName() + " 尝试收货,订单号:" +  order.getId());
        Boolean result = sendEvent(OrderStatusChangeEvent.CANCEL, order);
        if (!result) {
            System.out.println("线程名称:" + Thread.currentThread().getName() + " 接单失败, 状态异常,订单号:" + order.getId());
        }
        return result;
    }

    @Override
    public Boolean orderRefund(OrderInfo order) {
        System.out.println("线程名称:" + Thread.currentThread().getName() + " 尝试收货,订单号:" +  order.getId());
        Boolean result = sendEvent(OrderStatusChangeEvent.REFUND, order);
        if (!result) {
            System.out.println("线程名称:" + Thread.currentThread().getName() + " 接单失败, 状态异常,订单号:" + order.getId());
        }
        return result;
    }

    /**
     * 发送订单状态转换事件
     *
     * @param event
     * @param order
     * @return
     */
    private synchronized boolean sendEvent(OrderStatusChangeEvent event, OrderInfo order) {
        boolean result = false;
        Message<OrderStatusChangeEvent>  message = MessageBuilder.withPayload(event).
                setHeader("order", order).build();
        try {
            orderStateMachine.start();
//            //尝试恢复状态机状态
            persister.restore(orderStateMachine, order);
            //添加延迟用于线程安全测试
//            Thread.sleep(1000);
            result = orderStateMachine.sendEvent(message);
            //持久化状态机状态
            persister.persist(orderStateMachine, order);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            orderStateMachine.stop();
        }
        return result;
    }
}