StateMachine 状态机机制深入解析

 更新时间:2019年08月22日 09:44:40   作者:梁桂钊  
这篇文章主要介绍了,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

前言

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • 详解Java内存溢出的几种情况

    详解Java内存溢出的几种情况

    这篇文章主要介绍了详解Java内存溢出的几种情况,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-06-06
  • SpringBoot对Controller进行单元测试的实现代码 附乱码解决方案

    SpringBoot对Controller进行单元测试的实现代码 附乱码解决方案

    这篇文章主要介绍了SpringBoot对Controller进行单元测试的实现代码 附乱码解决方案,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-04-04
  • java和Spring中观察者模式的应用详解

    java和Spring中观察者模式的应用详解

    这篇文章主要介绍了java和Spring中观察者模式的应用,,具有一定的参考价值,感兴趣的可以了解一下,希望能够给你带来帮助
    2021-10-10
  • Java8新特性之新日期时间库的使用教程

    Java8新特性之新日期时间库的使用教程

    这篇文章主要给大家介绍了关于Java8新特性之新日期时间库使用的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • JVM中-D、-X、-XX参数的区别

    JVM中-D、-X、-XX参数的区别

    本文主要介绍了JVM中-D、-X、-XX参数的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-06-06
  • Java经典面试题汇总:JVM

    Java经典面试题汇总:JVM

    本篇总结的是JVM相关的面试题,后续会持续更新,希望我的分享可以帮助到正在备战面试的实习生或者已经工作的同行,如果发现错误还望大家多多包涵,不吝赐教,谢谢
    2021-07-07
  • Gradle的SpringBoot项目构建图解

    Gradle的SpringBoot项目构建图解

    这篇文章主要介绍了Gradle的SpringBoot项目构建图解,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01
  • 深入浅析SpringBoot中的自动装配

    深入浅析SpringBoot中的自动装配

    SpringBoot的自动装配是拆箱即用的基础,也是微服务化的前提。接下来通过本文给大家介绍SpringBoot中的自动装配,感兴趣的朋友跟随脚本之家小编一起学习吧
    2018-05-05
  • idea报错:程序包org.springframework.web.bind.annotation不存在

    idea报错:程序包org.springframework.web.bind.annotation不存在

    在用本地的maven仓库的时候会org.springframework.web.bind.annotation不存在的错误,本文就详细的介绍一下解决方法,感兴趣的可以了解下
    2023-08-08
  • Java中从Integer到Date的转换方法

    Java中从Integer到Date的转换方法

    这篇文章主要介绍了Java中integer怎么转换date,在Java中,如果我们有一个Integer类型的数据,想要将其转换为Date类型,本文给大家介绍了实现方法,并通过代码示例讲解的非常详细,需要的朋友可以参考下
    2024-05-05

最新评论