Spring State Machine状态机的简单使用

🖐🏻 免责声明

本教程仅供学习交流使用,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,请各读者自觉遵守相关法律法规。

# Spring State Machine关键功能

  1. 状态 (State):定义系统可以存在的各个状态,如订单的不同阶段(待支付、已支付、已发货、已完成等)。
  2. 事件(Event):触发状态变迁的动作或条件,如用户点击“支付”按钮引发的支付事件。
  3. 转换(Transition):定义了在特定状态下接收到特定事件时,如何从一个状态迁移到另一个状态。
  4. 动作(Action):可以在状态变迁前后执行的操作,如状态切换时更新数据库记录、发送通知邮件等。

在实际应用场景中,Spring State Machine 可以有效地应用于工作流引擎、订单处理流程、游戏逻辑、设备控制等多种领域帮助开发者更好地管理和抽象复杂的业务流程和状态变化。

# 应用场景

Spring 状态机(Spring state Machine)作为一种强大的状态管理和转换工具,在多个领域有着广泛的应用场景,以下列举了 几个典型示例:

  1. 订单生命周期管理:电商应用中,订单状态可能从创建、支付、发货、确认收货直至完成或取消等多个状态变化,通过状态机可以清晰地定义并控制这些状态之间的合法转换过程,同时在状态变迁时触发相应的操作,如发送邮件通知、更新库存等。
  2. 工作流引擎:在企业级应用中,工作流(如请假审批流程、报销流程等)通常具有多个步骤和决策点,状态机可以用来描述每个步骤之间的关系及转换条件,确保流程按照预设规则进行。
  3. 游戏逻辑:游戏开发中,游戏角色、游戏关卡、战斗场景等都有各自的状态,状态机可用于实现角色的不同行动模式切 换、关卡过关条件判断、战斗状态循环等复杂逻辑。
  4. 设备状态监控:物联网(10T)应用中,对设备运行状态进行实时跟踪和管理时,可以根据设备接收到的各种信号或指令触发状态转变,如设备开机、待机、运行、故障、维修等状态。
  5. 会话管理:Web应用中,用户的会话状态(登录、登出、活跃、超时等)可以通过状态机进行有效管理,简化会话状态相关的复杂业务逻辑。
  6. 权限控制:在安全性要求较高的系统中,用户权限可能会随着其操作行为和系统状态发生变化,状态机可以精确地表达权限状态的变化过程。
  7. 微服务架构中的事务一致性:在涉及多个微服务协作且需要保证事务一致性的场景中,可以通过状态机来协调各个服务的状态转移,确保整个业务流程的一致性。

# 使用

# 引入依赖

<dependency>
    <groupId>org.springframework.statemachine</groupId>
    <artifactId>spring-statemachine-starter</artifactId>
    <version>4.0.0</version>
</dependency>

# 创建订单实体

public class Order {
    // 仅保留状态字段
    private OrderStatus status;
}

# 创建状态enum

public enum OrderStatus {
    INIT,PAYED,SHIPPED,RECEIVED
}

# 创建事件enum

public enum OrderEvent {
    PAY,SHIPPING,RECEIVE
}

# 创建状态转换

@Configuration
@EnableStateMachine(name = "orderStateMachine")
public class OrderStateMachineConfig extends StateMachineConfigurerAdapter<OrderStatus, OrderEvent> {

    // 配置初始状态
    public void configure(StateMachineStateConfigurer<OrderStatus, OrderEvent> states) throws Exception {
        states.withStates()
                .initial(OrderStatus.INIT)
                .states(EnumSet.allOf(OrderStatus.class));
    }
    
    // 状态转换的事件关系
    public void configure(StateMachineTransitionConfigurer<OrderStatus, OrderEvent> transitions) throws Exception {
        transitions
        .withExternal().source(OrderStatus.INIT).target(OrderStatus.PAYED).event(OrderEvent.PAY)
        .and()
        .withExternal().source(OrderStatus.PAYED).target(OrderStatus.SHIPPED).event(OrderEvent.SHIPPING)
        .and()
        .withExternal().source(OrderStatus.SHIPPED).target(OrderStatus.RECEIVED).event(OrderEvent.RECEIVE);
    }
    
    // 持久化配置
    @bean
    public DefaultStateMachinePersist persister() {
        return new DefaultStateMachinePersist<>(
            new StateMachinePersist<Object, Object, Order>(){
                @Override
                public void write(StateMachineContext<Object, Object> context, Order order) throws Exception {
                // 此处并没有进行持久化
                }
                @Override
                public void read(StateMachineContext<Object, Object> context, Order order) throws Exception {
                // 直接获取订单状态,其实没有进行持久化
                    return new DeafaultStateMachineContext<>(order.getStatus(), null, null, null, null);
                }
            }    
        ) {
    }
    }
}

# 创建状态转换监听器

@Component("orderStateListener")
@WithStateMachine(name = "orderStateMachine")
public class OrderStateListener{
    @OnTransition(source = "INIT",target = "PAYED")
    public boolean pay(Message<OrderEvent> message){
        Order order = (Order) message.getHeaders().get("order");
        // 对订单做一些操作
        return true;
    }
    
    @OnTransition(source = "PAYED",target = "SHIPPED")
    public boolean shipping(Message<OrderEvent> message){
        Order order = (Order) message.getHeaders().get("order");
        // 对订单做一些操作
        return true;
    }
    
    @OnTransition(source = "SHIPPED",target = "RECEIVED")
    public boolean receive(Message<OrderEvent> message){
        Order order = (Order) message.getHeaders().get("order");
        // 对订单做一些操作
        return true;
    }
}

# 创建状态触犯器

public class OrderProcessor {
    @Resource
    private StateMachine<OrderStatus, OrderEvent> stateMachine;
    
    @Resource
    private StateMachinePersister<OrderStatus, OrderEvent, Order> persister;
    
    public Boolean process(Order order,OrderEvent event){
        Message<OrderEvent> message = MessageBuilder.withPayload(event)
        .setHeader("order",order).build();
        boolean b = sendEvent(message);
        return b;
    }
    
    @SneakyThrows
    private boolean sendEvent(Message<OrderEvents> message) {
        Order order = (Order) message.getHeaders().get("order");
        persister.restore(orderStateMachine,order);
        boolean result == stateMachine.sendEvent(message);
        return result;
    }
}

# 使用

void pay() {
    Order order = new Order(OrderStatus.INIT);
    orderProcessor.process(order,OrderEvents.PAY);
}

去config类找到初始状态为INIT,事件为PAY的配置,看目标状态为PAYED:.withExternal().source(OrderStatus.INIT).target(OrderStatus.PAYED).event(OrderEvent.PAY) 继续找到监听器文件,找到 @OnTransition(source = "INIT",target = "PAYED"),这里会执行数据库变更的一些操作,即业务逻辑,至此,状态机使命完成。

# ☕ 请我喝咖啡

如果本文章对您有所帮助,不妨请作者我喝杯咖啡 :)

pay


# ☀️ 广告时间

现承接以下业务,欢迎大家支持:)

  • Web 2.0 & Web 3.0应用定制
  • Web 3.0专项脚本定制与优化
  • 数据爬虫需求快速响应
  • 网站/公众号/小程序一站式开发
  • 毕业设计与科研项目支持
  • 企业管理软件定制:ERP, MES, CRM, 进销存系统等

联系方式:

X:@motuoka

V:ck742931485

wx