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

求助:如何基于Spring State Machine与Papyrus设计正交状态机

解决Spring State Machine正交状态与主状态依赖的实现问题

嘿,我刚好处理过类似的Spring State Machine正交状态场景,给你一套完整的实现方案,从Papyrus建模到SSM代码配置都理清楚,帮你搞定这个问题:

1. 先在Papyrus里梳理正确的状态机结构

先把模型搭对,这是代码实现的基础:

  • 根状态下划分两个正交区域:一个叫SubSystems(包含A、B、C三个独立子状态机),另一个叫MainSystem(放主状态M)
  • 每个子系统(A/B/C)的状态流:初始状态 → off,通过对应事件(比如TURN_ON_A)转换到on
  • 主状态M的状态流:初始 → off,只有当A/B/C全为on时,才触发转换到on

2. Spring State Machine代码实现步骤

2.1 定义状态和事件枚举

先把所有状态、事件用枚举明确,避免拼写错误:

public enum States {
    // 子系统状态
    A_OFF, A_ON,
    B_OFF, B_ON,
    C_OFF, C_ON,
    // 主状态
    M_OFF, M_ON,
    // 正交状态组标识
    SUB_SYSTEMS, MAIN_SYSTEM
}

public enum Events {
    TURN_ON_A, TURN_ON_B, TURN_ON_C
}

2.2 配置状态机核心结构

在配置类里搭建正交状态结构,同时定义转换规则和守卫条件:

@Configuration
@EnableStateMachine
public class StateMachineConfig extends StateMachineConfigurerAdapter<States, Events> {

    @Override
    public void configure(StateMachineStateConfigurer<States, Events> states) throws Exception {
        states
            // 配置主状态区域
            .withStates()
                .parent(States.MAIN_SYSTEM)
                .initial(States.M_OFF)
                .state(States.M_ON)
                .and()
            // 配置子系统正交组:A、B、C各自独立
            .withStates()
                .parent(States.SUB_SYSTEMS)
                .initial(States.A_OFF)
                .state(States.A_ON)
                .and()
            .withStates()
                .parent(States.SUB_SYSTEMS)
                .initial(States.B_OFF)
                .state(States.B_ON)
                .and()
            .withStates()
                .parent(States.SUB_SYSTEMS)
                .initial(States.C_OFF)
                .state(States.C_ON)
                .and()
            // 根状态绑定两个正交区域
            .withStates().root().orthogonal(States.SUB_SYSTEMS, States.MAIN_SYSTEM);
    }

    @Override
    public void configure(StateMachineTransitionConfigurer<States, Events> transitions) throws Exception {
        // 子系统的off→on转换
        transitions
            .withExternal()
                .source(States.A_OFF).target(States.A_ON).event(Events.TURN_ON_A)
                .and()
            .withExternal()
                .source(States.B_OFF).target(States.B_ON).event(Events.TURN_ON_B)
                .and()
            .withExternal()
                .source(States.C_OFF).target(States.C_ON).event(Events.TURN_ON_C)
                .and()
            // 主状态M的转换:用守卫判断所有子系统是否就绪
            .withExternal()
                .source(States.M_OFF).target(States.M_ON)
                .guard(allSubsystemsOnGuard());
    }

    // 自定义守卫:检查A、B、C是否都处于ON状态
    @Bean
    public Guard<States, Events> allSubsystemsOnGuard() {
        return context -> {
            StateMachine<States, Events> stateMachine = context.getStateMachine();
            // 正交状态机的当前状态是所有活跃子状态的集合,直接检查是否包含三个ON状态
            return stateMachine.getState().getStates().containsAll(Arrays.asList(States.A_ON, States.B_ON, States.C_ON));
        };
    }
}

2.3 触发事件与验证状态

在业务代码里触发事件,同时可以加监听器验证主状态转换:

@Autowired
private StateMachine<States, Events> stateMachine;

// 触发A系统开启
public void activateSystemA() {
    stateMachine.sendEvent(Events.TURN_ON_A);
}

// 同理实现activateSystemB、activateSystemC

添加状态监听器,方便调试:

@Component
public class SystemStateListener extends StateMachineListenerAdapter<States, Events> {
    @Override
    public void stateChanged(State<States, Events> from, State<States, Events> to) {
        if (to.getStates().contains(States.M_ON)) {
            System.out.println("✅ 主状态M已切换至ON,所有子系统A/B/C均就绪!");
        }
    }
}

3. 常见坑点排查

  • 主状态没触发转换?先检查守卫逻辑:正交状态机的getState().getStates()会返回所有活跃子状态,确保你的枚举值和代码里的状态名完全一致
  • Papyrus模型和代码要对齐:比如正交区域的划分、状态名称必须和代码枚举一一对应,避免模型和代码脱节
  • 事件发送顺序不影响:不管先开哪个子系统,只要三个都到ON,SSM会在每次状态变更后自动检查守卫条件,触发M的转换

内容的提问来源于stack exchange,提问作者JD Williams

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 09:16:56