Spring状态机

发布于:2025-06-10 ⋅ 阅读:(27) ⋅ 点赞:(0)

if-else实现状态机

public class BasketballMusicSateMachineUsingIfElse{
	
	private boolean isPlayingMusic;

	public BasketballMusicSateMachineUsingIfElse(){
		this.isPlayMusic = false;//初始状态为音乐未播放
	}

	public void playMusic(){
		
		if(!isPlayingMusic){
			System.out.println("Music starts playing...");
			ifPlayingMusic = true;
		}
	}

	public void stopMusic(){
		if(isPlayingMusic){
			System.out.println("Music stops playing...");
			isPlayingMusic = false;
		}
	} 

	public void performActivity(String activity){
		if ("basketball".equals(activity)) {
            System.out.println("Music~");
            playMusic(); // 打篮球时播放音乐
        } else if ("sing_rap".equals(activity)) {
            System.out.println("哎哟你干嘛!");
            stopMusic(); // 唱跳Rap时停止音乐
        } else {
            System.out.println("Invalid activity!");
        }
	}

	public static void main(String[] args) {
        BasketballMusicStateMachineUsingIfElse stateMachine = new BasketballMusicStateMachineUsingIfElse();

        // 测试状态机
        stateMachine.performActivity("basketball"); // 打篮球,音乐开始播放
        stateMachine.performActivity("sing_rap"); // 唱跳Rap,音乐停止播放
        stateMachine.performActivity("basketball"); // 再次打篮球,音乐重新开始播放
    }
}

和状态机的对比

①、引入依赖

spring-statemachine-core

②、定义状态、事件

public enum States {
    IDLE,       // 空闲状态
    PLAYING_BB, // 打篮球状态
    SINGING     // 唱跳Rap状态
}
public enum Event {
    START_BB_MUSIC, // 开始播放篮球音乐事件
    STOP_BB_MUSIC   // 停止篮球音乐事件
}

③、配置状态机

@Configuration
@EnableStateMachine
public class BasketballMusicStateMachineConfig extends EnumStateMachineConfigurerAdapter<States, Event> {

    @Autowired
    private BasketballMusicStateMachineEventListener eventListener;

    @Override
    public void configure(StateMachineConfigurationConfigurer<States, Event> config) throws Exception {
        config
            .withConfiguration()
            .autoStartup(true)
            .listener(eventListener); // 设置状态机事件监听器
    }

    @Override
    public void configure(StateMachineStateConfigurer<States, Event> states) throws Exception {
        states
            .withStates()
            .initial(States.IDLE)
            .states(EnumSet.allOf(States.class));
    }

    @Override
    public void configure(StateMachineTransitionConfigurer<States, Event> transitions) throws Exception {
        transitions
            .withExternal()
            .source(States.IDLE).target(States.PLAYING_BB).event(Event.START_BB_MUSIC)
            .and()
            .withExternal()
            .source(States.PLAYING_BB).target(States.SINGING).event(Event.STOP_BB_MUSIC)
            .and()
            .withExternal()
            .source(States.SINGING).target(States.PLAYING_BB).event(Event.START_BB_MUSIC);
    }
}

④、监听器

@Component
public class BasketballMusicStateMachineEventListener extends StateMachineListenerAdapter<States, Event> {

    @Override
    public void stateChanged(State<States, Event> from, State<States, Event> to) {
        if (from.getId() == States.IDLE && to.getId() == States.PLAYING_BB) {
            System.out.println("开始打篮球,music 起");
        } else if (from.getId() == States.PLAYING_BB && to.getId() == States.SINGING) {
            System.out.println("唱跳,你干嘛");
        } else if (from.getId() == States.SINGING && to.getId() == States.PLAYING_BB) {
            System.out.println("继续打篮球,music 继续");
        }
    }
}

⑤、单元测试

@SpringBootTest
class ChatApplicationTests {
    @Resource
    private StateMachine<States, Event> stateMachine;

    @Test
    void contextLoads() {
        //开始打球,music 起
        stateMachine.sendEvent(Event.START_BB_MUSIC);
  //开始唱跳,你干嘛
        stateMachine.sendEvent(Event.STOP_BB_MUSIC);
  //继续打球,music 继续
        stateMachine.sendEvent(Event.START_BB_MUSIC);

    }
}

在这里插入图片描述

==================================================

