Spring Statemachine 状态机详解

 更新时间:2025年09月11日 10:52:03   作者:csdn_tom_168  
SpringStatemachine是Spring应用中的状态机框架,支持复杂状态转换,适用于订单系统等场景,核心概念包括状态、事件、转换,提供守卫、动作、并行处理等高级功能,并支持持久化与可视化,本文给大家介绍Spring Statemachine的相关知识,感兴趣的朋友一起看看吧

Spring Statemachine 详解

Spring Statemachine 是一个强大的状态机框架,用于在 Spring 应用中实现复杂的状态转换逻辑。它特别适合管理具有多种状态和转换的业务流程,如订单系统、工作流引擎、设备控制等。

一、核心概念

1. 状态机基本元素

  • 状态(State):系统所处的特定条件
  • 事件(Event):触发状态转换的动作
  • 转换(Transition):状态之间的迁移
  • 守卫(Guard):转换的条件判断
  • 动作(Action):状态转换时执行的业务逻辑

2. 状态类型

  • 初始状态(Initial State):状态机的起点
  • 结束状态(End State):状态机的终点
  • 普通状态(Normal State):常规状态
  • 选择状态(Choice State):基于条件的分支
  • 叉状态(Fork State):并行执行分支
  • 连接状态(Join State):合并并行分支
  • 历史状态(History State):记录并恢复之前状态

二、依赖配置

Maven 依赖

<dependency>
    <groupId>org.springframework.statemachine</groupId>
    <artifactId>spring-statemachine-core</artifactId>
    <version>3.2.0</version>
</dependency>

Gradle 依赖

implementation 'org.springframework.statemachine:spring-statemachine-core:3.2.0'

三、基础配置

1. 定义状态和事件枚举

public enum States {
    SI, // 初始状态
    S1, 
    S2,
    SF  // 最终状态
}
public enum Events {
    E1, 
    E2
}

2. 配置状态机

@Configuration
@EnableStateMachine
public class StateMachineConfig 
        extends EnumStateMachineConfigurerAdapter<States, Events> {
    @Override
    public void configure(StateMachineStateConfigurer<States, Events> states)
            throws Exception {
        states
            .withStates()
            .initial(States.SI)
            .states(EnumSet.allOf(States.class))
            .end(States.SF);
    }
    @Override
    public void configure(StateMachineTransitionConfigurer<States, Events> transitions)
            throws Exception {
        transitions
            .withExternal()
                .source(States.SI)
                .target(States.S1)
                .event(Events.E1)
                .and()
            .withExternal()
                .source(States.S1)
                .target(States.S2)
                .event(Events.E2);
    }
}

四、高级特性

1. 守卫(Guard)实现条件转换

public class MyGuard implements Guard<States, Events> {
    @Override
    public boolean evaluate(StateContext<States, Events> context) {
        // 检查转换条件
        return context.getMessageHeader("key") != null;
    }
}
// 在配置中添加守卫
transitions
    .withExternal()
        .source(States.S1)
        .target(States.S2)
        .event(Events.E2)
        .guard(new MyGuard());

2. 动作(Action)执行业务逻辑

public class MyAction implements Action<States, Events> {
    @Override
    public void execute(StateContext<States, Events> context) {
        // 执行状态转换时的业务逻辑
        System.out.println("Transition action executed");
    }
}
// 在配置中添加动作
transitions
    .withExternal()
        .source(States.SI)
        .target(States.S1)
        .event(Events.E1)
        .action(new MyAction());

3. 层次状态(Hierarchical States)

@Override
public void configure(StateMachineStateConfigurer<States, Events> states)
        throws Exception {
    states
        .withStates()
        .initial(States.SI)
        .state(States.S1)
        .and()
        .withStates()
            .parent(States.S1)
            .initial(States.S11)
            .state(States.S12);
}

4. 并行状态(Fork/Join)

@Override
public void configure(StateMachineStateConfigurer<States, Events> states)
        throws Exception {
    states
        .withStates()
        .initial(States.SI)
        .fork(States.SFORK)
        .join(States.SJOIN)
        .and()
        .withStates()
            .parent(States.SFORK)
            .initial(States.S1)
            .end(States.S1END)
        .and()
        .withStates()
            .parent(States.SFORK)
            .initial(States.S2)
            .end(States.S2END);
}
@Override
public void configure(StateMachineTransitionConfigurer<States, Events> transitions)
        throws Exception {
    transitions
        .withFork()
            .source(States.SFORK)
            .target(States.S1)
            .target(States.S2)
        .and()
        .withJoin()
            .source(States.S1END)
            .source(States.S2END)
            .target(States.SJOIN);
}

