spring statemachine持久化

本文介绍如何利用Spring State Machine进行状态机的持久化处理,避免因应用重启而导致状态丢失。通过Redis实现状态机快照的存储与恢复,提供具体的实现代码及配置示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

spring statemachine持久化

您不能通过使用普通的java序列化来持久化,因为对象图太丰富,并且包含太多对其他Spring上下文类的依赖关系。 是状态机的运行时表示形式,可用于将现有计算机还原到由特定对象表示的状态。

——弹簧状态机 - 参考文档 (spring.io)

spring官方表示不用直接用序列化方法来实现状态机的持久化。之前我是将statemachine存入一个hashmap中,但只能存在内存当中,docker容器重新部署之后,之前的数据就丢失了。为此,通过spring提供的持久化方法存入到redis当中。持久化内容StateMachineContextStateMachine,只是持久化当前状态快照,恢复状态,不要求同一状态机。

StateMachineContext 是状态机的运行时表示形式(存储状态机当前状态的快照,可以从中获取StateMachine),可用StateMachineContext对象将状态机还原到特定的状态 。

  • 首先,生成一个StateMachinePersist,这里是通过RedisConnectionFactory生成RepositoryStateMachinePersist,然后再包装输出StateMachinePersister,这里是RedisStateMachinePersister。

    @Configuration
    public class PersistConfig {
        @Autowired
        private RedisConnectionFactory redisConnectionFactory;
        /**
         * 注入RedisStateMachinePersister对象
         *
         * @return
         */
        @Bean(name = "RedisPersister")
        public RedisStateMachinePersister<SessionStatus, SessionEvent> redisPersister() {
            return new RedisStateMachinePersister<>(redisPersist());
        }
        /**
         * 通过redisConnectionFactory创建StateMachinePersist
         *
         * @return
         */
        public StateMachinePersist<SessionStatus, SessionEvent, String> redisPersist() {
            RedisStateMachineContextRepository<SessionStatus, SessionEvent> repository = new RedisStateMachineContextRepository<>(redisConnectionFactory);
            return new RepositoryStateMachinePersist<>(repository);
        }
    }
    
  • 然后在controller调用

    StateMachine<SessionStatus,SessionEvent> stateMachine = new ApiStateMachineBuilder().build(beanFactory);
    stateMachinePersister.restore(stateMachine,sessionEntity1.getSessionId());
    //restore是取
    stateMachinePersister.persist(stateMachine,sessionEntity1.getSessionId());
    //persist是存
    
  • 在application.properties配置

    #Redis服务器地址
    #spring.redis.host=localhost
    spring.redis.host=172.22.0.1
    #Redis服务器连接端口
    spring.redis.port=6379
    #Redis数据库索引(默认为0)
    spring.redis.database= 0
    #连接超时时间(毫秒)
    spring.redis.timeout=1800000
    #连接池最大连接数(使用负值表示没有限制)
    spring.redis.lettuce.pool.max-active=20
    #最大阻塞等待时间(负数表示没限制)
    spring.redis.lettuce.pool.max-wait=-1
    #连接池中的最大空闲连接
    spring.redis.lettuce.pool.max-idle=5
    #连接池中的最小空闲连接
    spring.redis.lettuce.pool.min-idle=0
    
  • 部署在docker中之后,修改redis的conf文件

    • ifconfig获取ip

      @iZ8vb8s8t9gio6wq3bjc3bZ:/etc/redis$ ifconfig
      br-0a5afabfd675: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
              inet 172.22.0.1  netmask 255.255.0.0  broadcast 172.22.255.255
              inet6 fe80::42:a9ff:fe3a:ef1a  prefixlen 64  scopeid 0x20<link>
              ether 02:42:a9:3a:ef:1a  txqueuelen 0  (Ethernet)
              RX packets 43  bytes 2596 (2.5 KB)
              RX errors 0  dropped 0  overruns 0  frame 0
              TX packets 47  bytes 3566 (3.5 KB)
              TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
      
    • bind 127.0.0.1 -::1 修改为 bind 172.22.0.1 -::1

    • protected-mode 设置为no

    • 终端输入:redis-server

    • 终端输入:redis-cli -h 172.22.0.1 -p 6379

    • 在redis中查询:

      172.22.0.1:6379> keys *
      1) "001"
      172.22.0.1:6379> get 001
      "\xac\xed\x00\x05ur\x00\x02[B\xac\xf3\x17\xf8\x06\bT\xe0\x02\x00\x00xp\x00\x00\x00\x9d\x01\x00\x01\x00com.haifeng.spring_boot_demo.bean.SessionStatu\xf3\x01\x11\x00\x01\x01org.springframework.statemachine.support.ObservableMa\xf0\x01\x00\x01\x02java.util.ArrayLis\xf4\x01\x00\x01\x03java.util.HashMa\xf0\x01\x00\x00"
      
### 实现 StateMachine 的状态持久化 为了实现 `StateMachine` 的状态持久化,通常需要借助于 `StateMachinePersister` 接口来保存和恢复状态机的状态。具体来说,在 Spring Statemachine 中可以通过自定义 `StateMachinePersist` 来完成这一功能。 #### 创建自定义的 StateMachinePersist 类 首先创建一个类并实现 `StateMachinePersist<S, E, C>` 接口,其中泛型参数分别代表状态(S)、事件(E)以及上下文(C),该接口提供了两个核心的方法用于读写状态机的数据: - **write 方法**:负责将当前状态机的信息序列化后存入数据库或其他存储介质中。 ```java public void write(StateMachine<S, E> stateMachine, C context) throws Exception { // 序列化逻辑... } ``` - **read 方法**:当应用重启或需要回滚时可以从外部资源加载之前保存过的状态信息重新构建出相同的状态机实例 ```java public StateMachine<S, E> read(C context) throws Exception { // 反序列化逻辑... return restoredStateMachine; } ``` 此部分的具体实现在很大程度上取决于所使用的数据访问技术(如 JPA 或者 Redis 等)。对于每种不同的持久层框架都需要编写相应的适配器代码[^4]。 #### 构建 DefaultStateMachinePersister Bean 一旦完成了上述工作,则可通过配置文件或者 Java Config 方式注册一个新的 `DefaultStateMachinePersister` bean 并注入前面提到的那个实现了 `StateMachinePersist` 接口的对象作为其构造函数依赖项之一: ```java @Bean public DefaultStateMachinePersister<NewStates, NewEvents, String> newStateMachinePersister( CustomStateMachinePersist customStateMachinePersist){ return new DefaultStateMachinePersister<>(customStateMachinePersist); } ``` 这里假设已经有一个名为 `CustomStateMachinePersist` 的类实现了必要的持久化操作[^2]。 #### 使用 StateMachinePersister 进行状态管理 最后就可以利用这个 persister 对象来进行状态的保存与恢复了。例如下面这段伪代码展示了如何在一个服务方法内部调用这些 API : ```java // 存储状态机状态 newStateMachinePersister.persist(newStateMachine, STATE_MACHINE_PREFIX + id); // 恢复状态机状态 StateMachinestateMachine = newStateMachinePersister.restore(newStateMachine, STATE_MACHINE_PREFIX + id); ``` 以上就是关于 `StateMachine` 状态持久化的全部内容。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

五道口社畜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值