Skip to content

Spring 状态机

依赖

xml
 <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>

      <dependency>
          <groupId>org.springframework.statemachine</groupId>
          <artifactId>spring-statemachine-data-redis</artifactId>
          <version>4.0.1</version>
      </dependency>

  </dependencies>

枚举类

状态枚举类 States

java
public enum States {
    SI, S1, S2
}

事件枚举类 Events

java
public enum Events {
    E1, E2
}

配置类

StateMachineExample01Config

java
@Configuration
@EnableStateMachine(name = "stateMachineExample01")
public class StateMachineExample01Config extends EnumStateMachineConfigurerAdapter<States, Events> {

    @Override
    public void configure(StateMachineConfigurationConfigurer<States, Events> config) throws Exception {
        // 配置状态机自动启动,同时设置了监听器,该监听器的作用用来监听状态的变化
        config.withConfiguration().autoStartup(true).listener(example01Listener());
    }

    @Override
    public void configure(StateMachineStateConfigurer<States, Events> states) throws Exception {
        // 定义了初始化状态,及所有的状态
        states.withStates().initial(States.SI).states(EnumSet.allOf(States.class));
    }

    @Override
    public void configure(StateMachineTransitionConfigurer<States, Events> transitions) throws Exception {
        // 配置状态的转换,如下面从SI状态转化到S1状态需要通过E1事件
        transitions
                .withExternal().source(States.SI).target(States.S1).event(Events.E1)
                .and()
                .withExternal().source(States.S1).target(States.S2).event(Events.E2);
    }

    // 监听程序,监听状态的改变
    @Bean
    StateMachineListener<States, Events> example01Listener() {
        return new StateMachineListenerAdapter<States, Events>() {
            @Override
            public void stateChanged(State<States, Events> from, State<States, Events> to) {
                System.out.println("Example01 状态切换至 " + to.getId());
            }
        };
    }
}

控制器类

Example01Controller

java
@RestController
@RequestMapping("/example01")
public class Example01Controller {

    //  这里指定了注入的bean名称,因为项目中你可以定义多个不同的状态机
    @Resource(name = "stateMachineExample01")
    private StateMachine<States, Events> stateMachine;

    @GetMapping("/s1")
    public Object changeToS1() {
        Message<Events> message = MessageBuilder.withPayload(Events.E1).build();
        stateMachine.sendEvent(Mono.just(message)).subscribe();
        return "将状态切换到 S1";
    }

    @GetMapping("/s2")
    public Object changeToS2() {
        Message<Events> message = MessageBuilder.withPayload(Events.E2).build();
        stateMachine.sendEvent(Mono.just(message)).subscribe();
        return "将状态切换到 S2";
    }

    // 查看当前的状态
    @GetMapping("/state")
    public Object getState() {
        State<States, Events> state = stateMachine.getState();
        return state.getId();
    }
}

进阶

为状态切换添加 Action

java
@Override
public void configure(StateMachineStateConfigurer<States, Events> states) throws Exception {
    states.withStates()
            .initial(States.SI) // 设置初始状态为 SI
            // 进入 S1 状态时触发(已到达 S1)
            .stateEntry(States.S1, context -> {
                System.out.printf("准备从 %s 状态转换到 %s%n", context.getSource().getId(), context.getTarget().getId());
            })
            // 处于 S1 状态时触发(已处于 S1)
            .state(States.S1, context -> {
                System.out.printf("状态从 %s 状态转换到 %s%n", context.getSource().getId(), context.getTarget().getId());
            })
            // 离开 S1 状态时触发(即将离开 S1)
            .stateExit(States.S1, context -> {
                System.out.printf("状态从 %s 状态转换到 %s%n", context.getSource().getId(), context.getTarget().getId());
            })
            // 处于 S2 状态时触发(已处于 S2)
            .state(States.S2, context -> {
                System.out.printf("状态从 %s 状态转换到 %s%n", context.getSource().getId(), context.getTarget().getId());
            });
}

输出结果

java
// 1.启动应用程序
Example01 状态切换至 SI

// 2.访问 /example01/s1
准备从 SI 状态转换到 S1
Example01 状态切换至 S1
状态从 SI 状态转换到 S1

// 3.访问 /example01/s2
状态从 S1 状态转换到 S2
Example01 状态切换至 S2
状态从 S1 状态转换到 S2

