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

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

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

        

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

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

    

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

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 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裏面code

@WithStateMachine(id="orderMachine")
public class OrderEventConfig {
...
@WithStateMachine(id="formMachine")
public class FormEventConfig {

經過@WithStateMachine註解的id參數就區分出來了不一樣的狀態機,這個id就是builder裏面定義的MACHINEID。而後就是怎麼引用的問題了,咱們來看controllerorm

@Autowired
	private OrderStateMachineBuilder orderStateMachineBuilder;
	
	@Autowired
	private FormStateMachineBuilder formStateMachineBuilder;

這樣,不一樣的builder就能同時引用,兩種狀態機就互不干擾的各自運行了,這是運行的代碼:blog

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

碼雲配套代碼地址

相關文章
相關標籤/搜索