Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
社区首页 >专栏 >Cola-StateMachine状态机的实战使用

Cola-StateMachine状态机的实战使用

作者头像
政采云前端团队
发布于 2023-10-24 01:48:49
发布于 2023-10-24 01:48:49
6.4K01
代码可运行
举报
文章被收录于专栏:采云轩采云轩
运行总次数:1
代码可运行

前言

在电商领域,很多业务对象都是有状态的,且这些对象的状态又多又复杂。硬编码的方式已经不适合管理当前复杂业务对象的状态。为了适配复杂多变的业务,可以使用状态机来管理状态,统一定义业务对象状态和状态的流转。接下来,本文会重点介绍状态机相关的概念和使用场景。

定义

在介绍状态机之前,先介绍一个工作流(WorkFlow),初学者通常容易将两个概念混淆。工作流(WorkFlow),大体是指业务过程(整体或者部分)在计算机应用环境下的自动化,是对工作流程及其各操作步骤之间业务规则的描述。在计算机系统中,工作流属于计算机支持的协同工作(CSCW)的一部分。

状态机是工作流(WorkFlow)的一种类型,包括顺序工作流(Sequential)和状态机工作流(State Machine)。状态机是有限状态自动机的简称,是现实事物运行规则抽象而成的一个数学模型。

简单说明一下状态机和流程图这两个概念的区别。状态机用来描述一个特定对象的所有可能状态,以及由于各种事件的发生而引起的状态之间的转移。而流程图则用于表示完成某件事情中的各个活动过程,关键的是每一个步骤。

状态机(WorkFlow)

工作流(State Machine)

关注单个任务

关注状态流转

无循环

可以简单的实现循环

实现简单

比较麻烦,需要记录任务当前状态

串行表达,不是很灵活

表达更灵活

运行销量高

效率低,可并行

状态机选型

流程引擎易滥用,但状态机却实用且使用广泛,主要有以下两个原因:

  1. 实现。最简单、轻量的状态机用一个 Enum 就能实现,基本是零成本。
  2. 使用状态机的 DSL 来表达状态的流转,语义会更加清晰,会增强代码的可读性和可维护性。

然而,当业务场景比较复杂时,还是会超出 Enum 仅支持线性状态流转的范畴,因此不得不考虑一下开源状态机。

我着重看了两个状态机引擎的实现,一个是 Spring StateMachine,一个是 Squirrel StateMachine,他们的优点是功能很完备,缺点也是功能很完备。

就实际项目而言(其实大部分项目都是如此),实在不需要那么多状态机的高级玩法:比如状态的嵌套(Substate),状态的并行(Parallel,Fork,Join)、子状态机等等。

且开源状态机大多都是有状态的,使用分布式多线程来实现,无法做到线程安全,代码需要用到锁同步。每一次状态机在接收请求的时候,都不得不重新 Build 一个新的状态机实例,就导致开源状态机性能差。

优点

缺点

Spring StateMachine

1.强大的生命周期管理

1.学习曲线较陡峭

2.易于集成

2.可能增加项目复杂性

3.良好的文档和社区支持2

Squirrel StateMachine

1.轻量级

1.功能相对有限

2.简单易用

3.性能高效

Cola-StateMachine

1.高度可扩展

1.文档和社区支持相对较少

2.语义清晰、可读性强

3.线程安全

最终我选用了一个开源的状态机引擎 Cola-StateMachine。

Cola-StateMachine 简介

COLA 框架的状态机组件是一种小巧、无状态、简单、轻量、性能极高的状态机 DSL 实现,解决业务中的状态流转问题。

Cola-StateMachine 使用的是 Internal DSL 这样一种通用语言的特定用法,用这种 DSL 写出的程序有一种自定义语言的风格,与其所使用的宿主语言有所区别。Cola-StateMachine 使用 Java 实现,最简单,实现成本也最低,但是不支持“外部配置”。

Cola-StateMachine 中的核心概念:

  1. State : 状态
  2. Event:事件,状态由事件触发,引起变化
  3. Transtition:流转,表示从一个状态到另一个状态
  4. External Transititon:外部流转,两个不同状态之间的流转
  5. Interal Transtition:内部流转,同一个状态之间的流转
  6. Condition:条件,标识是否允许到达某个状态
  7. Action:动作,到达某个状态以后,可以做什么
  8. StateMachine:状态

Cola-statemachine 工作模式

Cola-StateMachine 核心代码

代码语言:javascript
代码运行次数:0
复制
builder.externalTransition()
  .from(States.STATE1)
  .to(States.STATE2)
  .on(Events.EVENT1)
  .when(checkCondition())
  .perform(doAction());

