聊聊Cola-StateMachine轻量级状态机的实现
2023-06-07 14:10:17 来源:博客园
背景

在分析Seata的saga模式实现时,实在是被其复杂的 json 状态语言定义文件劝退,我是有点没想明白为啥要用这么来实现状态机;盲猜可能是基于可视化的状态机设计器来定制化流程,更方便快捷且上手快吧,毕竟可以通过UI直接操作,设计状态流转图,但我暂时不太能get到。对于Saga模式的实现,之前的博文中已经阐述了基于状态机模式实现Saga,是比较常见且合适的做法,因此了解了下Java中的状态机实现方案,以后有相关的业务场景也可以直接上手使用状态机。


(资料图)

Cola-StateMachine

Cola-StateMachine组件是一种轻量级的、无状态的、基于注解的状态机实现,可以方便地管理订单等业务对象的状态转换。COLA框架的状态机使用了连贯接口(Fluent Interfaces)来定义状态和事件,以及对应的动作和检查。COLA框架的状态机是COLA 4.0应用架构的一部分,旨在控制复杂度,提高开发效率。开发背景可见实现一个状态机引擎,教你看清DSL的本质。

基础模型

在Cola-StateMachine组件中有如下的抽象概念模型:

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

Cola-StateMachine链路图业务应用示例

基于订单业务的场景,做一个简单的demo。

关闭订单的简单流程图

关闭订单简单的状态流转图

添加依赖

    com.alibaba.cola    cola-component-statemachine    4.3.1

定义一个订单的实体类、订单状态的枚举值、订单事件的枚举值

@Data@Builderpublic class Order {    public OrderStatusEnum orderStatusEnum;    public Integer orderId;    public String orderName;}public enum OrderStatusEnum {    INIT("0", "待付款"),    WAITING_FOR_DELIVERY("1", "待发货"),    HAVE_BEEN_DELIVERY("2", "已发货"),    CLOSE("3", "已取消");    private final String code;    private final String info;    OrderStatusEnum(String code, String info)    {        this.code = code;        this.info = info;    }    public String getCode()    {        return code;    }    public String getInfo()    {        return info;    }}public enum OrderEvent {    /**     * 用户关闭     */    USER_CLOSE("0", "用户取消"),    /**     * 管理员关闭     */    ADMIN_CLOSE("1", "后台取消"),    /**     * 超时关闭     */    OVERTIME_CLOSE("2", "超时取消"),    /**     * 检查错误关闭     */    CHECK_ERROR_CLOSE("3", "上级审核取消"),    /**     * 用户付费     */    USER_PAY("4", "用户支付");    /**     * 密码     */    private final String code;    /**     * 信息     */    private final String info;    /**     * 订单事件     *     * @param code 密码     * @param info 信息     */    OrderEvent(String code, String info) {        this.code = code;        this.info = info;    }    /**     * 获取代码     *     * @return {@link String}     */    public String getCode() {        return code;    }    /**     * 获取信息     *     * @return {@link String}     */    public String getInfo() {        return info;    }}

在容器启动的时候注册一个订单状态变更的工厂

