You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

恢复状态机后丢失StateMachineInterceptor的问题求助

问题

重启服务后,从持久化存储恢复的状态机丢失了首次创建时添加的StateMachineInterceptor。这个拦截器是状态转换后置处理的核心,不能用Listener替代(因为我的逻辑需要依赖stateMachineInstance实例)。

另外还有个疑惑:当前只有state_machine表有数据变更,其他初始化生成的表始终没有变化。

相关代码如下:

StateMachineConfig配置类

public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<S,E>{
@Override
    public void configure(StateMachineConfigurationConfigurer<S, E> config) throws Exception {
        config
            .withPersistence()
            .runtimePersister(stateMachinePersister);
        config
            .withConfiguration()
            .autoStartup(false)
            .listener(listener);
    }
}

StateMachineService配置类

@Configuration
@RequiredArgsConstructor
public class StateMachineServiceConfig {

    private final StateMachineFactory<S, E> factory;
    private final StateMachineRuntimePersister<S, E, String> stateMachinePersister;

    @Bean
    public StateMachineService<S, E> stateMachineService() {
        return new DefaultStateMachineService<>(factory, stateMachinePersister);
    }
}

持久化器配置类

@Configuration
public class StateMachinePersistenceConfiguration {
    @Bean
    public StateMachineRuntimePersister<S, E, String> stateMachinePersister(
            final JpaStateMachineRepository jpaStateMachineRepository) {
        return new JpaPersistingStateMachineInterceptor<>(jpaStateMachineRepository);
    }
}

状态机创建与恢复类

@Service
@RequiredArgsConstructor
@Slf4j
public class RelocationRequestsSSMService {

    private final StateMachineService<S, E> stateMachineService;
    private final MyInterceptor stateMachineInterceptor;

    public StateMachine<S, E> createStateMachine() {
        StateMachine<S, E> stateMachine = stateMachineService.acquireStateMachine(UUID.randomUuid());
        stateMachine.getStateMachineAccessor().withRegion().addStateMachineInterceptor(stateMachineInterceptor);
        log.debug("Created ssm with id: " + stateMachine.getId());
        return stateMachine;
    }


    private StateMachine<S, E> getStateMachineBySsmId(String ssmId) {
        log.debug("Request ssm from persister with id: " + ssmId);
        StateMachine<S, E> stateMachine = stateMachineService.acquireStateMachine(ssmId);
        log.debug("Get ssm from persister with id and uuid: " + stateMachine.getId() + " " + stateMachine.getUuid());
        return stateMachine;
    }
}

问题分析与解决办法

核心原因

Spring StateMachine的默认JPA持久化实现只会保存状态机的核心状态信息(比如当前状态、状态机ID等)和静态配置元数据,不会持久化运行时动态添加的StateMachineInterceptor——因为Interceptor属于附加的运行时逻辑,不属于状态机的可持久化状态范畴。

解决办法

1. 全局配置Interceptor(推荐)

把Interceptor直接配置到StateMachineConfig中,这样无论创建新状态机还是恢复旧状态机,都会自动加载这个Interceptor,不需要动态添加。修改StateMachineConfig的configure方法:

public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<S,E>{

    private final MyInterceptor stateMachineInterceptor;

    // 构造注入Interceptor
    public StateMachineConfig(MyInterceptor stateMachineInterceptor) {
        this.stateMachineInterceptor = stateMachineInterceptor;
    }

    @Override
    public void configure(StateMachineConfigurationConfigurer<S, E> config) throws Exception {
        config
            .withPersistence()
            .runtimePersister(stateMachinePersister);
        config
            .withConfiguration()
            .autoStartup(false)
            .listener(listener)
            // 全局添加Interceptor
            .stateMachineInterceptor(stateMachineInterceptor);
    }
}

之后createStateMachine方法里就可以去掉动态添加Interceptor的代码了。

2. 恢复状态机时重新附加(适用于动态场景)

如果你的Interceptor需要针对不同状态机实例做个性化配置,无法全局统一,那就在恢复状态机的getStateMachineBySsmId方法里,重新给恢复后的状态机添加Interceptor:

private StateMachine<S, E> getStateMachineBySsmId(String ssmId) {
    log.debug("Request ssm from persister with id: " + ssmId);
    StateMachine<S, E> stateMachine = stateMachineService.acquireStateMachine(ssmId);
    // 恢复后重新添加Interceptor
    stateMachine.getStateMachineAccessor().withRegion().addStateMachineInterceptor(stateMachineInterceptor);
    log.debug("Get ssm from persister with id and uuid: " + stateMachine.getId() + " " + stateMachine.getUuid());
    return stateMachine;
}

关于其他表无变更的说明

Spring StateMachine的JPA持久化中,state_machine表用来存储每个状态机实例的运行时状态(比如当前状态、最后更新时间等),状态变更时会更新这张表。而其他表(比如state_machine_state、state_machine_transition)是用来存储状态机的静态结构元数据(比如定义的状态、转换规则等),只有在首次初始化状态机结构或者结构发生变更时才会更新。如果你的状态机结构是固定的,这些表没有变更是完全正常的。

内容的提问来源于stack exchange,提问作者Ytug Ilya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 16:35:25