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