摘要:目前为止,多个状态机和多种状态机都可以在里面实现了,下一章我们来解决下状态机和实际业务间的数据传输问题,毕竟我们不是为了让状态机自个独自玩耍,和业务数据互通有无才是企业开发的正道。
在上一章的例子中,我们实现了多个状态机并存执行,不同的订单有各自的状态机运行,但只有一种状态机,这显然不能满足实际业务的要求,比如我就遇到了订单流程和公文审批流程在同一个项目的情况,所以我们这一章讲怎么让多种状态机共存。
我们先把上一章的例子状态机再复习一下,这是个订单状态机,流程图如下: ![](https://oscimg.oschina.net/oscnet/e60cfa4b1956ed1863632b34b7f0d7a60ff.jpg)
定义这个状态机我们用到了OrderEvents,OrderStates来表达状态(states)和事件(events),用OrderStateMachineBuilder来描述初始状态和状态变化流程,用OrderEventConfig来描述这个流程和状态变化过程中需要做的业务。
现在我们再弄一个新的状态机流程,表单状态机,流程图如下:
为此,我们同样配套了和订单状态机一样的表单四件套,events,states,StateMachineBuilder和eventConfig。
public enum FormStates {
BLANK_FORM, // 空白表单 FULL_FORM, // 填写完表单 CONFIRM_FORM, // 校验表单 SUCCESS_FORM// 成功表单
}
public enum FormEvents {
WRITE, // 填写 CONFIRM, // 校验 SUBMIT // 提交
}
import java.util.EnumSet;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.config.StateMachineBuilder;
import org.springframework.stereotype.Component;
/**
订单状态机构建器
*/
@Component
public class FormStateMachineBuilder {
private final static String MACHINEID = "formMachine"; /** * 构建状态机 * * @param beanFactory * @return * @throws Exception */ public StateMachinebuild(BeanFactory beanFactory) throws Exception { StateMachineBuilder.Builder builder = StateMachineBuilder.builder(); System.out.println("构建表单状态机"); builder.configureConfiguration() .withConfiguration() .machineId(MACHINEID) .beanFactory(beanFactory); builder.configureStates() .withStates() .initial(FormStates.BLANK_FORM) .states(EnumSet.allOf(FormStates.class)); builder.configureTransitions() .withExternal() .source(FormStates.BLANK_FORM).target(FormStates.FULL_FORM) .event(FormEvents.WRITE) .and() .withExternal() .source(FormStates.FULL_FORM).target(FormStates.CONFIRM_FORM) .event(FormEvents.CONFIRM) .and() .withExternal() .source(FormStates.CONFIRM_FORM).target(FormStates.SUCCESS_FORM) .event(FormEvents.SUBMIT); return builder.build(); }
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.messaging.Message;
import org.springframework.statemachine.annotation.OnTransition;
import org.springframework.statemachine.annotation.WithStateMachine;
@WithStateMachine(id="formMachine")
public class FormEventConfig {
private Logger logger = LoggerFactory.getLogger(getClass());
/** * 当前状态BLANK_FORM */ @OnTransition(target = "BLANK_FORM") public void create() { logger.info("---空白表单---"); } /** * BLANK_FORM->FULL_FORM 执行的动作 */ @OnTransition(source = "BLANK_FORM", target = "FULL_FORM") public void write(Messagemessage) { logger.info("---填写完表单---"); } /** * FULL_FORM->CONFIRM_FORM 执行的动作 */ @OnTransition(source = "FULL_FORM", target = "CONFIRM_FORM") public void confirm(Message message) { logger.info("---校验表单---"); } /** * CONFIRM_FORM->SUCCESS_FORM 执行的动作 */ @OnTransition(source = "CONFIRM_FORM", target = "SUCCESS_FORM") public void submit(Message message) { logger.info("---表单提交成功---"); }
}
从代码可以看到深深的套路感,里面除了对流程状态的描述不同外,另外一个不同点就是MACHINEID,在不同的状态机流程中,用MACHINEID来标识不同就能使用多种状态机了,对比一下就很清楚。在builder里面通过MACHINEID来区分
private final static String MACHINEID = "orderMachine";
public StateMachinebuild(BeanFactory beanFactory) throws Exception { StateMachineBuilder.Builder builder = StateMachineBuilder.builder(); System.out.println("构建订单状态机"); builder.configureConfiguration() .withConfiguration() .machineId(MACHINEID) .beanFactory(beanFactory);
...
private final static String MACHINEID = "formMachine";
public StateMachinebuild(BeanFactory beanFactory) throws Exception { StateMachineBuilder.Builder builder = StateMachineBuilder.builder(); System.out.println("构建表单状态机"); builder.configureConfiguration() .withConfiguration() .machineId(MACHINEID) .beanFactory(beanFactory);
...
对应的在eventconfig里面
@WithStateMachine(id="orderMachine")
public class OrderEventConfig {
...
@WithStateMachine(id="formMachine")
public class FormEventConfig {
通过@WithStateMachine注解的id参数就区分出来了不同的状态机,这个id就是builder里面定义的MACHINEID。然后就是怎么引用的问题了,我们来看controller
@Autowired private OrderStateMachineBuilder orderStateMachineBuilder; @Autowired private FormStateMachineBuilder formStateMachineBuilder;
这样,不同的builder就能同时引用,两种状态机就互不干扰的各自运行了,这是运行的代码:
@RequestMapping("/testOrderState")
public void testOrderState(String orderId) throws Exception { StateMachinestateMachine = orderStateMachineBuilder.build(beanFactory); System.out.println(stateMachine.getId()); // 创建流程 stateMachine.start(); // 触发PAY事件 stateMachine.sendEvent(OrderEvents.PAY); // 触发RECEIVE事件 stateMachine.sendEvent(OrderEvents.RECEIVE); // 获取最终状态 System.out.println("最终状态:" + stateMachine.getState().getId()); } @RequestMapping("/testFormState") public void testFormState() throws Exception { StateMachine stateMachine = formStateMachineBuilder.build(beanFactory); System.out.println(stateMachine.getId()); // 创建流程 stateMachine.start(); stateMachine.sendEvent(FormEvents.WRITE); stateMachine.sendEvent(FormEvents.CONFIRM); stateMachine.sendEvent(FormEvents.SUBMIT); // 获取最终状态 System.out.println("最终状态:" + stateMachine.getState().getId()); }
分别执行
http://localhost:9991/statemachine/testOrderState 使用StateMachineBuilder创建的多个状态机演示
http://localhost:9991/statemachine/testFormState 多种状态机的演示(上面都是order的状态机,这个是form的状态机)
在日志里面就能看到各自状态机的运行结果了。
目前为止,多个状态机和多种状态机都可以在spring statemachine里面实现了,下一章我们来解决下状态机和实际业务间的数据传输问题,毕竟我们不是为了让状态机自个独自玩耍,和业务数据互通有无才是企业开发的正道。
码云配套代码地址
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/77800.html
摘要:虽然多个状态机的问题解决了,但是对于实际的企业应用而言,还是有问题。这个问题就用到了状态机的持久化,我们下一章就谈谈持久化问题。 1、多个状态机的搞法在实际的企业应用中,基本不可能只有一个状态机流程在跑,比如订单,肯定是很多个订单在运行,每个订单都有自己的订单状态机流程,但上一章的例子,大家可以试一下,当执行到一个状态时,再次刷新页面,不会有任何日志出现,当一个状态流程执行到某个状态,...
摘要:让我们先看下状态机的概念。下面是状态机模型中的个要素,即现态条件动作次态。因为订单和审批公文都有很多的流程,每个流程都会产生状态的变化,而且流程是这种业务的主轴,其他都是围绕这个流程和状态变化来考虑的,所以看起来蛮适合用状态机来做。 1、背景在我打算学习spring statemachine的时候,我几乎看过了所有网上的中文教程,基本上都处于浅尝辄止的阶段,有几篇讲的比较深入的,都只是...
摘要:在实际的企业开发中,不可能所有情况都是从头到尾的按状态流程来,会有很多意外,比如历史数据,故障重启后的遗留流程,所以这种可以任意调节状态的才是我们需要的状态机。 1、伪持久化和中间段的状态机我们设想一个业务场景,就比如订单吧,我们一般的设计都会把订单状态存到订单表里面,其他的业务信息也都有表保存,而状态机的主要作用其实是规范整个订单业务流程的状态和事件,所以状态机要不要保存真的不重要,...
摘要:先来一个,它的主要作用就告诉状态机的初始状态应该啥样,然后把整个状态流程都用代码配置出来。继承了类,表明身份,我就是来配置状态机的初始状态,并描绘一下状态流程的全过程。 上一篇说了很多废话,这一篇就不唠叨,先跑起来 1、来个spring boot去start.spring.io新建一个springboot的项目,虽然我对spirngboot也有不少的牢骚,但作为demo的开始,还是一个...
摘要:目前为止,我们都是从状态流程的开始阶段创建一个状态机,然后一路走下去。然后就可以愉快的在里面看怎么用了发送事件持久化恢复状态机后的状态为执行完保存后,大家可以自己在客户端查看以下,是不是有内容保存进去了。 目前为止,我们都是从状态流程的开始阶段创建一个状态机,然后一路走下去。但在实际业务中,状态机可能需要在某个环节停留,等待其他业务的触发,然后再继续下面的流程。比如订单,可能在支付环节...
阅读 2505·2023-04-26 00:57
阅读 867·2021-11-25 09:43
阅读 2174·2021-11-11 16:55
阅读 2128·2019-08-30 15:53
阅读 3524·2019-08-30 15:52
阅读 1406·2019-08-30 14:10
阅读 3309·2019-08-30 13:22
阅读 1177·2019-08-29 11:18