持久化

持久化配置 (redis)

java
@Configuration
public class StateMachinePersisterConfig {

    @Bean
    RedisStateMachinePersister<States, Events> repositoryStateMachinePersist(RedisConnectionFactory redisConnectionFactory) {
        RedisStateMachineContextRepository<States, Events> stateMachineContextRepository = new RedisStateMachineContextRepository<>(redisConnectionFactory);
        StateMachinePersist<States, Events, String> repositoryStateMachinePersist = new RepositoryStateMachinePersist<States, Events>(stateMachineContextRepository);
        return new RedisStateMachinePersister<States, Events>(repositoryStateMachinePersist);
    }

}

状态机配置

java
@Configuration
@EnableStateMachine(name = "stateMachineExample")
public class StateMachineExampleConfig extends EnumStateMachineConfigurerAdapter<States, Events> {

    @Resource
    private ApplicationContext context;

    @Resource
    private RedisStateMachinePersister<States, Events> repositoryStateMachinePersist;

    @Override
    public void configure(StateMachineConfigurationConfigurer<States, Events> config) throws Exception {
        config.withConfiguration().autoStartup(true).listener(exampleListener());
    }

    @Override
    public void configure(StateMachineStateConfigurer<States, Events> states) throws Exception {
        states.withStates().initial(States.SI).states(EnumSet.allOf(States.class));
    }

    @Override
    public void configure(StateMachineTransitionConfigurer<States, Events> transitions) throws Exception {
        transitions
                .withExternal().source(States.SI).target(States.S1).event(Events.E1)
                .and()
                .withExternal().source(States.S1).target(States.S2).event(Events.E2);
    }

    @Bean
    StateMachineListener<States, Events> exampleListener() {
        return new StateMachineListenerAdapter<States, Events>() {
            @Override
            public void stateChanged(State<States, Events> from, State<States, Events> to) {
                try {
                    //  初始状态不做保存,只有状态发生切换后,才进行持久化操作
                    if (from != null) {
                        repositoryStateMachinePersist.persist(
                                (StateMachine<States, Events>) context.getBean("stateMachineExample"),
                                "s000"
                        );
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
    }
}

数据恢复配置

java
@Component
public class StatePersistComponent {

    @Resource
    private RedisStateMachinePersister<States, Events> persist; // 状态机持久化工具(Redis

    @Resource(name = "stateMachineExample")
    private StateMachine<States, Events> stateMachineExample; // 状态机实例

    @PostConstruct
    public void init() {
        try {
            this.persist.restore(stateMachineExample, "s000"); // 从Redis恢复状态
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

多上下文

基于内存

java
@Bean(name = "memoryPersisiter")
static StateMachinePersister<States, Events, Object> getMemoryPersisiter() {
    return new DefaultStateMachinePersister<>(
            new StateMachinePersist<States, Events, Object>() {

                private Map<Object, StateMachineContext<States, Events>> map = new HashMap<>();

                @Override
                public void write(StateMachineContext<States, Events> context, Object contextObj) throws Exception {
                    log.info("持久状态机, context: {}, contextObj: {}", context, new ObjectMapper().writeValueAsString(contextObj));
                    map.put(contextObj, context);
                }

                @Override
                public StateMachineContext<States, Events> read(Object contextObj) throws Exception {
                    log.info("获取状态机, contextObj: {}", new ObjectMapper().writeValueAsString(contextObj));
                    StateMachineContext<States, Events> stateMachineContext = map.get(contextObj);
                    log.info("获取状态机结果, stateMachineContext: {}", new ObjectMapper().writeValueAsString(stateMachineContext));
                    return stateMachineContext;
                }
            }
    );
}
java
private void sendEvent(Message<Events> message, Object contextObj) {
    try {
        stateMachine.startReactively().block(); // 启动
        this.memoryPersisiter.restore(stateMachine, contextObj); // 恢复状态
        stateMachine.sendEvent(Mono.just(message)).blockLast(); // 发送事件
        this.memoryPersisiter.persist(stateMachine, contextObj); // 保存状态
    } catch (Exception e) {
        System.out.println(e.getMessage());
    } finally {
        stateMachine.stopReactively().block(); // 停止
    }
}

更新: 2025-07-18 13:20:32
原文: https://www.yuque.com/lsxxyg/sz/wps7g4guzdg2utyl