实践使用

使用场景

在设计电商系统订单模块时,订单会涉及各种状态以及状态与状态之间的流转,可扩展性、可维护性会是开发者关注的重点。

订单状态包括:初始化、待支付、待接单、待发货、待收货...

订单事件包括:创建订单、支付成功、接单、发货、取消订单...

需要考虑如下问题:

  1. 当订单状态增加时,如何尽可能少的改动或改动对历史影响不大?
  2. 如果在同一入口调用,每个事件的处理方法需要的入参都有所不同,如何处理?
  3. 有可能某个事件,在不同平台(买家端、卖家后台、管理平台)的处理逻辑也有些不同,如何处理?

因为订单涉及到很多状态的流转,我们选择使用状态机引擎来表达状态流转。因为状态机 DSL 带来的表达能力,相比较于 if-else 的代码,要更优雅更容易理解。另一方面,状态机很简单,不像流程引擎那么华而不实。

1.引入依赖

第一步:引入依赖

代码语言:javascript
代码运行次数:0
复制
  <dependency>
    <groupId>com.alibaba.cola</groupId>
    <artifactId>cola-component-statemachine</artifactId>
    <version>4.2.1</version>
  </dependency>
2.订单基本配置

第二步:定义状态机中基础属性:状态、时间、状态机。在本次实践中使用 OrderStatusEnum 定义订单状态,使用 OrderEventParam定义订单事件,使用 OrderStateMachineIdEnum 定义状态机。

代码语言:javascript
代码运行次数:0
复制
  //订单状态
  public enum OrderStatusEnum {
    INIT("初始化", 0),
    PAY_ONLINE("待支付", 1),
    WAITING_FOR_RECEIVED("待接单", 2),
    WAITING_DELIVERY("待发货", 3),
    PART_DELIVERY("部分发货", 4),
    DELIVER_ALL("待收货", 5),
    RECEIVED("已收货", 6),
    DONE("已完成", 7),
    CANCEL("已关闭", 8);
  }

  //订单事件
  public enum OrderEventEnum {
    CREATE_ORDER(1, "创建订单"),
    REPAY(2, "支付"),
    CANCEL_ORDER(3, "取消订单"),
    TAKE_ORDER(4, "接单"),
    REJECT_ORDER(5, "拒单"), 
    DELIVERY_PART(6, "部分发货"),
    DELIVERY_ALL(7, "全部发货"),
    CONFIRM_RECEIPT(8, "确认收货"),
    EXTEND_RECEIPT(9, "延长收货"),
    COMPLETE(10, "交易完成");
  }

  //订单状态机ID 枚举
  public enum OrderStateMachineIdEnum {
    ORDER_OF_SALE("ORDER_OF_SALE",
    OrderBizEnum.SALE_ORDER, "订单状态机");
  }
3.订单流转状态机

第三步:定义订单状态流转事件。具体使用 Builder 和 Fluent Interface 的方式,确保代码调用的顺序。比如,在 From 的后面只能调用To,从而保证了状态机构建的语义正确性和连贯性。我们使用状态机 Builder,确认状态流转模式(Transition),接收状态(From),定义动作(On),检查条件(When),执行事件(Perform),然后返回目标状态(To)。

当有新订单事件的增加时,在此状态机中增加相应事件即可,同时维护好订单事件与事件实现方法之间的关系。