案例一:

①、依赖

spring-statemachine-core

②、模拟订单类

@Data
public class Order {
    private Long orderId;
    private OrderStatusEnum orderStatus;
}
//订单状态转换
public enum OrderStatusEnum {
    // 待支付
    WAIT_PAYMENT,
    // 待发货
    WAIT_DELIVER,
    // 待收货
    WAIT_RECEIVE,
    // 完成
    FINISH;
}
//订单状态
public enum OrderStatusChangeEventEnum {
    //支付
    PAYED,
    //发货
    DELIVERY,
    //收货
    RECEIVED;
}

③、构造订单状态机

@Configuration
@EnableStateMachine
public class OrderStatusMachineConfig extends StateMachineConfigurerAdapter<OrderStatusEnum, OrderStatusChangeEventEnum> {

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

    /**
     * 配置状态转换事件关系
     */
    @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);
    }
}

④、状态机监听器

监听状态变更事件,完成状态转换

@Component
@WithStateMachine
@Transactional
public class OrderStatusListener {
    @OnTransition(source = "WAIT_PAYMENT", target = "WAIT_DELIVER")
    public boolean payTransition(Message message) {
        Order order = (Order) message.getHeaders().get("order");
        order.setOrderStatus(OrderStatusEnum.WAIT_DELIVER);
        System.out.println("支付,状态机反馈信息:" + message.getHeaders().toString());
        return true;
    }

    @OnTransition(source = "WAIT_DELIVER", target = "WAIT_RECEIVE")
    public boolean deliverTransition(Message message) {
        Order order = (Order) message.getHeaders().get("order");
        order.setOrderStatus(OrderStatusEnum.WAIT_RECEIVE);
        System.out.println("发货,状态机反馈信息:" + message.getHeaders().toString());
        return true;
    }

    @OnTransition(source = "WAIT_RECEIVE", target = "FINISH")
    public boolean receiveTransition(Message message) {
        Order order = (Order) message.getHeaders().get("order");
        order.setOrderStatus(OrderStatusEnum.FINISH);
        System.out.println("收货,状态机反馈信息:" + message.getHeaders().toString());
        return true;
    }

}

⑤、编写订单服务类

@Service
public class OrderServiceImpl implements OrderService {

    @Resource
    private StateMachine<OrderStatusEnum, OrderStatusChangeEventEnum> orderStateMachine;

    private long id = 1L;

    private Map<Long, Order> orders = Maps.newConcurrentMap();

    @Override
    public Order create() {
        Order order = new Order();
        order.setOrderStatus(OrderStatusEnum.WAIT_PAYMENT);
        order.setOrderId(id++);
        orders.put(order.getOrderId(), order);
        System.out.println("订单创建成功:" + order.toString());
        return order;
    }

    @Override
    public Order pay(long id) {
        Order order = orders.get(id);
        System.out.println("尝试支付,订单号:" + id);
        Message message = MessageBuilder.withPayload(OrderStatusChangeEventEnum.PAYED).
                setHeader("order", order).build();
        if (!sendEvent(message)) {
            System.out.println(" 支付失败, 状态异常,订单号:" + id);
        }
        return orders.get(id);
    }

    @Override
    public Order deliver(long id) {
        Order order = orders.get(id);
        System.out.println(" 尝试发货,订单号:" + id);
        if (!sendEvent(MessageBuilder.withPayload(OrderStatusChangeEventEnum.DELIVERY)
                .setHeader("order", order).build())) {
            System.out.println(" 发货失败,状态异常,订单号:" + id);
        }
        return orders.get(id);
    }

    @Override
    public Order receive(long id) {
        Order order = orders.get(id);
        System.out.println(" 尝试收货,订单号:" + id);
        if (!sendEvent(MessageBuilder.withPayload(OrderStatusChangeEventEnum.RECEIVED)
                .setHeader("order", order).build())) {
            System.out.println(" 收货失败,状态异常,订单号:" + id);
        }
        return orders.get(id);
    }


    @Override
    public Map<Long, Order> getOrders() {
        return orders;
    }