5. 状态机监听器

@Component
public class StateMachineListener 
        extends StateMachineListenerAdapter<States, Events> {
    @Override
    public void stateChanged(State<States, Events> from, State<States, Events> to) {
        System.out.println("State changed from " + from + " to " + to);
    }
    @Override
    public void eventNotAccepted(Message<Events> event) {
        System.err.println("Event not accepted: " + event.getPayload());
    }
}

五、持久化状态机

1. 配置持久化仓库

@Bean
public StateMachineRuntimePersister<States, Events, String> stateMachineRuntimePersister() {
    return new JpaStateMachineRuntimePersister<>();
}

2. 启用持久化

@Configuration
@EnableStateMachineFactory
public class PersistConfig 
        extends StateMachineConfigurerAdapter<States, Events> {
    @Autowired
    private StateMachineRuntimePersister<States, Events, String> stateMachineRuntimePersister;
    @Override
    public void configure(StateMachineConfigurationConfigurer<States, Events> config)
            throws Exception {
        config
            .withPersistence()
            .runtimePersister(stateMachineRuntimePersister);
    }
}

3. 保存和恢复状态

// 保存状态
stateMachinePersist.persist(stateMachine, "machineId");
// 恢复状态
StateMachine<States, Events> stateMachine = 
    stateMachineFactory.getStateMachine("machineId");
stateMachinePersist.restore(stateMachine, "machineId");

六、状态机可视化

1. 导出UML状态图

UmlStateMachineModelProducer modelProducer = new UmlStateMachineModelProducer();
Model model = modelProducer.produce(stateMachine.getStateMachineModel());
UmlStateMachineModelConverter converter = new UmlStateMachineModelConverter();
String uml = converter.convertToString(model);
System.out.println(uml);

2. 生成PlantUML图

@startuml
[*] --> SI
SI --> S1 : E1
S1 --> S2 : E2
S2 --> SF : E3
SF --> [*]
@enduml

七、完整示例:订单状态机

1. 定义状态和事件

public enum OrderStates {
    CREATED,        // 订单创建
    PAYMENT_PENDING, // 待支付
    PAYMENT_RECEIVED,// 已支付
    PROCESSING,     // 处理中
    SHIPPED,        // 已发货
    DELIVERED,      // 已送达
    CANCELLED,      // 已取消
    RETURNED        // 已退货
}
public enum OrderEvents {
    INITIATE_PAYMENT,   // 发起支付
    PAYMENT_SUCCESS,    // 支付成功
    PAYMENT_FAILED,     // 支付失败
    PROCESS_ORDER,      // 处理订单
    SHIP_ORDER,         // 发货
    DELIVER_ORDER,      // 送达
    CANCEL_ORDER,       // 取消订单
    RETURN_ORDER        // 退货
}

2. 配置状态机

@Configuration
@EnableStateMachineFactory
public class OrderStateMachineConfig 
        extends EnumStateMachineConfigurerAdapter<OrderStates, OrderEvents> {
    @Override
    public void configure(StateMachineStateConfigurer<OrderStates, OrderEvents> states)
            throws Exception {
        states
            .withStates()
            .initial(OrderStates.CREATED)
            .state(OrderStates.PAYMENT_PENDING)
            .state(OrderStates.PAYMENT_RECEIVED)
            .state(OrderStates.PROCESSING)
            .state(OrderStates.SHIPPED)
            .state(OrderStates.DELIVERED)
            .end(OrderStates.CANCELLED)
            .end(OrderStates.RETURNED);
    }
    @Override
    public void configure(StateMachineTransitionConfigurer<OrderStates, OrderEvents> transitions)
            throws Exception {
        transitions
            // 从创建到待支付
            .withExternal()
                .source(OrderStates.CREATED)
                .target(OrderStates.PAYMENT_PENDING)
                .event(OrderEvents.INITIATE_PAYMENT)
                .and()
            // 支付成功
            .withExternal()
                .source(OrderStates.PAYMENT_PENDING)
                .target(OrderStates.PAYMENT_RECEIVED)
                .event(OrderEvents.PAYMENT_SUCCESS)
                .and()
            // 支付失败
            .withExternal()
                .source(OrderStates.PAYMENT_PENDING)
                .target(OrderStates.CANCELLED)
                .event(OrderEvents.PAYMENT_FAILED)
                .and()
            // 开始处理订单
            .withExternal()
                .source(OrderStates.PAYMENT_RECEIVED)
                .target(OrderStates.PROCESSING)
                .event(OrderEvents.PROCESS_ORDER)
                .and()
            // 发货
            .withExternal()
                .source(OrderStates.PROCESSING)
                .target(OrderStates.SHIPPED)
                .event(OrderEvents.SHIP_ORDER)
                .and()
            // 送达
            .withExternal()
                .source(OrderStates.SHIPPED)
                .target(OrderStates.DELIVERED)
                .event(OrderEvents.DELIVER_ORDER)
                .and()
            // 取消订单(在特定状态下)
            .withExternal()
                .source(OrderStates.CREATED)
                .target(OrderStates.CANCELLED)
                .event(OrderEvents.CANCEL_ORDER)
                .and()
            .withExternal()
                .source(OrderStates.PAYMENT_PENDING)
                .target(OrderStates.CANCELLED)
                .event(OrderEvents.CANCEL_ORDER)
                .and()
            // 退货
            .withExternal()
                .source(OrderStates.DELIVERED)
                .target(OrderStates.RETURNED)
                .event(OrderEvents.RETURN_ORDER);
    }
}