代码语言:javascript
代码运行次数:0
复制
  public class OrderOfSaleStateMachine implements OrderStateMachine {
    public void initialize() {

       //对状态机开始构建,并在StateMachineFactory中注册
       StateMachineBuilder<OrderStatusEnum, OrderEventEnum, OrderContext> builder
       = StateMachineBuilderFactory.create();

       /**
       * 创建订单: 初始化 -> 待支付
       * externalTransition : 用于一个流转的构建器
       */
       builder.externalTransition().from(OrderStatusEnum.INIT).to(OrderStatusEnum.PAY_ONLINE)
       .on(OrderEventEnum.CREATE_ORDER).when(checkOrder()).perform(createOrderAction);

       /**
       * 部分发货: 部分发货
       * internalTransition : 内部流转
       */
       builder.internalTransition()
       .within(OrderStatusEnum.PART_DELIVERY)
       .on(OrderEventEnum.DELIVERY_PART)
       .when(checkOrder())
       .perform(deliverOrderAction);

       /**
       * 取消订单: 待支付、待发货、待收货 -> 待支付
       * externalTransitions : 用于多个流转的构建器
       */
       builder.externalTransitions()
       .fromAmong(OrderStatusEnum.PAY_ONLINE,OrderStatusEnum.WAITING_FOR_RECEIVED,                                      OrderStatusEnum.WAITING_DELIVERY)
       .to(OrderStatusEnum.CANCEL)
       .on(OrderEventEnum.CANCEL_ORDER)
       .when(checkOrder())
       .perform(cancelOrderAction);


       // 说明:cola statemachine 构建后,会自动 StateMachineFactory 注册。
       // 构建成功后根据 StateMachineFactory.get(machineId) 获取状态机,不允许重复构建,重复构建会报错。
       builder.build(this.getStateMachineIdEnum().getMachineId());
    }

    @Override
    public OrderStateMachineIdEnum getStateMachineIdEnum() {
        return OrderStateMachineIdEnum.ORDER_OF_SALE;
    }
4.单个起始状态-外部状态流转
代码语言:javascript
代码运行次数:0
复制
  /*
   * 设置一个外部状态转义类型的builder,并设置from\to\on\when\perform
   */
  builder.externalTransition()
    .from(OrderStatusEnum.INIT)
    .to(OrderStatusEnum.PAY_ONLINE)
    .on(OrderEventEnum.CREATE_ORDER)
    .when(checkOrder())
    .perform(createOrderAction);

描述:订单起始状态为“初始化”,当发生“创建订单”事件执行状态转义,当满足 CheckCondition 时,执行 CreateOrderAction。

代码语言:javascript
代码运行次数:0
复制
  public class CreateOrderAction implements Action<OrderStatusEnum, OrderEventEnum, OrderContext> {
    @Override
    public void execute(OrderStatusEnum from, OrderStatusEnum to, OrderEventEnum event, OrderContext context) {
      // ...
      // 1.获取状态机
      StateMachine<OrderStatusEnum, OrderEventEnum, OrderContext> stateMachine = getStateMachine();
      // 2.组状态机 messageContext
      OrderContext orderContext = buildContext();
      // 3.状态机事件触发
      stateMachine.fireEvent(OrderStatusEnum.INIT, OrderEventEnum.CREATE_ORDER, orderContext);
      // ...
    }
  }

描述:CreateOrderAction 实现创建订单事件,通过 StateMachine.FireEvent 触发状态机事件。

5. 内部状态流转
代码语言:javascript
代码运行次数:0
复制
  /**
   * 部分发货: 部分发货
   * internalTransition : 内部流转
   */
  builder.internalTransition()
    .within(OrderStatusEnum.PART_DELIVERY)
    .on(OrderEventEnum.DELIVERY_PART)
    .when(checkOrder())
    .perform(deliverOrderAction);

描述:订单起始状态发生在部分发货状态下,当发生发货时执行状态流转,当满足 CheckCondition(订单部分发货条件)时,执行DeliverOrderAction,执行成功则返回状态:部分发货

6. 多个起始状态-外部状态流转
代码语言:javascript
代码运行次数:0
复制
  /**
   * 取消订单: 待支付、待发货、待收货 -> 待支付
   * externalTransitions : 用于多个流转的构建器
   */
  builder.externalTransitions()
    .fromAmong(OrderStatusEnum.PAY_ONLINE,OrderStatusEnum.WAITING_FOR_RECEIVED,OrderStatusEnum.WAITING_DELIVERY)
    .to(OrderStatusEnum.CANCEL)
    .on(OrderEventEnum.CANCEL_ORDER)
    .when(checkOrder())
    .perform(cancelOrderAction);

描述:订单起始状态为:待支付、待发货或待收货下,当发生取消订单事件时,当满足 CheckCondition 时,执行 CancelOrderAction,返回状态 CANCEL_ORDER。

小结

Cola-StateMachine 作为阿里开源项目 COLA 中的轻量级状态机组件,最大的特点就是无状态、采用纯 Java 实现,用 Fluent Interface (连贯接口)定义状态和事件,可用于管理状态转换场景。比如:订单状态、支付状态等简单有限状态场景。

参考文献

https://blog.csdn.net/significantfrank/article/details/104996419

https://www.jianshu.com/p/895047a04ae5

https://blog.csdn.net/qq_28959087/article/details/118359809

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-10-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 政采云技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
聊聊Cola-StateMachine轻量级状态机的实现
在分析Seata的saga模式实现时,实在是被其复杂的 json 状态语言定义文件劝退,我是有点没想明白为啥要用这么来实现状态机;盲猜可能是基于可视化的状态机设计器来定制化流程,更方便快捷且上手快吧,毕竟可以通过UI直接操作,设计状态流转图,但我暂时不太能get到。对于Saga模式的实现,之前的博文中已经阐述了基于状态机模式实现Saga,是比较常见且合适的做法,因此了解了下Java中的状态机实现方案,以后有相关的业务场景也可以直接上手使用状态机。
Ryan_OVO
2023/10/19
1K0
聊聊Cola-StateMachine轻量级状态机的实现
管理订单状态,该上状态机吗?轻量级状态机COLA StateMachine保姆级入门教程
在平常的后端项目开发中,状态机模式的使用其实没有大家想象中那么常见,笔者之前由于不在电商领域工作,很少在业务代码中用状态机来管理各种状态,一般都是手动get/set状态值。去年笔者进入了电商领域从事后端开发。电商领域,状态又多又复杂,如果仍然在业务代码中东一块西一块维护状态值,很容易陷入出了问题难于Debug,难于追责的窘境。
蛮三刀酱
2022/06/01
3.5K0
github上fork2.4k,star8.7k的这款状态机,原来长这样!
上一篇文章《关于状态机的技术选型,最后一个真心好》我跟大家聊了一下关于”状态机“的话题。从众多技术选型中我也推荐了一款阿里开源的状态机—“cola-statemachine”。
陶朱公Boy
2023/01/07
1K0
github上fork2.4k,star8.7k的这款状态机,原来长这样!
关于状态机的技术选型,最后一个真心好!
今天想跟大家分享一个关于“状态机”的话题。状态属性在我们的现实生活中无处不在。比如电商场景会有一系列的订单状态(待支付、待发货、已发货、超时、关闭);员工提交请假申请会有申请状态(已申请、审核中、审核成功、审核拒绝、结束);差旅报销单会有单据审核状态(已提交、审核中、审核成功、退回、打款中、打款成功、打款失败、结束)等等。
陶朱公Boy
2023/01/07
3K0
关于状态机的技术选型,最后一个真心好!
Spring-statemachine实现订单状态机
每次用到的时候新创建一个状态机,太奢侈了,官方文档里面也提到过这点。而且创建出来的实例,其状态也跟当前订单的不符;spring statemachine暂时不支持每次创建时指定当前状态,所以对状态机引擎实例的持久化,就成了必须要考虑的问题。
才疏学浅的木子
2023/10/17
1K0
状态机引擎在vivo营销自动化中的深度实践 | 引擎篇02
营销自动化平台支持多种不同类型运营活动策略(比如:短信推送策略、微信图文推送策略、App Push推送策略),每种活动类型都有各自不同的执行流程和活动状态。比如短信活动的活动执行流程如下:
2020labs小助手
2022/04/11
1.1K0
状态机引擎在vivo营销自动化中的深度实践 | 引擎篇02
彻底搞懂Spring状态机原理,实现订单与物流解耦
当我们在社区阅读文章时,如果觉得文章写得很好,我们就会评论、收藏两连发。如果处于登录情况下,则可以直接做评论、收藏这些行为。否则,跳转到登录界面,登录后再继续执行先前的动作。这里涉及的状态有两种:登录与未登录;行为有两种:评论和收藏。下面使用状态模式来实现这个逻辑,代码如下。
Tom弹架构
2021/11/16
1.7K0
COLA-statemachine事务失效踩坑
cola-statemachine是阿里开源项目COLA (opens new window)中的轻量级状态机组件。最大的特点是无状态、采用纯Java实现,用Fluent Interface(连贯接口)定义状态和事件,可用于管理状态转换场景。比如:订单状态、支付状态等简单有限状态场景。在实际使用的过程中我曾发现状态机内事务不生效的问题,经过排查得到解决,以此记录一下。
benym
2023/05/18
1.3K0
COLA-statemachine事务失效踩坑
Spring Statemachine的应用
在开发中总会遇到这样的场景,比如工单状态,流程状态,通过状态判断该执行的操作,不断改动的需求导致永无止境的 IF、ELSE 和 BREAK 子句的层次结构,当事情开始看起来太复杂时,简直就像面满池子的海洋球。
张云飞Vir
2023/05/01
8050
状态机
下面的内容基于https://github.com/alibaba/COLA。COLA 是 Clean Object-Oriented and Layered Architecture的缩写,代表“整洁面向对象分层架构”。目前COLA已经发展到COLA v4。
路行的亚洲
2023/02/28
1.2K0
状态机
项目终于用上了Spring状态机,非常优雅!
先来解释什么是“状态”( State )。现实事物是有不同状态的,例如一个自动门,就有 open 和 closed 两种状态。我们通常所说的状态机是有限状态机,也就是被描述的事物的状态的数量是有限个,例如自动门的状态就是两个 open 和 closed 。
终码一生
2023/08/22
7980
项目终于用上了Spring状态机,非常优雅!
使用Spring StateMachine框架实现状态机
Spring StateMachine框架可能对于大部分使用Spring的开发者来说还比较生僻,该框架目前差不多也才刚满一岁多。它的主要功能是帮助开发者简化状态机的开发过程,让状态机结构更加层次化。前几天刚刚发布了它的第三个Release版本1.2.0,其中增加了对Spring Boot的自动化配置,既然一直在写Spring Boot的教程,所以干脆就将该内容也纳入进来吧,希望对有需求的小伙伴有一定的帮助。 快速入门 依照之前的风格,我们通过一个简单的示例来对Spring StateMachine有一个初步
程序猿DD
2018/02/01
3K0
使用Spring StateMachine框架实现状态机
COLA-statemachine在多级审核业务中的实践
在实际的项目开发中,开发者经常会遇见类似多级审核之类的开发需求,比如某个文件审核,需要经过申请->直系领导审核->总经理审核等多个步骤。如果是一次动作触发整个审核过程,开发者可能会想到使用责任链模式来进行开发。但如果多级审核的间隔时间长,审核触发的条件不一样,责任链模式会不太能够解耦这项需求。如果采用平铺直叙式开发,无疑会将审核状态转移过程散落在系统间各个位置,前后两个状态之间的关系没有直观进行维护,同时状态转移时的条件、执行的方式和状态之间的逻辑关系很容易让开发者写出“面条代码”。在项目开发初期可能还好,随着需求的增量变化,平铺直叙式开发将使得状态转移逻辑和业务逻辑高度混合,且每增加一级节点审核,就要新增对应的审核状态及状态转移的逻辑,长此以往变得难以阅读和维护。所以,在这种情况下使用状态机这样建模方式就显得尤为必要。
benym
2023/10/18
1.4K1
COLA-statemachine在多级审核业务中的实践
状态机的基本原理以及SSM实践
“状态” 算是 人们对事物一个很基本的抽象理解了,在现实世界里,“状态” 无时无刻不体现在我们的生活和工作之中;现实中客观存在的事物,我们总可以给它定义出几个状态来。 而在软件领域,也很早就形成了基于状态的行为模型范式,即 有限状态机(Finite-State Machine)。 本文将 结合状态机的实现框架Spring State Machine (aka. SSM, 下面的内容将直接使用此简称),介绍下状态机的基本原理,以及在实践中遇到的一些坑。
亦山
2022/05/11
1.5K0
状态机的基本原理以及SSM实践
自己动手造一个状态机
有限自动状态机 (Finite-state machine , FSM) 通常用来描述某个具有有限个状态的对象,并且在对象的生命周期中组成了一个状态序列,通过响应外界各种事件完成状态流转。
大忽悠爱学习
2024/01/13
4430
自己动手造一个状态机
设计模式如何提升 vivo 营销自动化业务扩展性 | 引擎篇01
在《vivo 营销自动化技术解密 |开篇》中,我们从整体上介绍了vivo营销自动化平台的业务架构、核心业务模块功能、系统架构和几大核心技术设计。
2020labs小助手
2021/10/11
6830
设计模式如何提升 vivo 营销自动化业务扩展性 | 引擎篇01
状态机的设计与实现
好久没有写博客进行输出了,是时候需要水一篇了,嘻嘻。 正好项目中使用了状态机,也借此分享一下系统中状态机的项目落地经验。
CBeann
2023/12/25
3670
状态机的设计与实现
Spring状态机
有限状态机简称就是状态机,因为一般的状态机的状态都是离散和可举的,即为有限,所以后面的介绍都不加有限二字。状态机表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。通俗的描述状态机就是定义了一套状态変更的流程:状态机包含一个状态集合,定义当状态机处于某一个状态的时候它所能接收的事件以及可执行的行为,执行完成后,状态机所处的状态。所以状态机会包含以下几个重要的元素:
算法之名
2020/06/02
1.8K0
yarn中的事件分发与状态机框架
在早之前的文章《YARN——任务提交启动流程》中提到了,其处理逻辑是围绕applicaiton、container、attempt实例对象的创建,各自状态机的变化来实现的。
陈猿解码
2023/02/28
7740
yarn中的事件分发与状态机框架
精妙设计:支付系统状态机与核心代码实现
本篇主要讲清楚什么是状态机,简洁的状态机对支付系统的重要性,状态机设计常见误区,以及如何设计出简洁而精妙的状态机,核心的状态机代码实现等。
路人甲Java
2024/02/01
2.6K0
精妙设计:支付系统状态机与核心代码实现
推荐阅读
相关推荐
聊聊Cola-StateMachine轻量级状态机的实现
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验