摘要:目前為止,多個狀態(tài)機和多種狀態(tài)機都可以在里面實現(xiàn)了,下一章我們來解決下狀態(tài)機和實際業(yè)務(wù)間的數(shù)據(jù)傳輸問題,畢竟我們不是為了讓狀態(tài)機自個獨自玩耍,和業(yè)務(wù)數(shù)據(jù)互通有無才是企業(yè)開發(fā)的正道。
在上一章的例子中,我們實現(xiàn)了多個狀態(tài)機并存執(zhí)行,不同的訂單有各自的狀態(tài)機運行,但只有一種狀態(tài)機,這顯然不能滿足實際業(yè)務(wù)的要求,比如我就遇到了訂單流程和公文審批流程在同一個項目的情況,所以我們這一章講怎么讓多種狀態(tài)機共存。
我們先把上一章的例子狀態(tài)機再復習一下,這是個訂單狀態(tài)機,流程圖如下: ![](https://oscimg.oschina.net/oscnet/e60cfa4b1956ed1863632b34b7f0d7a60ff.jpg)
定義這個狀態(tài)機我們用到了OrderEvents,OrderStates來表達狀態(tài)(states)和事件(events),用OrderStateMachineBuilder來描述初始狀態(tài)和狀態(tài)變化流程,用OrderEventConfig來描述這個流程和狀態(tài)變化過程中需要做的業(yè)務(wù)。
現(xiàn)在我們再弄一個新的狀態(tài)機流程,表單狀態(tài)機,流程圖如下:
為此,我們同樣配套了和訂單狀態(tài)機一樣的表單四件套,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;
/**
訂單狀態(tài)機構(gòu)建器
*/
@Component
public class FormStateMachineBuilder {
private final static String MACHINEID = "formMachine"; /** * 構(gòu)建狀態(tài)機 * * @param beanFactory * @return * @throws Exception */ public StateMachinebuild(BeanFactory beanFactory) throws Exception { StateMachineBuilder.Builder builder = StateMachineBuilder.builder(); System.out.println("構(gòu)建表單狀態(tài)機"); 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());
/** * 當前狀態(tài)BLANK_FORM */ @OnTransition(target = "BLANK_FORM") public void create() { logger.info("---空白表單---"); } /** * BLANK_FORM->FULL_FORM 執(zhí)行的動作 */ @OnTransition(source = "BLANK_FORM", target = "FULL_FORM") public void write(Messagemessage) { logger.info("---填寫完表單---"); } /** * FULL_FORM->CONFIRM_FORM 執(zhí)行的動作 */ @OnTransition(source = "FULL_FORM", target = "CONFIRM_FORM") public void confirm(Message message) { logger.info("---校驗表單---"); } /** * CONFIRM_FORM->SUCCESS_FORM 執(zhí)行的動作 */ @OnTransition(source = "CONFIRM_FORM", target = "SUCCESS_FORM") public void submit(Message message) { logger.info("---表單提交成功---"); }
}
從代碼可以看到深深的套路感,里面除了對流程狀態(tài)的描述不同外,另外一個不同點就是MACHINEID,在不同的狀態(tài)機流程中,用MACHINEID來標識不同就能使用多種狀態(tài)機了,對比一下就很清楚。在builder里面通過MACHINEID來區(qū)分
private final static String MACHINEID = "orderMachine";
public StateMachinebuild(BeanFactory beanFactory) throws Exception { StateMachineBuilder.Builder builder = StateMachineBuilder.builder(); System.out.println("構(gòu)建訂單狀態(tài)機"); 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("構(gòu)建表單狀態(tài)機"); builder.configureConfiguration() .withConfiguration() .machineId(MACHINEID) .beanFactory(beanFactory);
...
對應(yīng)的在eventconfig里面
@WithStateMachine(id="orderMachine")
public class OrderEventConfig {
...
@WithStateMachine(id="formMachine")
public class FormEventConfig {
通過@WithStateMachine注解的id參數(shù)就區(qū)分出來了不同的狀態(tài)機,這個id就是builder里面定義的MACHINEID。然后就是怎么引用的問題了,我們來看controller
@Autowired private OrderStateMachineBuilder orderStateMachineBuilder; @Autowired private FormStateMachineBuilder formStateMachineBuilder;
這樣,不同的builder就能同時引用,兩種狀態(tài)機就互不干擾的各自運行了,這是運行的代碼:
@RequestMapping("/testOrderState")
public void testOrderState(String orderId) throws Exception { StateMachinestateMachine = orderStateMachineBuilder.build(beanFactory); System.out.println(stateMachine.getId()); // 創(chuàng)建流程 stateMachine.start(); // 觸發(fā)PAY事件 stateMachine.sendEvent(OrderEvents.PAY); // 觸發(fā)RECEIVE事件 stateMachine.sendEvent(OrderEvents.RECEIVE); // 獲取最終狀態(tài) System.out.println("最終狀態(tài):" + stateMachine.getState().getId()); } @RequestMapping("/testFormState") public void testFormState() throws Exception { StateMachine stateMachine = formStateMachineBuilder.build(beanFactory); System.out.println(stateMachine.getId()); // 創(chuàng)建流程 stateMachine.start(); stateMachine.sendEvent(FormEvents.WRITE); stateMachine.sendEvent(FormEvents.CONFIRM); stateMachine.sendEvent(FormEvents.SUBMIT); // 獲取最終狀態(tài) System.out.println("最終狀態(tài):" + stateMachine.getState().getId()); }
分別執(zhí)行
http://localhost:9991/statemachine/testOrderState 使用StateMachineBuilder創(chuàng)建的多個狀態(tài)機演示
http://localhost:9991/statemachine/testFormState 多種狀態(tài)機的演示(上面都是order的狀態(tài)機,這個是form的狀態(tài)機)
在日志里面就能看到各自狀態(tài)機的運行結(jié)果了。
目前為止,多個狀態(tài)機和多種狀態(tài)機都可以在spring statemachine里面實現(xiàn)了,下一章我們來解決下狀態(tài)機和實際業(yè)務(wù)間的數(shù)據(jù)傳輸問題,畢竟我們不是為了讓狀態(tài)機自個獨自玩耍,和業(yè)務(wù)數(shù)據(jù)互通有無才是企業(yè)開發(fā)的正道。
碼云配套代碼地址
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/77800.html
摘要:雖然多個狀態(tài)機的問題解決了,但是對于實際的企業(yè)應(yīng)用而言,還是有問題。這個問題就用到了狀態(tài)機的持久化,我們下一章就談?wù)劤志没瘑栴}。 1、多個狀態(tài)機的搞法在實際的企業(yè)應(yīng)用中,基本不可能只有一個狀態(tài)機流程在跑,比如訂單,肯定是很多個訂單在運行,每個訂單都有自己的訂單狀態(tài)機流程,但上一章的例子,大家可以試一下,當執(zhí)行到一個狀態(tài)時,再次刷新頁面,不會有任何日志出現(xiàn),當一個狀態(tài)流程執(zhí)行到某個狀態(tài),...
摘要:讓我們先看下狀態(tài)機的概念。下面是狀態(tài)機模型中的個要素,即現(xiàn)態(tài)條件動作次態(tài)。因為訂單和審批公文都有很多的流程,每個流程都會產(chǎn)生狀態(tài)的變化,而且流程是這種業(yè)務(wù)的主軸,其他都是圍繞這個流程和狀態(tài)變化來考慮的,所以看起來蠻適合用狀態(tài)機來做。 1、背景在我打算學習spring statemachine的時候,我?guī)缀蹩催^了所有網(wǎng)上的中文教程,基本上都處于淺嘗輒止的階段,有幾篇講的比較深入的,都只是...
摘要:在實際的企業(yè)開發(fā)中,不可能所有情況都是從頭到尾的按狀態(tài)流程來,會有很多意外,比如歷史數(shù)據(jù),故障重啟后的遺留流程,所以這種可以任意調(diào)節(jié)狀態(tài)的才是我們需要的狀態(tài)機。 1、偽持久化和中間段的狀態(tài)機我們設(shè)想一個業(yè)務(wù)場景,就比如訂單吧,我們一般的設(shè)計都會把訂單狀態(tài)存到訂單表里面,其他的業(yè)務(wù)信息也都有表保存,而狀態(tài)機的主要作用其實是規(guī)范整個訂單業(yè)務(wù)流程的狀態(tài)和事件,所以狀態(tài)機要不要保存真的不重要,...
摘要:先來一個,它的主要作用就告訴狀態(tài)機的初始狀態(tài)應(yīng)該啥樣,然后把整個狀態(tài)流程都用代碼配置出來。繼承了類,表明身份,我就是來配置狀態(tài)機的初始狀態(tài),并描繪一下狀態(tài)流程的全過程。 上一篇說了很多廢話,這一篇就不嘮叨,先跑起來 1、來個spring boot去start.spring.io新建一個springboot的項目,雖然我對spirngboot也有不少的牢騷,但作為demo的開始,還是一個...
摘要:目前為止,我們都是從狀態(tài)流程的開始階段創(chuàng)建一個狀態(tài)機,然后一路走下去。然后就可以愉快的在里面看怎么用了發(fā)送事件持久化恢復狀態(tài)機后的狀態(tài)為執(zhí)行完保存后,大家可以自己在客戶端查看以下,是不是有內(nèi)容保存進去了。 目前為止,我們都是從狀態(tài)流程的開始階段創(chuàng)建一個狀態(tài)機,然后一路走下去。但在實際業(yè)務(wù)中,狀態(tài)機可能需要在某個環(huán)節(jié)停留,等待其他業(yè)務(wù)的觸發(fā),然后再繼續(xù)下面的流程。比如訂單,可能在支付環(huán)節(jié)...
閱讀 2538·2023-04-26 00:57
閱讀 910·2021-11-25 09:43
閱讀 2221·2021-11-11 16:55
閱讀 2204·2019-08-30 15:53
閱讀 3592·2019-08-30 15:52
閱讀 1458·2019-08-30 14:10
閱讀 3379·2019-08-30 13:22
閱讀 1209·2019-08-29 11:18