3. 使用状态机服务

@Service
public class OrderService {
    @Autowired
    private StateMachineFactory<OrderStates, OrderEvents> factory;
    private final Map<Long, StateMachine<OrderStates, OrderEvents>> machines = 
        new ConcurrentHashMap<>();
    public void createOrder(Long orderId) {
        StateMachine<OrderStates, OrderEvents> sm = buildStateMachine(orderId);
        sm.sendEvent(OrderEvents.INITIATE_PAYMENT);
    }
    public void processPayment(Long orderId, boolean success) {
        StateMachine<OrderStates, OrderEvents> sm = machines.get(orderId);
        if (sm != null) {
            sm.sendEvent(success ? 
                OrderEvents.PAYMENT_SUCCESS : 
                OrderEvents.PAYMENT_FAILED);
        }
    }
    public void shipOrder(Long orderId) {
        StateMachine<OrderStates, OrderEvents> sm = machines.get(orderId);
        if (sm != null && sm.getState().getId() == OrderStates.PROCESSING) {
            sm.sendEvent(OrderEvents.SHIP_ORDER);
        }
    }
    private StateMachine<OrderStates, OrderEvents> buildStateMachine(Long orderId) {
        StateMachine<OrderStates, OrderEvents> sm = factory.getStateMachine();
        sm.start();
        machines.put(orderId, sm);
        return sm;
    }
}

八、最佳实践

1. 状态机设计原则

  • 保持状态简单:每个状态应有明确的含义
  • 限制状态数量:避免状态爆炸(State Explosion)
  • 使用层次状态:管理复杂状态关系
  • 合理使用守卫:确保转换条件清晰
  • 分离业务逻辑:动作应调用服务而非包含复杂逻辑

2. 性能优化

  • 重用状态机实例:避免频繁创建
  • 异步事件处理:使用sendEvent(Message)异步接口
  • 合理持久化:只在必要时持久化状态
  • 缓存守卫结果:避免重复计算

3. 错误处理

@Component
public class ErrorStateMachineListener 
        extends StateMachineListenerAdapter<OrderStates, OrderEvents> {
    @Override
    public void stateMachineError(
            StateMachine<OrderStates, OrderEvents> stateMachine, 
            Exception exception) {
        // 记录错误并处理
        System.err.println("State machine error: " + exception.getMessage());
        stateMachine.stop();
    }
    @Override
    public void eventNotAccepted(Message<OrderEvents> event) {
        // 处理不被接受的事件
        System.err.println("Event not accepted: " + event.getPayload());
    }
}

九、测试状态机

JUnit 测试示例

@SpringBootTest
public class OrderStateMachineTest {
    @Autowired
    private StateMachineFactory<OrderStates, OrderEvents> factory;
    @Test
    public void testOrderFlow() {
        StateMachine<OrderStates, OrderEvents> sm = factory.getStateMachine();
        sm.start();
        // 初始状态应为CREATED
        assertEquals(OrderStates.CREATED, sm.getState().getId());
        // 发起支付
        sm.sendEvent(OrderEvents.INITIATE_PAYMENT);
        assertEquals(OrderStates.PAYMENT_PENDING, sm.getState().getId());
        // 支付成功
        sm.sendEvent(OrderEvents.PAYMENT_SUCCESS);
        assertEquals(OrderStates.PAYMENT_RECEIVED, sm.getState().getId());
        // 处理订单
        sm.sendEvent(OrderEvents.PROCESS_ORDER);
        assertEquals(OrderStates.PROCESSING, sm.getState().getId());
        // 发货
        sm.sendEvent(OrderEvents.SHIP_ORDER);
        assertEquals(OrderStates.SHIPPED, sm.getState().getId());
        // 送达
        sm.sendEvent(OrderEvents.DELIVER_ORDER);
        assertEquals(OrderStates.DELIVERED, sm.getState().getId());
    }
}