@Componentpublic class StateMachineBuilderConfig {    @Autowired    UserCloseAction userCloseAction;    @Bean("orderOperaMachine")    public StateMachine orderOperaMachine() {        String ORDER_OPERA = "order_opera";        StateMachineBuilder builder = StateMachineBuilderFactory.create();        //订单从初始化状态-待发货-状态-转到-关闭订单状态--用户关闭        builder.externalTransitions()                .fromAmong(OrderStatusEnum.INIT, OrderStatusEnum.WAITING_FOR_DELIVERY)                .to(OrderStatusEnum.CLOSE)                .on(OrderEvent.USER_CLOSE)                .when(checkCondition())                .perform(userCloseAction);        //订单从-初始化状态-已发货-待发货--转到-关闭订单状态--后台操作人员关闭        builder.externalTransitions()                .fromAmong(OrderStatusEnum.INIT, OrderStatusEnum.HAVE_BEEN_DELIVERY, OrderStatusEnum.WAITING_FOR_DELIVERY)                .to(OrderStatusEnum.CLOSE)                .on(OrderEvent.ADMIN_CLOSE)                .when(checkCondition())                .perform(doAction());        //订单从等待发货状态-转为-订单关闭状态-超时关闭        builder.externalTransition()                .from(OrderStatusEnum.WAITING_FOR_DELIVERY)                .to(OrderStatusEnum.CLOSE)                .on(OrderEvent.OVERTIME_CLOSE)                .when(checkCondition())                .perform(doAction());        //订单从待发货状态--转为-订单关闭状态-上级审批不通过关闭        builder.externalTransition()                .from(OrderStatusEnum.WAITING_FOR_DELIVERY)                .to(OrderStatusEnum.CLOSE)                .on(OrderEvent.CHECK_ERROR_CLOSE)                .when(checkCondition())                .perform(doAction());        //订单从初始化状态--转为待发货状态--用户支付完毕动        builder.externalTransition()                .from(OrderStatusEnum.INIT)                .to(OrderStatusEnum.WAITING_FOR_DELIVERY)                .on(OrderEvent.USER_PAY)                .when(checkCondition())                .perform(doAction());        StateMachine orderOperaMachine = builder.build(ORDER_OPERA);        //打印uml图        String plantUML = orderOperaMachine.generatePlantUML();        System.out.println(plantUML);        return orderOperaMachine;    }    private Condition checkCondition() {        return (ctx) -> {            return true;        };    }    private Action doAction() {        return (from, to, event, ctx) -> {            System.out.println(ctx.getOrderName() + " 正在操作 " + ctx.getOrderId() + " from:" + from + " to:" + to + " on:" + event);        };    }}

在定义一个特殊的,只是举个例子,可以通过集成的方式集成实现一个用户关单的具体操作

@Componentpublic class UserCloseAction implements Action {    @Override    public void execute(OrderStatusEnum from, OrderStatusEnum to, OrderEvent event, Order context) {        System.out.println("用户关闭流程开始走了");        System.out.println("从这个状态-【" + from.getInfo() + "】-转为+【" + to.getInfo() + "】 的状态");        System.out.println("上下文信息:" + context.toString());        System.out.println("中间执行的一些操作.......");        System.out.println("用户关闭流程完毕了");    }}

定义一个 controller 的操作接口

@RestControllerpublic class OrderOperaController {    @Autowired    @Qualifier("orderOperaMachine")    StateMachine orderOperaMachine;    /**     * 场景1-用户关闭订单     *     * @return {@link Boolean}     */    @RequestMapping("userclose")    public Boolean userCloseOrder() {        //把订单状态改为关闭        String machineId = orderOperaMachine.getMachineId();        System.out.println(machineId);        Order order = Order.builder().orderId(1).orderName("用户").orderStatusEnum(OrderStatusEnum.INIT).build();        OrderStatusEnum orderStatusEnum = orderOperaMachine.fireEvent(OrderStatusEnum.INIT,OrderEvent.USER_CLOSE, order);        System.out.println(orderStatusEnum.toString());        return true;    }    /**     * 场景2-管理员关闭订单     *     * @return {@link Boolean}     */    @RequestMapping("adminClose")    public Boolean adminCloseOrder() {        //把订单状态改为关闭        Order order = Order.builder().orderId(1).orderName("后台操作人员").orderStatusEnum(OrderStatusEnum.HAVE_BEEN_DELIVERY).build();        OrderStatusEnum orderStatusEnum = orderOperaMachine.fireEvent(OrderStatusEnum.HAVE_BEEN_DELIVERY, OrderEvent.ADMIN_CLOSE, order);        System.out.println(orderStatusEnum.toString());        return true;    }    /**     * 场景3-超时关闭订单     *     * @return {@link Boolean}     */    @RequestMapping("overTimeclose")    public Boolean overTimeCloseOrder() {        //把订单状态改为关闭        Order order = Order.builder().orderId(1).orderName("超时了关闭订单")                .orderStatusEnum(OrderStatusEnum.WAITING_FOR_DELIVERY).build();        //OrderStatusEnum orderStatusEnum = orderOperaMachine.fireEvent(OrderStatusEnum.CLOSE, OrderEvent.OVERTIME_CLOSE, order);        OrderStatusEnum orderStatusEnum = orderOperaMachine.fireEvent(OrderStatusEnum.WAITING_FOR_DELIVERY, OrderEvent.OVERTIME_CLOSE, order);        System.out.println(orderStatusEnum.toString());        return true;    }    /**     * 场景4-检查错误关闭订单     *     * @return {@link Boolean}     */    @RequestMapping("checkErrorClose")    public Boolean checkErrorCloseOrder() {        //把订单状态改为关闭        Order order = Order.builder().orderId(1).orderName("上级检查错误").orderStatusEnum(OrderStatusEnum.WAITING_FOR_DELIVERY).build();        OrderStatusEnum orderStatusEnum = orderOperaMachine.fireEvent(OrderStatusEnum.WAITING_FOR_DELIVERY, OrderEvent.CHECK_ERROR_CLOSE, order);        System.out.println(orderStatusEnum.toString());        return true;    }}

启动程序

安装UML

随便新建一个uml文件,然后将启动程序的控制台输出内容复制到uml中

最后运行下

聊聊Cola-StateMachine轻量级状态机的实现

2023-06-07

10名中国选手赌球被禁赛,中国台球协会回应

2023-06-07

6月6日中国汽、柴油平均批发价格分别为8788、7539元/吨

2023-06-07

环球速读:陈泓在调研“三夏”生产、秸秆禁烧、防汛工作时强调:千方百计克服困难 确保粮食应收尽收

2023-06-07

今日关注:广发证券:看好游戏板块基本面持续向上的趋势

2023-06-07

澳大利亚今年一季度国内生产总值环比增长0.2%|全球快讯

2023-06-07

京冀“两市三区”突发水环境事件联合应急演练举办

2023-06-07

今日视点:限时优享价6.19万元起 第4代帝豪2023冠军款上市

2023-06-07

多面体外接球万能公式_多面体

2023-06-07

原谅色是什么颜色?_原谅色是什么颜色为什么绿色叫做原谅色-全球讯息

2023-06-07

中基健康(000972.SZ):拟通过司法拍卖方式摘牌购置新光油脂固定资产 热消息

2023-06-07

高考期间北京送考车辆不受尾号限行限制 环球速递

2023-06-07

男子驾驶面包车撞伤9人逃跑 已被警方抓获

2023-06-07

时代中国前5个月合同销售额近84亿元

2023-06-07

海贼王之最强霸气系统_海贼王霸气有几种-简讯

2023-06-07

全球今日讯!为促进学生全面发展 今年将启动基础教育课程教学深化改革

2023-06-07

网页qq登陆方法_如何登陆webqq网页版

2023-06-07

醉逍遥_蜀门

2023-06-07

蜜雪冰城公司总部的企业名称是什么?(蜜雪冰城企业总部名称叫什么)

2023-06-07

魔兽世界怀旧服牧师武器选择什么_魔兽世界怀旧服牧师武器选择

2023-06-07

哈密瓜用放冰箱冷藏保鲜吗

2023-06-07

微信隐私保护指引更新是怎么回事_微信隐私保护指引

2023-06-07

磁盘分区无法合并_合并磁盘分区时对象不支持此操作

2023-06-07

变形计胡政尧在线观看_手机上怎么看不了变形计胡政尧那一集

2023-06-07

美股异动 | 诺和诺德涨超2% 拟以1.54亿欧元收购Biocorp

2023-06-07

今亮点!“诚信高考”让青春无悔绽放

2023-06-07

苹果首发MR,国内Micro OLED股价反响不及从业者兴奋-头条

2023-06-07

头条:普力马发动机号位置_普力马发动机

2023-06-06

精选!Truist:下调西方石油(OXY.US)目标价至82美元 维持“买入”评级

2023-06-06

@金山人,您的餐食可以在线看到制作过程了! 视点

2023-06-06

环球百事通!哪些关于劝告的古诗 4. 关于豁达对待离别的诗句

2023-06-06

汉滨区关家镇幼儿园志愿服务队_关于汉滨区关家镇幼儿园志愿服务队简述

2023-06-06

复利3.5增额终身寿险相当于单利多少?从定义、区别和举例分析

2023-06-06

天天简讯:“少井高产”!我国特高含硫气田开发技术实现新突破

2023-06-06

古树普洱茶品牌排名前十_古树普洱茶品牌|每日速递

2023-06-06

大都会风格是什么意思_什么是大都会风格建筑

2023-06-06

小学作业不回家!青羊区责任督学赴实小青华进行专项督导|环球要闻

2023-06-06

环球观焦点:韩方称中方不应只重视朝鲜正当安全关切也应考虑韩国 中方回应

2023-06-06

世界消息!中国台币是什么样的(1000台币是什么样的)

2023-06-06

梦中的那片海完整版歌词是什么 速讯

2023-06-06

每日热文:美国公寓倒塌事故致3人死亡 居民起诉当地政府:未发出风险警告

2023-06-06

焦点讯息:Apple Vision Pro:不负One more thing,库克时代最为浓墨重彩的标记

2023-06-06

世界热资讯!取代iPhone,苹果智能眼镜正式发布,真的太酷了,就是有点贵!

2023-06-06

天天观点:又一环保企业入局新能源领域 拟3亿设子公司开展储能等相关业务

2023-06-06

热门看点:文商旅“流量”如何变“留量”

2023-06-06

土耳其首都什么时候迁到安卡拉(土耳其首都是安卡拉还是伊斯坦布尔)

2023-06-06

共和报:特奥可能考虑转会,队内多人不满马尔蒂尼被炒_全球微速讯

2023-06-06

最新:“帮忙资金”不管了 迷你基金保壳更难了

2023-06-06

dnf狂战100级加点(怎么加点)|每日视点

2023-06-06

世界速读:角的公式怎么算(角公式是什么意思)

2023-06-06

田径亚青赛第二日:中国队收获4金2银1铜-世界聚看点

2023-06-06

先兆流产和痛经 焦点速递

2023-06-06

[DR2C] 统计数据 之加拿大死亡之路-全球报资讯

2023-06-06

微速讯:北交所新三板出台“十八条”优化市场服务

2023-06-06

颍上县安排部署预防青少年儿童溺水工作|独家焦点

2023-06-06

最好用的短线指标_短线指标

2023-06-06

无序之主_关于无序之主介绍

2023-06-06

祈风石刻群

2023-06-05

杉杉品牌(01749):沈金鑫获任非执行董事

2023-06-05

天天快看点丨晋江 怎样在晋江写好小说 如何在网站注册成为一个新作者?

2023-06-05

中建二局三公司:打响防汛新攻势 全力筑牢安全防线

2023-06-05

国家开发银行上海市分行原党委书记、行长茆君才被查-资讯推荐

2023-06-05

热头条丨台风“玛娃”已造成日本2死35伤 救援和搜救行动仍在进行中

2023-06-05

官方声明!这类“志愿者”招募不可信 全球快播报

2023-06-05

这所学校曾因“老鼠事件”被联合执法!记者实地调查→

2023-06-05

3岁儿子被拐,爸爸抑郁自杀,妈妈寻子25年后发现:儿子竟是自己的好友!

2023-06-05

天天百事通!特发信息:公司将持续跟进超算、智算等算力基础设施项目,争取更多的业务机会

2023-06-05

微动态丨永太科技收年报问询函:是否存在资金压力或流动性风险

2023-06-05

6月第1周正定人气小区榜出炉,这些小区优秀了!

2023-06-05

天天新资讯:特色产业为媒 农文旅融合激活乡村“瓜果经济”

2023-06-05

世界看热讯:足浴店及时纠正错误行为 市卫健委发出首张不予行政处罚决定书​

2023-06-05

全球今热点:2023天津滨海新区大港高考考点汇总

2023-06-05

神界原罪2全流程攻略——A027,命运之至

2023-06-05

6月5日 11:00分 众智科技(301361)股价快速拉升_世界快资讯

2023-06-05

浙商证券孙建:拥抱新周期 天天聚看点

2023-06-05

天天即时看!提升审计整改成效的六个重要举措

2023-06-05

曹操和貂蝉有没有在一起过(曹操和貂蝉)-每日速看

2023-06-05

中钞国鼎基准银价今天多少一克(2023年06月04日)

2023-06-05

361官方旗舰店男鞋_361官方旗舰店_当前热讯

2023-06-05

人造电子皮肤破损后可自行修复,有望造出有类似人类触觉的机器人|总编辑圈点

2023-06-05

天天观焦点:艾曼妞电影完整版观看_法国艾曼妞电影完整版

2023-06-05

世界热推荐:屠龙之术诗句_屠龙之术

2023-06-05

在北京,四十个藏族孩子留下了风|焦点速讯

2023-06-04

世界今热点:本泽马连续18个赛季取得欧冠进球,仅梅西和他做到这点

2023-06-04

win7不激活能上网吗(Win7不激活会怎么样)-天天看点

2023-06-04

红凯吹的曲子叫什么 红凯吹的曲子

2023-06-04

《街头霸王6》PS平台各版本对比:次世代优势明显

2023-06-04

全球消息!微信退票一定要登录12306吗(微信上退票还用去车站吗)

2023-06-04

全球观焦点:音乐mv怎么下载到u盘_歌曲mv怎么下载到u盘

2023-06-04

点读机女孩高君雨生病暴瘦,称睡觉疼醒吃了就吐,面色苍白好憔悴

2023-06-04

世界十大银行最新排名_世界十大银行

2023-06-04

天天消息!什么叫双亲留守儿童_什么叫留守儿童

2023-06-04

刑法告诉才处理的犯罪是什么意思_世界今头条

2023-06-04

世界新消息丨大科学装置为何能既出成果又出人才

2023-06-04

全球热头条丨《熊家餐馆》第二季发预告,6月22日10集一起上线Hulu

2023-06-04

环球热议:纺织行业报价预警:济南普莱华化工有限公司丙烯腈价格4周暴跌11.46%(2023年06月03日)

2023-06-04

湖北创新实施流域综合治理办法 上游来水水质明显改善 武汉补偿仙桃300万元-天天快看

2023-06-04

当前通讯!神舟十五号载人飞船返回舱成功着陆

2023-06-04

焦点报道:不能更改数组的某一部分怎么处理(不能更改数组的某一部分是什么意思)

2023-06-04

铁板烤羊肉的腌制方法窍门?

2023-06-04