spring statemachine持久化

鞠凌龙
2023-12-01

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"
      
 类似资料: