欢迎来到徐庆高(Tea)的个人博客网站
磨难很爱我,一度将我连根拔起。从惊慌失措到心力交瘁,我孤身一人,但并不孤独无依。依赖那些依赖我的人,信任那些信任我的人,帮助那些给予我帮助的人。如果我愿意,可以分裂成无数面镜子,让他们看见我,就像看见自己。察言观色和模仿学习是我的领域。像每个深受创伤的人那样,最终,我学会了随遇而安。
当前位置: 日志文章 > 详细内容

Spring StateMachine实现状态机使用示例详解

2025年07月13日 Java
什么是状态机状态机是计算机科学中的​​核心建模工具​​,用于描述对象在其生命周期内状态变化的逻辑模型。它通过定义​​有限状态集合​​、​​状态转移规则​​和​​触发事件​​,精确控制系统的行为逻辑。本

什么是状态机

状态机是计算机科学中的​​核心建模工具​​,用于描述对象在其生命周期内状态变化的逻辑模型。它通过定义​​有限状态集合​​、​​状态转移规则​​和​​触发事件​​,精确控制系统的行为逻辑。

本文主要讲spring statemachine实现的状态机

使用示例

导入maven依赖

        <dependency>
            <groupid>org.springframework.statemachine</groupid>
            <artifactid>spring-statemachine-core</artifactid>
            <version>4.0.0</version>
        </dependency>

创建订单状态枚举类

public enum orderstatusenum {
    waiting_payment,//待支付
    waiting_receive,//待取货
    finished,//已完成
    canceled;//已取消
}

创建订单转悠事件枚举类

public enum orderevent {
    create_order,//创建订单
    pay_order,//支付订单
    receive_order,//取货
    cancel_order,//取消订单
    finish_order//完成订单
}

添加状态机实例并添加状态转移规则

@configuration
@enablestatemachine(name="orderstatemachine")
public class orderstatemachineconfig {
    @bean
    public statemachine<orderstatusenum, orderevent> orderstatemachine() throws exception {
        statemachinebuilder.builder<orderstatusenum, orderevent> builder = statemachinebuilder.builder();
        // 配置状态
        builder.configurestates()
                .withstates()
                .initial(orderstatusenum.waiting_payment) // 初始状态
                .states(enumset.allof(orderstatusenum.class));// 配置所有状态
        // 配置状态转换 规则
        builder.configuretransitions()
                // 订单待支付 -> 待取货
                .withexternal()
                .source(orderstatusenum.waiting_payment).target(orderstatusenum.waiting_receive)
                .event(orderevent.pay_order)
                .and()
                // 订单待取货 -> 已完成
                .withexternal()
                .source(orderstatusenum.waiting_receive).target(orderstatusenum.finished)
                .event(orderevent.finish_order)
                .and()
                // 订单待支付 -> 已取消
                .withexternal()
                .source(orderstatusenum.waiting_payment).target(orderstatusenum.canceled)
                .event(orderevent.cancel_order);
        return builder.build();
    }
}

注入上下文bean,方法作用后面会说

@bean
    public defaultstatemachinepersister persister(){
        return new defaultstatemachinepersister<>(new statemachinepersist<object, object, order>() {
            @override
            public void write(statemachinecontext<object, object> context, order order) throws exception {
                //此处并没有进行持久化操作
                system.out.println("订单状态持久化:" + context.getstate());
            }
            @override
            public statemachinecontext<object, object> read(order order) throws exception {
                //此处直接获取order中的状态,其实并没有进行持久化读取操作
                return new defaultstatemachinecontext(order.getstatus(), null, null, null);
            }
        });
    }

创建调用示例服务

@service
@requiredargsconstructor
public class orderservice {
    private final statemachine<orderstatusenum, orderevent> orderstatemachine;
    private final defaultstatemachinepersister persister;
    // 1、事件: 支付
    // 2、状态转换:待支付 → 待发货\
     public order pay() {
         order order = order
                 .builder()
                 .orderid("1")
                 .status(orderstatusenum.waiting_receive)
                 .build();
         system.out.println("线程名称:" + thread.currentthread().getname() + " 尝试支付,订单号:" + order.getorderid());
        message message = messagebuilder.withpayload(orderevent.pay_order).setheader("order", order).build();
        if (!sendevent(message, order)) {
            system.out.println("线程名称:" + thread.currentthread().getname() + " 支付失败, 状态异常,订单号:" + order.getorderid());
        }
        system.out.println("线程名称:" + thread.currentthread().getname() + " 支付成功,订单号:" + order.getorderid());
        return order;
    }
    /**
     * 发送订单状态转换事件
     *
     * @param message
     * @param order
     * @return
     */
    private synchronized boolean sendevent(message<orderevent> message, order order) {
        boolean result = false;
        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;
    }
}

代码解析:

创建订单示例模拟数据库实际订单信息,基于当前订单状态变换的流转与事件创建对应message消息,同时添加head信息。调用sendevent方法使用状态机判断。

public order pay() {
         order order = order
                 .builder()
                 .orderid("1")
                 .status(orderstatusenum.waiting_receive)
                 .build();
         system.out.println("线程名称:" + thread.currentthread().getname() + " 尝试支付,订单号:" + order.getorderid());
        message message = messagebuilder.withpayload(orderevent.pay_order).setheader("order", order).build();
        if (!sendevent(message, order)) {
            system.out.println("线程名称:" + thread.currentthread().getname() + " 支付失败, 状态异常,订单号:" + order.getorderid());
        }
        system.out.println("线程名称:" + thread.currentthread().getname() + " 支付成功,订单号:" + order.getorderid());
        return order;
    }

判断逻辑很简单,

.start()启动状态机,

.restore()方法跟踪发现实际调用的是上面上下文bean中的read()方法,作用是恢复状态机的上下文,结果一番搜索后,博主终于明白这步的作用。首先我们要知道spring statemachine状态机是无状态的,每次启动都会是默认的状态,而他状态判断逻辑不会从所有规则中寻找符合的规则,而是基于状态机当前的状态与传入的事件进行判断状态流转是否正确,因此需要将当前状态与状态机中的状态进行同步

.sendevent()方法是实际调用状态机内部的进行状态流转规则的判断,符合状态流转规则时对状态进行变换,同时符合规则转换成功时返回true,否则返回false

通过dubug追踪看到,状态变换成功,同时返回true

.persist()方法内部实际调用上下文中的write方法,可以在此进行实际的数据持久化

接着在finally中停止状态机

private synchronized boolean sendevent(message<orderevent> message, order order) {
        boolean result = false;
        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;
    }

至此,基本的状态机就顺利实现

到此这篇关于spring statemachine实现状态机使用示例详解的文章就介绍到这了,更多相关spring statemachine状态机内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!