spring statemachine的企業可用級開發指南4-多種狀態機共存

在上一章的例子中,咱們實現了多個狀態機並存執行,不一樣的訂單有各自的狀態機運行,但只有一種狀態機,這顯然不能知足實際業務的要求,好比我就遇到了訂單流程和公文審批流程在同一個項目的狀況,因此咱們這一章講怎麼讓多種狀態機共存。java

咱們先把上一章的例子狀態機再複習一下,這是個訂單狀態機,流程圖以下:

![](https://oscimg.oschina.net/oscnet/e60cfa4b1956ed1863632b34b7f0d7a60ff.jpg)

定義這個狀態機咱們用到了OrderEvents,OrderStates來表達狀態(states)和事件(events),用OrderStateMachineBuilder來描述初始狀態和狀態變化流程,用OrderEventConfig來描述這個流程和狀態變化過程當中須要作的業務。git

如今咱們再弄一個新的狀態機流程,表單狀態機,流程圖以下:spring

爲此,咱們一樣配套了和訂單狀態機同樣的表單四件套,events,states,StateMachineBuilder和eventConfig。app

public enum FormStates {ui

BLANK_FORM, // 空白表單
FULL_FORM, // 填寫完表單
CONFIRM_FORM, // 校驗表單
SUCCESS_FORM// 成功表單

}spa

public enum FormEvents {.net

WRITE, // 填寫
CONFIRM, // 校驗
SUBMIT // 提交

}日誌

import java.util.EnumSet;code

import org.springframework.beans.factory.BeanFactory;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.config.StateMachineBuilder;
import org.springframework.stereotype.Component;orm

/**

  • 訂單狀態機構建器

*/
@Component
public class FormStateMachineBuilder {

private final static String MACHINEID = "formMachine";

 /**
  * 構建狀態機
  * 
 * @param beanFactory
 * @return
 * @throws Exception
 */
public StateMachine<FormStates, FormEvents> build(BeanFactory beanFactory) throws Exception {
     StateMachineBuilder.Builder<FormStates, FormEvents> 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(Message<FormEvents> message) {
    logger.info("---填寫完表單---");
}

/**
 * FULL_FORM->CONFIRM_FORM 執行的動做
 */
@OnTransition(source = "FULL_FORM", target = "CONFIRM_FORM")
public void confirm(Message<FormEvents> message) {
    logger.info("---校驗表單---");
}

/**
 * CONFIRM_FORM->SUCCESS_FORM 執行的動做
 */
@OnTransition(source = "CONFIRM_FORM", target = "SUCCESS_FORM")
public void submit(Message<FormEvents> message) {
    logger.info("---表單提交成功---");
}

}
從代碼能夠看到深深的套路感,裏面除了對流程狀態的描述不一樣外,另一個不一樣點就是MACHINEID,在不一樣的狀態機流程中,用MACHINEID來標識不一樣就能使用多種狀態機了,對比一下就很清楚。在builder裏面經過MACHINEID來區分

private final static String MACHINEID = "orderMachine";

public StateMachine<OrderStates, OrderEvents> build(BeanFactory beanFactory) throws Exception {
     StateMachineBuilder.Builder<OrderStates, OrderEvents> builder = StateMachineBuilder.builder();

     System.out.println("構建訂單狀態機");

     builder.configureConfiguration()
             .withConfiguration()
             .machineId(MACHINEID)
             .beanFactory(beanFactory);

...

private final static String MACHINEID = "formMachine";

public StateMachine<FormStates, FormEvents> build(BeanFactory beanFactory) throws Exception {
     StateMachineBuilder.Builder<FormStates, FormEvents> 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 {

    StateMachine<OrderStates, OrderEvents> stateMachine = 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<FormStates, FormEvents> 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裏面實現了,下一章咱們來解決下狀態機和實際業務間的數據傳輸問題,畢竟咱們不是爲了讓狀態機自個獨自玩耍,和業務數據互通有無纔是企業開發的正道。

碼雲配套代碼地址

相關文章
相關標籤/搜索