十、常见问题解决

1. 事件未被处理

  • 检查状态:确保当前状态支持该事件
  • 验证守卫:检查守卫条件是否满足
  • 查看日志:启用DEBUG日志查看状态机内部处理

2. 状态机不启动

  • 检查配置:确保@EnableStateMachine@EnableStateMachineFactory已启用
  • 手动启动:调用stateMachine.start()
  • 验证依赖:确保所有必需依赖已正确配置

3. 并发问题

  • 使用同步:对状态机操作加锁
  • 消息队列:使用消息队列顺序处理事件
  • 状态机池:创建状态机实例池

4. 持久化失败

  • 检查序列化:确保状态和事件可序列化
  • 数据库配置:验证持久化仓库配置正确
  • 事务管理:确保在事务边界内操作状态机

Spring Statemachine 提供了强大的状态管理能力,特别适合处理复杂的业务流程。通过合理设计状态模型、转换规则和业务动作,可以构建出高度可维护和可扩展的状态驱动应用。

到此这篇关于Spring Statemachine 状态机详解的文章就介绍到这了,更多相关Spring Statemachine 内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java中线程休眠编程实例

    Java中线程休眠编程实例

    这篇文章主要介绍了Java中线程休眠编程实例,本文直接给出代码实例,并对休眠方法做了一番讲解,需要的朋友可以参考下
    2015-06-06
  • java 删除数组元素与删除重复数组元素的代码

    java 删除数组元素与删除重复数组元素的代码

    在java中删除数组元素与过滤重复数组元素我们都会需要去遍历数组然后根据我们设置的值或方法进行去除数组
    2013-10-10
  • MyBatis 核心配置文件及映射文件详解

    MyBatis 核心配置文件及映射文件详解

    MyBatis是支持定制化SQL、存储过程以及高级映射的优秀的持久层框架,本文重点介绍MyBatis 核心配置文件及映射文件,需要的朋友可以参考下
    2023-01-01
  • java实现坦克大战游戏

    java实现坦克大战游戏

    这篇文章主要为大家详细介绍了java实现坦克大战游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-09-09
  • Java项目防止SQL注入的几种方法总结

    Java项目防止SQL注入的几种方法总结

    SQL注入是比较常见的网络攻击方式之一,在客户端在向服务器发送请求的时候,sql命令通过表单提交或者url字符串拼接传递到后台持久层,最终达到欺骗服务器执行恶意的SQL命令,下面这篇文章主要给大家总结介绍了关于Java项目防止SQL注入的几种方法,需要的朋友可以参考下
    2023-04-04
  • java AES加密/解密实现完整代码(附带源码)

    java AES加密/解密实现完整代码(附带源码)

    这篇文章主要介绍了java AES加密/解密实现的相关资料,包括AES加密算法的基本原理、Java加密API的使用方法以及项目实现的步骤和代码示例,需要的朋友可以参考下
    2025-04-04
  • 为什么Java要把字符串设计成不可变的

    为什么Java要把字符串设计成不可变的

    为什么Java要把字符串设计成不可变的,这篇文章给出了Java字符串设计成不可变的原因,感兴趣的小伙伴们可以参考一下
    2017-06-06
  • Mybatis-plus常见的坑@TableField不生效问题

    Mybatis-plus常见的坑@TableField不生效问题

    这篇文章主要介绍了Mybatis-plus常见的坑@TableField不生效问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01
  • Java中Function的使用及说明

    Java中Function的使用及说明

    这篇文章主要介绍了Java中Function的使用及说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-05-05
  • Java数据结构顺序表的详细讲解

    Java数据结构顺序表的详细讲解

    大家好,今天给大家带来的是顺序表,我觉得顺序表还是有比较难理解的地方的,于是我就把这一块的内容全部整理到了一起,希望能够给刚刚进行学习数据结构的人带来一些帮助,或者是已经学过这块的朋友们带来更深的理解,我们现在就开始吧
    2022-05-05

最新评论