    /**
     * 发送状态转换事件
     * @param message
     * @return
     */
    private synchronized boolean sendEvent(Message<OrderStatusChangeEventEnum> message) {
        boolean result = false;
        try {
            orderStateMachine.start();
            result = orderStateMachine.sendEvent(message);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (Objects.nonNull(message)) {
                Order order = (Order) message.getHeaders().get("order");
                if (Objects.nonNull(order) && Objects.equals(order.getOrderStatus(), OrderStatusEnum.FINISH)) {
                    orderStateMachine.stop();
                }
            }
        }
        return result;
    }
}

⑥、测试入口

@RestController
public class OrderController {

    @Resource
    private OrderService orderService;

    @RequestMapping("/testOrderStatusChange")
    public String testOrderStatusChange(){
        orderService.create();
        orderService.create();
        orderService.pay(1L);
        orderService.deliver(1L);
        orderService.receive(1L);
        orderService.pay(2L);
        orderService.deliver(2L);
        orderService.receive(2L);
        System.out.println("全部订单状态:" + orderService.getOrders());
        return "success";
    }

}

在这里插入图片描述

拓展:

消息队列方式
订单状态的流转可以通过 MQ 发布一个事件,消费者根据业务条件把订单状态进行流转,可以根据不同的事件发送到不同的 Topic。

定时任务驱动
每隔一段时间启动一下 job,根据特定的状态从数据库中拿对应的订单记录,然后判断订单是否有条件到达下一个状态。

规则引擎方式
业务团队可以在规则引擎里编写一系列的状态及其对应的转换规则,由规则引擎根据已经加载的规则对输入数据进行解析,根据解析的结果执行相应的动作,完成状态流转。

===============================================================

案例二

①、引入依赖

spring-statemachine-starter

②、定义状态和事件

public enum OrderStates {
    NEW, PAID, SHIPPED, COMPLETED, CANCELLED
}
 
public enum OrderEvents {
    PAY, SHIP, COMPLETE, CANCEL
}

③、配置状态机

@Configuration
@EnableStateMachine
public class StateMachineConfig extends StateMachineConfigurerAdapter<OrderStates, OrderEvents> {
 
    private static final Logger log = LoggerFactory.getLogger(StateMachineConfig.class);
 
    @Override
    public void configure(StateMachineConfigurationConfigurer<OrderStates, OrderEvents> config)
            throws Exception {
        config
                .withConfiguration()
                .autoStartup(true)
                .listener(listener());
    }
 
    @Override
    public void configure(StateMachineStateConfigurer<OrderStates, OrderEvents> states)
            throws Exception {
        states
                .withStates()
                .initial(OrderStates.NEW)
                .end(OrderStates.COMPLETED)
                .end(OrderStates.CANCELLED)
                .states(EnumSet.allOf(OrderStates.class));
    }
 
    @Override
    public void configure(StateMachineTransitionConfigurer<OrderStates, OrderEvents> transitions) throws Exception {
        transitions
                .withExternal()
                .source(OrderStates.NEW).target(OrderStates.PAID).event(OrderEvents.PAY)
                .and()
                .withExternal()
                .source(OrderStates.PAID).target(OrderStates.SHIPPED).event(OrderEvents.SHIP)
                .and()
                .withExternal()
                .source(OrderStates.SHIPPED).target(OrderStates.COMPLETED).event(OrderEvents.COMPLETE)
                .and()
                .withExternal()
                .source(OrderStates.NEW).target(OrderStates.CANCELLED).event(OrderEvents.CANCEL)
                .and()
                .withExternal()
                .source(OrderStates.PAID).target(OrderStates.CANCELLED).event(OrderEvents.CANCEL);
    }
 
    @Bean
    public StateMachineListener<OrderStates, OrderEvents> listener() {
        return new StateMachineListenerAdapter<>() {
            @Override
            public void stateChanged(State<OrderStates, OrderEvents> from, State<OrderStates, OrderEvents> to) {
                log.info("State change to: {}", to.getId());
            }
 
            @Override
            public void stateMachineError(StateMachine<OrderStates, OrderEvents> stateMachine, Exception exception) {
                log.error("Exception caught: {}", exception.getMessage(), exception);
            }
 
            @Override
            public void eventNotAccepted(Message<OrderEvents> message) {
                Order order = (Order) message.getHeaders().get("order");
                log.error("Order state machine can't change state {} --> {}", Objects.requireNonNull(order).getStatus(), message.getPayload());
            }
        };
    }
 
