文章目录

  1. 1. 环境依赖
  2. 2. 状态和事件
    1. 2.1. 状态枚举
    2. 2.2. 事件枚举
  3. 3. 状态机配置
    1. 3.1. 初始化状态机状态
    2. 3.2. 初始化状态迁移事件
  4. 4. 状态监听器
  5. 5. 总结
  6. 6. 源代码

Spring StateMachine 让状态机结构更加层次化,可以帮助开发者简化状态机的开发过程。

之前,我们使用二维数组实现状态机机制,现在,我们来用 Spring StateMachine 进行改造。

环境依赖

修改 POM 文件,添加 spring-statemachine-core 依赖。

<dependency>
    <groupId>org.springframework.statemachine</groupId>
    <artifactId>spring-statemachine-core</artifactId>
    <version>1.2.0.RELEASE</version>
</dependency>

状态和事件

现在,我以用户注册为案例,来讲解状态和事件之间的状态机机制。

状态枚举

注册有哪些状态呢,我们来想想,应该有4个状态:未连接、已连接、注册中、已注册。

public enum RegStatusEnum {

    // 未连接
    UNCONNECTED,
    // 已连接
    CONNECTED,
    // 注册中
    REGISTERING,
    // 已注册
    REGISTERED;

}

事件枚举

相对应的,存在几个核心事件:连接、注册、注册成功、注册失败、注销。

public enum RegEventEnum {
    // 连接
    CONNECT,
    // 注册
    REGISTER,
    // 注册成功
    REGISTER_SUCCESS,
    // 注册失败
    REGISTER_FAILED,
    // 注销
    UN_REGISTER;
}

状态机配置

@Configuration
@EnableStateMachine
public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<RegStatusEnum, RegEventEnum> {

}

@EnableStateMachine注解,标识启用 Spring StateMachine 状态机功能。

初始化状态机状态

我们需要初始化状态机的状态。

@Override
public void configure(StateMachineStateConfigurer<RegStatusEnum, RegEventEnum> states) throws Exception {
    states.withStates()
    // 定义初始状态
    .initial(RegStatusEnum.UNCONNECTED)
    // 定义状态机状态
    .states(EnumSet.allOf(RegStatusEnum.class));
} 

其中,initial(RegStatusEnum.UNCONNECTED) 定义了初始状态是未连接状态。states(EnumSet.allOf(RegStatusEnum.class)) 定义了定义状态机中存在的所有状态。

初始化状态迁移事件

我们需要初始化当前状态机有哪些状态事件。

@Override
public void configure(StateMachineTransitionConfigurer<RegStatusEnum, RegEventEnum> transitions)
        throws Exception {
    transitions
        // 1.连接事件
        // 未连接 -> 已连接
        .withExternal()
            .source(RegStatusEnum.UNCONNECTED)
            .target(RegStatusEnum.CONNECTED)
            .event(RegEventEnum.CONNECT)
        .and()                     

        // 2.注册事件   
        // 已连接 -> 注册中
        .withExternal()
            .source(RegStatusEnum.CONNECTED)
            .target(RegStatusEnum.REGISTERING)
            .event(RegEventEnum.REGISTER)
        .and()

        // 3.注册成功事件   
        // 注册中 -> 已注册
        .withExternal()
            .source(RegStatusEnum.REGISTERING)
            .target(RegStatusEnum.REGISTERED)
            .event(RegEventEnum.REGISTER_SUCCESS)
        .and()

        // 5.注销事件
        // 已连接 -> 未连接
        .withExternal()
            .source(RegStatusEnum.CONNECTED)
            .target(RegStatusEnum.UNCONNECTED)
            .event(RegEventEnum.UN_REGISTER)
        .and()
        // 注册中 -> 未连接
        .withExternal()
            .source(RegStatusEnum.REGISTERING)
            .target(RegStatusEnum.UNCONNECTED)
            .event(RegEventEnum.UN_REGISTER)
        .and()
        // 已注册 -> 未连接
        .withExternal()
            .source(RegStatusEnum.REGISTERED)
            .target(RegStatusEnum.UNCONNECTED)
            .event(RegEventEnum.UN_REGISTER)
        ;
}

这里,我以连接事件为案例,其中 source 指定原始状态,target 指定目标状态,event 指定触发事件。

因此,下面的状态就很好理解了,即当发生连接事件时,从未连接状态变更为已连接状态。

// 未连接 -> 已连接
.withExternal()
    .source(RegStatusEnum.UNCONNECTED)
    .target(RegStatusEnum.CONNECTED)
    .event(RegEventEnum.CONNECT)

状态监听器

Spring StateMachine 提供了注解配置实现方式,所有 StateMachineListener 接口中定义的事件都能通过注解的方式来进行配置实现。

@WithStateMachine
public class StateMachineEventConfig {

    @OnTransition(source = "UNCONNECTED", target = "CONNECTED")
    public void connect() {
        System.out.println("///////////////////");
        System.out.println("连接事件, 未连接 -> 已连接");
        System.out.println("///////////////////");
    }

    @OnTransition(source = "CONNECTED", target = "REGISTERING")
    public void register() {
        System.out.println("///////////////////");
        System.out.println("注册事件, 已连接 -> 注册中");
        System.out.println("///////////////////");
    }

    @OnTransition(source = "REGISTERING", target = "REGISTERED")
    public void registerSuccess() {
        System.out.println("///////////////////");
        System.out.println("注册成功事件, 注册中 -> 已注册");
        System.out.println("///////////////////");
    }

    @OnTransition(source = "REGISTERED", target = "UNCONNECTED")
    public void unRegister() {
        System.out.println("///////////////////");
        System.out.println("注销事件, 已注册 -> 未连接");
        System.out.println("///////////////////");
    }
}

这里,我仍然以连接事件为案例,@OnTransition 中 source 指定原始状态,target 指定目标状态,当事件触发时将会被监听到从而调用 connect() 方法。

总结

Spring StateMachine 让状态机结构更加层次化,可以帮助开发者简化状态机的开发过程。

我们来回顾下几个核心步骤

  • 定义状态枚举。
  • 定义事件枚举。
  • 定义状态机配置,设置初始状态,以及状态与事件之间的关系。
  • 定义状态监听器,当状态变更时,触发方法。

源代码

相关示例完整代码: springboot-action

(完)

微信公众号

文章目录

  1. 1. 环境依赖
  2. 2. 状态和事件
    1. 2.1. 状态枚举
    2. 2.2. 事件枚举
  3. 3. 状态机配置
    1. 3.1. 初始化状态机状态
    2. 3.2. 初始化状态迁移事件
  4. 4. 状态监听器
  5. 5. 总结
  6. 6. 源代码