当前位置: 代码网 > it编程>编程语言>Java > Springboot集成SpringState状态机的实现

Springboot集成SpringState状态机的实现

2025年06月30日 Java 我要评论
1.springstate 简介状态机核心概念​​项目说明状态(state)​​对象生命周期中的特定条件(如订单的待支付、已发货)事件(event)​​触发状态转换的动作(如支付成功、取消订单)转换(

1.springstate 简介

状态机核心概念​​

项目说明
状态(state)​​对象生命周期中的特定条件(如订单的待支付、已发货)
事件(event)​​触发状态转换的动作(如支付成功、取消订单)
转换(transition)​​定义事件如何驱动状态迁移(如待支付 → 支付事件 → 待发货)
守卫(guard)​​条件检查,决定是否允许转换(如“仅未超时订单可支付”)
​​动作(action)​​条件检查,决定是否允许转换(如“仅未超时订单可支付”)

应用场景

  • 订单生命周期管理​​
    管理订单从创建到完成的完整流程(如待支付 → 待发货 → 已完成)

  • 工作流引擎​​
    审批流程的状态控制(如提交 → 审核中 → 已批准)

  • ​​游戏状态流转​​
    角色状态切换(如空闲 → 战斗 → 死亡)

  • 物联网设备监控​​
    设备状态跟踪(如离线 → 在线 → 故障)

2.状态机示例

2.1 项目结构和依赖包

在这里插入图片描述

<?xml version="1.0" encoding="utf-8"?>
<project xmlns="http://maven.apache.org/pom/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"
         xsi:schemalocation="http://maven.apache.org/pom/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelversion>4.0.0</modelversion>

    <groupid>org.example</groupid>
    <artifactid>spring-state-m</artifactid>
    <version>1.0-snapshot</version>

    <properties>
        <maven.compiler.source>21</maven.compiler.source>
        <maven.compiler.target>21</maven.compiler.target>
        <project.build.sourceencoding>utf-8</project.build.sourceencoding>
        <spring-boot.version>3.5.3</spring-boot.version>
    </properties>

    <dependencymanagement>
        <dependencies>
            <dependency>
                <groupid>org.springframework.boot</groupid>
                <artifactid>spring-boot-dependencies</artifactid>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencymanagement>

    <dependencies>
        <dependency>
            <groupid>org.springframework.boot</groupid>
            <artifactid>spring-boot-starter-web</artifactid>
        </dependency>
        <dependency>
            <groupid>org.springframework.boot</groupid>
            <artifactid>spring-boot-starter-data-redis</artifactid>
        </dependency>

        <!-- spring state machine -->
        <dependency>
            <groupid>org.springframework.statemachine</groupid>
            <artifactid>spring-statemachine-starter</artifactid>
            <version>4.0.0</version>
        </dependency>
        <!-- spring state machine redis persistence -->
        <dependency>
            <groupid>org.springframework.statemachine</groupid>
            <artifactid>spring-statemachine-data-redis</artifactid>
            <version>4.0.0</version>
        </dependency>
    </dependencies>
</project>

启动类

package org.example;

import org.springframework.boot.springapplication;
import org.springframework.boot.autoconfigure.springbootapplication;
import org.springframework.scheduling.annotation.enableasync;

@enableasync
@springbootapplication
public class springstatemachine {
    public static void main(string[] args) {
        springapplication.run(springstatemachine.class, args);
    }
}

2.2 定义事件类和状态类

事件用于驱动状态转移,状态用于记录事件进度

事件类

package org.example.common;

/**
 * @author zhx && moon
 * @since 21
 * @date 2025-06-18 pm 6:38
 */
public enum orderevent {
    pay,            // 支付操作
    ship,           // 发货操作
    confirm,        // 确认收货
    cancel          // 取消订单
}

状态类

package org.example.common;

/**
 * @author zhx && moon
 * @since 21
 * @date 2025-06-18 pm 6:37
 */
public enum orderstate {
    unpaid,         // 待支付
    paid,           // 已支付
    shipped,        // 已发货
    confirmed,      // 已确认收货
    cancelled       // 已取消
}

2.3 spring 事件监听器

spring 事件监听器,用于异步处理事件流,当状态机结束时,推送当前状态机到监听器,监听器则从持久化中删除该状态机

package org.example.config;

import org.example.entity.ordersmcontext;
import org.slf4j.logger;
import org.slf4j.loggerfactory;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.context.event.eventlistener;
import org.springframework.scheduling.annotation.async;
import org.springframework.stereotype.component;

/**
 * @author zhx && moon
 * @since 21
 * @date 2025-06-20 am 10:18
 */
@component
public class asynceventlistener {

    logger logger = loggerfactory.getlogger(this.getclass());

    @autowired
    smcontainer smcontainer;

    @async
    @eventlistener
    public void handleasyncevent(ordersmcontext context) {
        logger.info("order id {} has delete {}", context.getorderid(), smcontainer.delete(context.getorderid()));
    }

}

2.4 状态机持久化类

利用 redis 做状态机的持久化存储

2.4.1 redis 状态机持久化容器

package org.example.config;

import org.example.common.orderevent;
import org.example.common.orderstate;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.context.annotation.bean;
import org.springframework.data.redis.connection.redisconnectionfactory;
import org.springframework.data.redis.core.redistemplate;
import org.springframework.data.redis.serializer.stringredisserializer;
import org.springframework.statemachine.data.redis.redisstatemachinecontextrepository;
import org.springframework.statemachine.persist.repositorystatemachinepersist;
import org.springframework.stereotype.component;

/**
 * @author zhx && moon
 * @since 21
 * @date 2025-06-18 pm 6:54
 */
@component
public class myredispersisterconfig {

    @autowired
    private redisconnectionfactory factory;

    /**
     * 创建 redisstatemachinerepository 实例
     */
    @bean(name = "redisstatemachinecontextrepository")
    public myredisstatemachineper<orderstate, orderevent> getredispersister() {
        // 创建 redisstatemachinerepository 实例
        redisstatemachinecontextrepository<orderstate, orderevent> repository = new redisstatemachinecontextrepository<>(factory);
        // 持久化
        repositorystatemachinepersist persister = new repositorystatemachinepersist(repository);
        // 获取 redis statemachinepersister 实例
        myredisstatemachineper machine = new myredisstatemachineper<>(persister);
        redistemplate<string, byte[]>  redistemplate = createdefaulttemplate(factory);
        machine.setredistemplate(redistemplate);
        // 返回
        return machine;
    }

    /**
     * 与 redisstatemachinecontextrepository 使用相同的序列化配置
     * @param connectionfactory
     * @return
     */
    private static redistemplate<string, byte[]> createdefaulttemplate(redisconnectionfactory connectionfactory) {
        redistemplate<string, byte[]> template = new redistemplate();
        template.setkeyserializer(new stringredisserializer());
        template.sethashkeyserializer(new stringredisserializer());
        template.setconnectionfactory(connectionfactory);
        template.afterpropertiesset();
        return template;
    }
}

2.4.2 redis 配置

package org.example.config;

import org.springframework.data.redis.core.redistemplate;
import org.springframework.statemachine.statemachinepersist;
import org.springframework.statemachine.data.redis.redisstatemachinepersister;

/**
 * @author zhx && moon
 * @since 21
 * @date 2025-06-19 pm 5:21
 */
public class myredisstatemachineper<s, e> extends redisstatemachinepersister<s, e> {

    redistemplate<string, byte[]> redistemplate;

    public myredisstatemachineper(statemachinepersist<s, e, string> statemachinepersist) {
        super(statemachinepersist);
    }

    public void setredistemplate(redistemplate<string, byte[]> redistemplate){
        this.redistemplate = redistemplate;
    }

    /**
     * 检查 redis 中是否存在指定的 key
     * @param key
     * @return
     */
    public boolean isunexist(string key){
        return !this.redistemplate.haskey(key);
    }

    /**
     * 删除 redis 中指定的 key
     * @param key
     * @return
     */
    public boolean deletekey(string key){
        return this.redistemplate.delete(key);
    }

}

2.4.3 状态机监听器

用于监听状态机状态变化

package org.example.config;

import org.example.common.orderevent;
import org.example.common.orderstate;
import org.example.entity.ordersmcontext;
import org.slf4j.logger;
import org.slf4j.loggerfactory;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.context.applicationeventpublisher;
import org.springframework.messaging.message;
import org.springframework.statemachine.statemachine;
import org.springframework.statemachine.listener.statemachinelisteneradapter;
import org.springframework.statemachine.state.state;
import org.springframework.stereotype.component;

/**
 * @author zhx && moon
 * @since 21
 * @date 2025-06-19 pm 4:58
 */
@component
public class redstatemachinelistener extends statemachinelisteneradapter<orderstate, orderevent> {

    logger logger = loggerfactory.getlogger(this.getclass());

    @autowired
    private applicationeventpublisher publisher;

    /**
     * 状态变化
     * @param from
     * @param to
     */
    @override
    public void statechanged(state<orderstate, orderevent> from, state<orderstate, orderevent> to) {
        // 状态变更时的处理
        if (null == from) {
            logger.info("state machine init, from init to {}", to.getid());
        } else {
            logger.info("state machine change, from {} to {}", from.getid(), to.getid());
        }
    }

    /**
     * 状态机启动成功时的回调
     * @param sm
     */
    @override
    public void statemachinestarted(statemachine<orderstate, orderevent> sm) {
        logger.info("state machine {} start success.", sm.getid());
    }

    /**
     * 状态机结束的回调
     * @param sm
     */
    @override
    public void statemachinestopped(statemachine<orderstate, orderevent> sm) {
        logger.info("state machine {} stop success.", sm.getid());
        publisher.publishevent(new ordersmcontext(sm.getid()));
    }

    @override
    public void eventnotaccepted(message<orderevent> event) {
        logger.error("event not accepted: {}", event.getpayload());
    }

}

2.5 装机器容器

用于管理状态机的创建,本地化缓存与持久化存储

package org.example.config;

import org.example.common.orderevent;
import org.example.common.orderstate;
import org.slf4j.logger;
import org.slf4j.loggerfactory;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.statemachine.statemachine;
import org.springframework.statemachine.config.statemachinefactory;
import org.springframework.stereotype.component;

import java.util.hashmap;
import java.util.map;
import java.util.objects;

/**
 * @author zhx && moon
 * @since 21
 * @date 2025-06-19 pm 4:30
 */
@component
public class smcontainer {

    logger logger = loggerfactory.getlogger(this.getclass());

    @autowired
    private statemachinefactory<orderstate, orderevent> factory;

    @autowired
    private myredisstatemachineper<orderstate, orderevent> myredisstatemachineper;

    private map<string, statemachine<orderstate, orderevent>> map = new hashmap<>(16);

    /**
     * 获取状态机
     * @param orderid 订单id
     * @return 状态机实例
     */
    public synchronized statemachine<orderstate, orderevent> getstatemachine(string orderid) {
        string key = getkey(orderid);
        try {
            // 取缓存
            statemachine<orderstate, orderevent> sm = map.get(orderid);
            // 校验
            if (objects.isnull(sm)) {
                // 获取状态机实例
                sm = factory.getstatemachine(orderid);
                // 校验是否存在
                if (myredisstatemachineper.isunexist(key)) {
                    sm.startreactively().subscribe();
                    myredisstatemachineper.persist(sm, key);
                } else {
                    // 恢复状态
                    myredisstatemachineper.restore(sm, key);
                }
                // 缓存状态机
                map.put(orderid, sm);
            }
            return sm;
        } catch (exception e) {
            logger.error("get state machine error: {}", e.getmessage(), e);
            return null;
        }
    }

    /**
     * 保存状态机
     * @param orderid
     * @param statemachine
     */
    public synchronized boolean save(statemachine<orderstate, orderevent> statemachine, string orderid){
        try {
            string key = getkey(orderid);
            myredisstatemachineper.persist(statemachine, key);
            return true;
        } catch (exception e) {
            logger.error("save state machine error: {}", e.getmessage(), e);
            return false;
        }
    }

    /**
     * 删除状态机
     * @param orderid
     * @return
     */
    public synchronized boolean delete(string orderid){
        return myredisstatemachineper.deletekey(getkey(orderid));
    }

    /**
     * 获取 key
     * @param orderid
     * @return
     */
    private string getkey(string orderid){
        return "state-machine:" +orderid;
    }

}

2.6 状态机事件发送器

用于统一发送状态机事件,管理事件发送过程

package org.example.config;

import org.example.common.orderevent;
import org.example.common.orderstate;
import org.slf4j.logger;
import org.slf4j.loggerfactory;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.messaging.message;
import org.springframework.messaging.support.messagebuilder;
import org.springframework.statemachine.statemachine;
import org.springframework.statemachine.statemachineeventresult;
import org.springframework.stereotype.component;
import reactor.core.publisher.mono;

import java.util.concurrent.atomic.atomicboolean;

/**
 * @author zhx && moon
 * @since 21
 * @date 2025-06-20 pm 2:22
 */
@component
public class smeventsender {

    logger logger = loggerfactory.getlogger(this.getclass());

    @autowired
    smcontainer smcontainer;

    /**
     * 初始化订单状态机
     * @param orderid
     */
    public void initorderstatemachine(string orderid) {
        smcontainer.getstatemachine(orderid);
    }

    /**
     * 发送事件
     * @param orderid
     * @param event
     * @return
     */
    public boolean send(string orderid, orderevent event) {
        // 获取状态
        statemachine<orderstate, orderevent> sm = smcontainer.getstatemachine(orderid);
        // 构建事件消息
        message<orderevent> message = messagebuilder
                .withpayload(event)
                .setheader("orderid", orderid) // 订单对象关联状态机
                .build();
        // 发送事件
        atomicboolean result = new atomicboolean(false);
        sm.sendevent(mono.just(message)).subscribe(r->{
            if (r.getresulttype() == statemachineeventresult.resulttype.accepted) {
                // 成功
                result.set(true);
                // 在未完成时持久化
                if (!orderevent.confirm.equals(event)) {
                    smcontainer.save(sm, orderid);
                }
            } else {
                result.set(false);
            }
        });
        // 输出
        logger.info("send event: {}, orderid: {}, result: {}", event, orderid, result.get());
        // 返回
        return result.get();
    }

}

2.7 状态机配置

状态机配置,定义事件和状态关系,以及守卫和动作

package org.example.config;

import org.example.common.orderevent;
import org.example.common.orderstate;
import org.slf4j.logger;
import org.slf4j.loggerfactory;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.context.annotation.configuration;
import org.springframework.statemachine.config.enablestatemachinefactory;
import org.springframework.statemachine.config.statemachineconfigureradapter;
import org.springframework.statemachine.config.builders.statemachineconfigurationconfigurer;
import org.springframework.statemachine.config.builders.statemachinestateconfigurer;
import org.springframework.statemachine.config.builders.statemachinetransitionconfigurer;

import java.util.enumset;

/**
 * @author zhx && moon
 * @since 21
 * @date 2025-06-18 pm 6:38
 */
@configuration
@enablestatemachinefactory
public class statemachineconfig extends statemachineconfigureradapter<orderstate, orderevent> {

    logger logger = loggerfactory.getlogger(this.getclass());

    @autowired
    redstatemachinelistener listener;

    @override
    public void configure(statemachineconfigurationconfigurer<orderstate, orderevent> config) throws exception {
        config.withconfiguration()
                // 注册监听器
                .listener(listener);
    }

    /**
     * 状态机初始化
     * @param states
     * @throws exception
     */
    @override
    public void configure(statemachinestateconfigurer<orderstate, orderevent> states) throws exception {
        states.withstates()
                .initial(orderstate.unpaid)
                .states(enumset.allof(orderstate.class))
                .end(orderstate.confirmed)
                .end(orderstate.cancelled);
    }

    /**
     * 状态转移逻辑
     * @param transitions
     * @throws exception
     */
    @override
    public void configure(statemachinetransitionconfigurer<orderstate, orderevent> transitions) throws exception {
        transitions
                // 支付:unpaid -> paid
                .withexternal()
                .source(orderstate.unpaid)
                .target(orderstate.paid)
                .guard(context -> {
                    // (前置)守卫条件,校验支付结果
                    logger.info("check order {} pay result ...", context.getmessageheader("orderid"));
                    return true;
                })
                .action(context -> {
                    // (后置)触发动作,通知仓库备货
                    logger.info("order {} pay success, notify warehouse to prepare goods ...", context.getmessageheader("orderid"));
                })
                .event(orderevent.pay)
                .and()
                // 发货:paid -> shipped
                .withexternal()
                .source(orderstate.paid)
                .target(orderstate.shipped)
                .event(orderevent.ship)
                .and()
                // 确认收货:shipped -> confirmed
                .withexternal()
                .source(orderstate.shipped)
                .target(orderstate.confirmed)
                .event(orderevent.confirm)
                .and()
                // 取消订单(仅在待支付可取消)
                .withexternal()
                .source(orderstate.unpaid)
                .target(orderstate.cancelled)
                .event(orderevent.cancel);
    }

}


2.8 接口类

用于模拟订单操作

package org.example.controller;

import org.example.service.orderservice;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.web.bind.annotation.getmapping;
import org.springframework.web.bind.annotation.pathvariable;
import org.springframework.web.bind.annotation.requestmapping;
import org.springframework.web.bind.annotation.restcontroller;

/**
 * @author zhx && moon
 * @since 21
 * @date 2025-06-18 pm 6:41
 */
@restcontroller
@requestmapping("/orders")
public class ordercontroller {

    @autowired
    private orderservice orderservice;

    @getmapping("/create")
    public string create() {
        return orderservice.createorder();
    }

    @getmapping("/pay/{orderid}")
    public string pay(@pathvariable("orderid") string orderid) {
        return orderservice.payorder(orderid);
    }

    @getmapping("/shipped/{orderid}")
    public string shipped(@pathvariable("orderid") string orderid) {
        return orderservice.shipped(orderid);
    }

    @getmapping("/confirm/{orderid}")
    public string confirm(@pathvariable("orderid") string orderid) {
        return orderservice.confirm(orderid);
    }

    @getmapping("/{orderid}/status")
    public string status(@pathvariable string orderid) {
        return "当前状态: " + orderservice.getorderstate(orderid);
    }

}

2.9 实现类

package org.example.service;

import org.example.common.orderevent;
import org.example.common.orderstate;
import org.example.config.smeventsender;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.stereotype.service;

/**
 * @author zhx && moon
 * @since 21
 * @date 2025-06-18 pm 6:40
 */
@service
public class orderservice {

    @autowired
    smeventsender smeventsender;

    /**
     * 创建订单并初始化状态机
     * @return
     */
    public string createorder() {
        try {
            // 使用时间戳作为订单id
            string orderid = string.valueof(system.currenttimemillis());
            // 初始化
            smeventsender.initorderstatemachine(orderid);
            // 返回订单id
            return orderid;
        } catch (exception e) {
            return e.getmessage();
        }
    }

    /**
     * 支付
     * @param orderid
     * @return
     */
    public string payorder(string orderid) {
        try {
            boolean result = smeventsender.send(orderid, orderevent.pay);
            return "success:" + result;
        } catch (exception e) {
            return e.getmessage();
        }
    }

    /**
     * 发货
     * @param orderid
     * @return
     */
    public string shipped(string orderid) {
        try {
            boolean result = smeventsender.send(orderid, orderevent.ship);
            return "success:" + result;
        } catch (exception e) {
            return e.getmessage();
        }
    }

    /**
     * 确认收货
     * @param orderid
     * @return
     */
    public string confirm(string orderid) {
        try {
            boolean result = smeventsender.send(orderid, orderevent.confirm);
            return "success:" + result;
        } catch (exception e) {
            return e.getmessage();
        }
    }

    public orderstate getorderstate(string orderid) {
        return orderstate.unpaid;
    }
}

2.10 状态机上下文

用于管理状态机信息

package org.example.entity;

import org.example.common.orderstate;

import java.time.localdatetime;
import java.util.hashmap;
import java.util.map;

/**
 * @author zhx && moon
 * @since 21
 * @date 2025-06-18 pm 6:54
 */
public class ordersmcontext {

    public ordersmcontext(string orderid){
        this.orderid = orderid;
    }

    private string orderid;
    private orderstate currentstate;
    private map<string, object> extendedstate = new hashmap<>();
    private localdatetime createdat;
    private localdatetime lastmodifiedat;

    public string getorderid() {
        return orderid;
    }

    public void setorderid(string orderid) {
        this.orderid = orderid;
    }
}

2.11 配置文件

spring:
  data:
    redis:
      database: 0
      host: 192.168.1.103
      port: 6379
      password: 123456
      timeout: 5000

3.状态机测试

3.1创建订单

在这里插入图片描述

3.2持久化结果

初始化时自动将数据持久化到 redis

在这里插入图片描述

3.3 支付订单

在这里插入图片描述

3.4 发货

在这里插入图片描述

3.5 确认收货

在这里插入图片描述

后台日志

在这里插入图片描述

到此这篇关于springboot集成springstate状态机的实现的文章就介绍到这了,更多相关springstate 状态机内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网! 

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com