    @Bean
    public StateMachinePersist<OrderStates, OrderEvents, String> inMemoryStateMachinePersist() {
        return new StateMachinePersist<>() {
            private final Map<String, StateMachineContext<OrderStates, OrderEvents>> contexts = new HashMap<>();
 
            @Override
            public void write(StateMachineContext<OrderStates, OrderEvents> context, String contextObj) {
                contexts.put(contextObj, context);
            }
 
            @Override
            public StateMachineContext<OrderStates, OrderEvents> read(String contextObj) {
                return contexts.get(contextObj);
            }
        };
    }
}

④、配置状态改变后的处理器

使用@WithStateMachine来配置状态机流转后的后续逻辑,比如更新订单状态、发邮件等。

@Service
@WithStateMachine
public class OrderStateChangeHandler {
 
    private static final Logger log = LoggerFactory.getLogger(OrderStateChangeHandler.class);
 
    @OnTransition(source = "NEW", target = "PAID")
    public void payTransition(Message<OrderEvents> message) {
        Order order = (Order) message.getHeaders().get("order");
        log.info("Handle Pay Order:{}", order);
        // 其他业务 如保存订单状态
        Objects.requireNonNull(order).setStatus(OrderStates.PAID);
        //orderRepository.save(order);
 
    }
 
    @OnTransition(source = "PAID", target = "SHIPPED")
    public void shipTransition(Message<OrderEvents> message) {
        Order order = (Order) message.getHeaders().get("order");
        log.info("Handle Ship Order:{}", order);
        // 其他业务 如更新订单
        Objects.requireNonNull(order).setStatus(OrderStates.SHIPPED);
//        orderMapper.updateById(order);
    }
    @OnTransition(source = "SHIPPED", target = "COMPLETED")
    public void completeTransition(Message<OrderEvents> message) {
        Order order = (Order) message.getHeaders().get("order");
        log.info("Handle Complete Order:{}", order);
 
        // 其他业务 如更新订单
        Objects.requireNonNull(order).setStatus(OrderStates.COMPLETED);
//        orderMapper.updateById(order);
    }
 
}

⑤、使用状态机控制订单状态流转

@Service
public class OrderService {
 
    private static final Logger log = LoggerFactory.getLogger(OrderService.class);
 
    private final StateMachine<OrderStates, OrderEvents> stateMachine;
 
    public OrderService(StateMachine<OrderStates, OrderEvents> stateMachine) {
        this.stateMachine = stateMachine;
    }
 
    public void payOrder(Integer id) {
        log.info("Pay Order: {}", id);
        Order order = new Order("12345", "Sample Order", OrderStates.NEW, new BigDecimal("99.99"));
        // 模拟支付
//        payService.payOrder(1);
        Message<OrderEvents> message = MessageBuilder.withPayload(OrderEvents.PAY).setHeader("order", order).build();
        stateMachine.sendEvent(Mono.just(message)).subscribe();
    }
 
    public void shipOrder(Integer id) {
        log.info("Ship Order: {}", id);
        Order order = new Order("12345", "Sample Order", OrderStates.PAID, new BigDecimal("99.99"));
        // 模拟发货
//        tradeService.shipOrder(1);
        Message<OrderEvents> message = MessageBuilder.withPayload(OrderEvents.SHIP).setHeader("order", order).build();
        stateMachine.sendEvent(Mono.just(message)).subscribe();
    }
 
    public void completeOrder(Integer id) {
        log.info("Complete Order: {}", id);
        Order order = new Order("12345", "Sample Order", OrderStates.SHIPPED, new BigDecimal("99.99"));
 
        Message<OrderEvents> message = MessageBuilder.withPayload(OrderEvents.COMPLETE).setHeader("order", order).build();
        stateMachine.sendEvent(Mono.just(message)).subscribe();
    }
 
}

⑥、控制订单流转

@GetMapping("/order/pay/{id}")
public String payOrder(@PathVariable("id") Integer id) {
     orderService.payOrder(id);
     return "Order paid ";
}
 
@GetMapping("/order/ship/{id}")
public String shipOrder(@PathVariable("id") Integer id) {
    orderService.shipOrder(id);
    return "Order shipped ";
}
 
@GetMapping("/order/complete/{id}")
 public String completeOrder(@PathVariable("id") Integer id) {
    orderService.completeOrder(id);
    return "Order completed ";
}

测试:

1.NEW --> SHIPPED
因为我们配置的订单流转规则中,NEW只能转换到PAID或CANCELLED,所以我们期望的是订单不能流转成功。

在浏览器中访问:http://localhost:8082/order/ship/1

控制台中打印如下错误信息,并且处理器中业务未执行,和我们的预期一致。

  1. NEW --> COMPLETE
    同上面一样,期望是会出现错误,不能转换成功。访问:http://localhost:8082/order/complete/1

  2. NEW --> PAID
    由于在状态机的配置,NEW是可以转换成PAID的。所以,期望能转换成功。访问:http://localhost:8082/order/pay/1

我们从控制台中可以看到, 订单状态流转成功,并且进入到handler中进行订单流转后的业务处理。这时该订单的状态已经变成PAID。

如果我们在来支付一次,结果会怎么样?

执行一次结果是报错,因为上一次请求,该订单的状态已经流转为了PAID,所以再次流转NEW --> PAY就会报错。

  1. PAID --> SHIPPED
    属于配置允许的状态流转,所以期望能够转换成功。访问:http://localhost:8082/order/ship/1

从控制台中可以看到能够成功流转,因为符合我们配置的状态机流转规则。

同样如果我们再调用一次会怎么样?

和上一步的测试结果一样,因为该订单的状态已经扭转为了SHIPPED,所以它不能再次转换为SHIPPED。

  1. SHIPPED --> COMPLETED
    我们之间访问:http://localhost:8082/order/complete/1

该订单当前状态为SHIPPED,根据配置的规则可以转换为COMPLETED

====================================================================

案例:

在这里插入图片描述

①、导入sql,订单表的创建


CREATE TABLE `tb_order` (
      `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
      `order_code` varchar(128) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '订单编码',
      `status` smallint(3) DEFAULT NULL COMMENT '订单状态',
      `name` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '订单名称',
      `price` decimal(12,2) DEFAULT NULL COMMENT '价格',
      `delete_flag` tinyint(2) NOT NULL DEFAULT '0' COMMENT '删除标记,0未删除  1已删除',
      `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',
      `update_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '更新时间',
      `create_user_code` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '创建人',
      `update_user_code` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '更新人',
      `version` int(11) NOT NULL DEFAULT '0' COMMENT '版本号',
      `remark` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '备注',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='订单表';
    
    /*Data for the table `tb_order` */
    
    insert  into `tb_order`(`id`,`order_code`,`status`,`name`,`price`,`delete_flag`,`create_time`,`update_time`,`create_user_code`,`update_user_code`,`version`,`remark`) values 
    (2,'A111',1,'A','22.00',0,'2022-10-15 16:14:11','2022-10-02 21:29:14','zhangsan','zhangsan',0,NULL),
    (3,'A111',1,'订单A','22.00',0,'2022-10-02 21:53:13','2022-10-02 21:29:14','zhangsan','zhangsan',0,NULL),
    (4,'A111',1,'订单A','22.00',0,'2022-10-02 21:53:13','2022-10-02 21:29:14','zhangsan','zhangsan',0,NULL),
    (5,'A111',1,'订单A','22.00',0,'2022-10-03 09:08:30','2022-10-02 21:29:14','zhangsan','zhangsan',0,NULL);

②、引入依赖

 <!-- redis持久化状态机
	项目中:yml配置文件中进行Redis连接信息的配置
 -->
<dependency>
    <groupId>org.springframework.statemachine</groupId>
    <artifactId>spring-statemachine-redis</artifactId>
    <version>1.2.9.RELEASE</version>
</dependency>
<!--状态机-->
<dependency>
    <groupId>org.springframework.statemachine</groupId>
    <artifactId>spring-statemachine-starter</artifactId>
    <version>2.0.1.RELEASE</version>
</dependency>

③、定义状态机状态和事件

public enum OrderStatus {
    // 待支付,待发货,待收货,已完成
    WAIT_PAYMENT(1, "待支付"),
    WAIT_DELIVER(2, "待发货"),
    WAIT_RECEIVE(3, "待收货"),
    FINISH(4, "已完成");
    private Integer key;
    private String desc;
    OrderStatus(Integer key, String desc) {
        this.key = key;
        this.desc = desc;
    }
    public Integer getKey() {
        return key;
    }
    public String getDesc() {
        return desc;
    }
    public static OrderStatus getByKey(Integer key) {
        for (OrderStatus e : values()) {
            if (e.getKey().equals(key)) {
                return e;
            }
        }
        throw new RuntimeException("enum not exists.");
    }
}
public enum OrderStatusChangeEvent {
     // 支付,发货,确认收货
     PAYED, DELIVERY, RECEIVED;
}

③、定义状态机规则和配置状态机

@Configuration
@EnableStateMachine(name = "orderStateMachine")
public class OrderStateMachineConfig extends StateMachineConfigurerAdapter<OrderStatus, OrderStatusChangeEvent> {
    /**
     * 配置状态
     *
     * @param states
     * @throws Exception
     */
    public void configure(StateMachineStateConfigurer<OrderStatus, OrderStatusChangeEvent> states) throws Exception {
        states
                .withStates()
                .initial(OrderStatus.WAIT_PAYMENT)
                .states(EnumSet.allOf(OrderStatus.class));
    }
    /**
     * 配置状态转换事件关系
     *
     * @param transitions
     * @throws Exception
     */
    public void configure(StateMachineTransitionConfigurer<OrderStatus, OrderStatusChangeEvent> transitions) throws Exception {
        transitions
                //支付事件:待支付-》待发货
                .withExternal().source(OrderStatus.WAIT_PAYMENT).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);
    }
}

④、配置持久化

@Configuration
@Slf4j
public class Persist<E, S> {
    /**
     * 持久化到内存map中
     *
     * @return
     */
    @Bean(name = "stateMachineMemPersister")
    public static StateMachinePersister getPersister() {
        return new DefaultStateMachinePersister(new StateMachinePersist() {
            @Override
            public void write(StateMachineContext context, Object contextObj) throws Exception {
                log.info("持久化状态机,context:{},contextObj:{}", JSON.toJSONString(context), JSON.toJSONString(contextObj));
                map.put(contextObj, context);
            }
            @Override
            public StateMachineContext read(Object contextObj) throws Exception {
                log.info("获取状态机,contextObj:{}", JSON.toJSONString(contextObj));
                StateMachineContext stateMachineContext = (StateMachineContext) map.get(contextObj);
                log.info("获取状态机结果,stateMachineContext:{}", JSON.toJSONString(stateMachineContext));
                return stateMachineContext;
            }
            private Map map = new HashMap();
        });
    }

    @Resource
    private RedisConnectionFactory redisConnectionFactory;
    /**
     * 持久化到redis中,在分布式系统中使用
     *
     * @return
     */
    @Bean(name = "stateMachineRedisPersister")
    public RedisStateMachinePersister<E, S> getRedisPersister() {
        RedisStateMachineContextRepository<E, S> repository = new RedisStateMachineContextRepository<>(redisConnectionFactory);
        RepositoryStateMachinePersist p = new RepositoryStateMachinePersist<>(repository);
        return new RedisStateMachinePersister<>(p);
    }
}

监听状态的变化:

@Component("orderStateListener")
@WithStateMachine(name = "orderStateMachine")
@Slf4j
public class OrderStateListenerImpl {
    @Resource
    private OrderMapper orderMapper;
    
    @OnTransition(source = "WAIT_PAYMENT", target = "WAIT_DELIVER")
    public void payTransition(Message<OrderStatusChangeEvent> message) {
        Order order = (Order) message.getHeaders().get("order");
        log.info("支付,状态机反馈信息:{}",  message.getHeaders().toString());
        //更新订单
        order.setStatus(OrderStatus.WAIT_DELIVER.getKey());
        orderMapper.updateById(order);
        //TODO 其他业务
    }
    @OnTransition(source = "WAIT_DELIVER", target = "WAIT_RECEIVE")
    public void deliverTransition(Message<OrderStatusChangeEvent> message) {
        Order order = (Order) message.getHeaders().get("order");
        log.info("发货,状态机反馈信息:{}",  message.getHeaders().toString());
        //更新订单
        order.setStatus(OrderStatus.WAIT_RECEIVE.getKey());
        orderMapper.updateById(order);
        //TODO 其他业务
    }
    @OnTransition(source = "WAIT_RECEIVE", target = "FINISH")
    public void receiveTransition(Message<OrderStatusChangeEvent> message) {
        Order order = (Order) message.getHeaders().get("order");
        log.info("确认收货,状态机反馈信息:{}",  message.getHeaders().toString());
        //更新订单
        order.setStatus(OrderStatus.FINISH.getKey());
        orderMapper.updateById(order);
        //TODO 其他业务
    }
}

⑤、业务系统

@Controller
@RequestMapping
public class OrderController{
	
	@Resource
	private OrderService.orderService;

	//根据id查询订单
	@RequestMapping("/getById")
	public Order getById(@RequestParam("id") Long id){
		
		Order order = orderServiceService.getById(id);
		return order;
	}
	
	//创建订单
	public String create(@RequestBody Order order){
		
		orderService.create(order);
		return "success";
	}

	//对订单进行支付
	@RequestMapping("/pay")
	public String pay(@RequestParam("id") Long id){
		
		orderService.pay(id);
		return "success";
	}

	//对订单进行发货
	@RequestMapping("/deliver")
	public String deliver(@RequestParam("id") Long id){
		
		orderService.deliver(id);
		return "success";
	}

	//对订单进行确认收货
	@RequestMapping("receive")
	public String receive(@RequestParam("id") Long id){
		
		orderService.receive(id);
		return "success";
	}
}
@Service
@Slf4j
public class OrerServiceImpl extends ServiceImpl<OrderMapper,Order> implements OrderService {
	
	@Resource
    private StateMachine<OrderStatus, OrderStatusChangeEvent> orderStateMachine;
    
    @Resource
    private StateMachinePersister<OrderStatus, OrderStatusChangeEvent, String> stateMachineMemPersister;
    
    @Resource
    private OrderMapper orderMapper;

	public Order create(Order order) {
        order.setStatus(OrderStatus.WAIT_PAYMENT.getKey());
        orderMapper.insert(order);
        return order;
    }

	public Order pay(Long id) {
	
	    Order order = orderMapper.selectById(id);
	    log.info("线程名称:{},尝试支付,订单号:{}" ,Thread.currentThread().getName() , id);
	    if (!sendEvent(OrderStatusChangeEvent.PAYED, order)) {
	        log.error("线程名称:{},支付失败, 状态异常,订单信息:{}", Thread.currentThread().getName(), order);
	        throw new RuntimeException("支付失败, 订单状态异常");
	    }
	    return order;
	}

	public Order deliver(Long id) {
	
       Order order = orderMapper.selectById(id);
       log.info("线程名称:{},尝试发货,订单号:{}" ,Thread.currentThread().getName() , id);
       if (!sendEvent(OrderStatusChangeEvent.DELIVERY, order)) {
           log.error("线程名称:{},发货失败, 状态异常,订单信息:{}", Thread.currentThread().getName(), order);
           throw new RuntimeException("发货失败, 订单状态异常");
       }
       return order;
   }

	public Order receive(Long id) {
	
      Order order = orderMapper.selectById(id);
      log.info("线程名称:{},尝试收货,订单号:{}" ,Thread.currentThread().getName() , id);
      if (!sendEvent(OrderStatusChangeEvent.RECEIVED, order)) {
          log.error("线程名称:{},收货失败, 状态异常,订单信息:{}", Thread.currentThread().getName(), order);
          throw new RuntimeException("收货失败, 订单状态异常");
      }
      return order;
  }
	
	private synchronized boolean sendEvent(OrderStatusChangeEvent changeEvent, Order order) {
	
            boolean result = false;
            try {
                //启动状态机
                orderStateMachine.start();
                //尝试恢复状态机状态
                stateMachineMemPersister.restore(orderStateMachine, String.valueOf(order.getId()));
                Message message = MessageBuilder.withPayload(changeEvent).setHeader("order", order).build();
                result = orderStateMachine.sendEvent(message);
                //持久化状态机状态
                stateMachineMemPersister.persist(orderStateMachine, String.valueOf(order.getId()));
            } catch (Exception e) {
                log.error("订单操作失败:{}", e);
            } finally {
                orderStateMachine.stop();
            }
            return result;
        }
}

测试:

1)验证业务

新增一个订单
http://localhost:8084/order/create

对订单进行支付
http://localhost:8084/order/pay?id=2

对订单进行发货
http://localhost:8084/order/deliver?id=2

对订单进行确认收货
http://localhost:8084/order/receive?id=2

正常流程结束。如果对一个订单进行支付了,再次进行支付,则会报错:http://localhost:8084/order/pay?id=2

在这里插入图片描述