概述
其實對於英文好的同學來說,這個狀態機的使用就非常簡單了,參考https://github.com/hekailiang/squirrel上的文檔即可,因為這個狀態機的入門成本並不高。
實戰代碼
由於這個狀態機比較簡單,就直接上代碼了,注釋寫在代碼里,通過調試運行,相信你馬上就理解了。
定義事件FSMEvent.java
/**
* 定義狀態機事件
*
* @author: 吳慶龍
* @date: 2019/12/23 10:44 上午
*/
public enum FSMEvent {
ToA, ToB, ToC, ToD, toE, ToF
}
定義監聽器DeclarativeEventListener.java
import lombok.extern.slf4j.Slf4j;
import org.squirrelframework.foundation.exception.TransitionException;
import org.squirrelframework.foundation.fsm.Action;
import org.squirrelframework.foundation.fsm.annotation.*;
/**
* 聲明式監聽
*
* @author: 吳慶龍
* @date: 2019/12/23 1:20 下午
*/
@Slf4j
public class DeclarativeEventListener {
/**
* 轉換事件開始時進行調用
*/
@OnTransitionBegin
public void transitionBegin(FSMEvent event) {
System.out.println();
log.info("transitionBegin event {}", event);
}
/**
* 轉換事件開始時進行調用
* 可以加入條件
* 'event'(E), 'from'(S), 'to'(S), 'context'(C) and 'stateMachine'(T) can be used in MVEL scripts
*/
@OnTransitionBegin(when="event.name().equals(\"ToB\")")
public void transitionBeginConditional() {
log.info("transitionBeginConditional");
}
/**
* 轉換事件結束時進行調用
* 這個方法必須是 public 並且返回值是 void
*/
@OnTransitionEnd
@ListenerOrder(10)
public void transitionEnd() {
log.info("transitionEnd");
System.out.println();
}
@OnTransitionComplete
public void transitionComplete(String from, String to, FSMEvent event, Integer context) {
log.info("transitionComplete {}=>{} on {} with {}", from, to, event, context);
}
@OnTransitionException
public void transitionException(String from, String to, FSMEvent event, Integer context) {
log.info("transitionException");
}
/**
* 當轉換被拒絕時,將調用注有TransitionDecline的方法
*/
@OnTransitionDecline
public void transitionDeclined(String from, FSMEvent event, Integer context) {
log.info("transitionDeclined {}=>??? on {} with {}", from, event, context);
}
/**
* 帶有 OnAfterActionExecuted 注釋的方法將在調用操作之前被調用
* 實際是 callMethod 中的方法被調用錢執行這個方法。類似於 AOP 的效果,運行一下即可知道
*/
@OnBeforeActionExecuted
public void onBeforeActionExecuted(Object sourceState, Object targetState,
Object event, Object context, int[] mOfN, Action<?, ?, ?,?> action) {
log.info("onBeforeActionExecuted");
}
/**
* 帶有 OnAfterActionExecuted 注釋的方法將在調用操作之后被調用
* 實際是 callMethod 中的方法被調用后執行這個方法。類似於 AOP 的效果,運行一下即可知道
*/
@OnAfterActionExecuted
public void onAfterActionExecuted(Object sourceState, Object targetState,
Object event, Object context, int[] mOfN, Action<?, ?, ?,?> action) {
log.info("onAfterActionExecuted");
}
/**
* 帶有 OnActionExecException 注釋的方法將在調用操作異常之后被調用
* 實際是 callMethod 中的方法被調用時拋異常了之后執行這個方法。類似於 AOP 的效果,運行一下即可知道
*/
@OnActionExecException
public void onActionExecException(Action<?, ?, ?,?> action, TransitionException e) {
log.info("onActionExecException");
}
}
狀態機和StateMachineSample.java
import lombok.extern.slf4j.Slf4j;
import org.squirrelframework.foundation.fsm.*;
import org.squirrelframework.foundation.fsm.annotation.StateMachineParameters;
import org.squirrelframework.foundation.fsm.impl.AbstractUntypedStateMachine;
/**
* 定義狀態機,支持如下格式的方法定義
* transitFrom[fromStateName]To[toStateName]On[eventName]When[conditionName]
* transitFrom[fromStateName]To[toStateName]On[eventName]
* transitFromAnyTo[toStateName]On[eventName]
* transitFrom[fromStateName]ToAnyOn[eventName]
* transitFrom[fromStateName]To[toStateName]
* on[eventName]
* entry[eventName]
* exit[eventName]
*
* @author: 吳慶龍
* @date: 2019/12/23 10:46 上午
*/
@Slf4j
@StateMachineParameters(stateType = String.class, eventType = FSMEvent.class, contextType = Integer.class)
public class StateMachineSample extends AbstractUntypedStateMachine {
// =========== A -> B:需要將方法名配置在 callMethod 內
public void fromAToB(String from, String to, FSMEvent event, Integer context) {
log.info("轉換事件 {}=>{} on {} with {}.", from, to, event, context);
}
// =========== B -> C:符合 transitFrom[fromStateName]To[toStateName] 格式,不需要配置 callMethod
public void transitFromBToC(String from, String to, FSMEvent event, Integer context) {
log.info("轉換事件 {}=>{} on {} with {}.", from, to, event, context);
}
// =========== 進入 A, 符合 entry[StateName] 格式,不需要配置 callMethod
public void entryA(String from, String to, FSMEvent event, Integer context) {
log.info("進入事件 {}=>{} on {} with {}.", from, to, event, context);
}
// =========== 退出 A, 符合 exit[StateName] 格式,不需要配置 callMethod
public void exitA(String from, String to, FSMEvent event, Integer context) {
log.info("退出事件 {}=>{} on {} with {}.", from, to, event, context);
}
// =========== 進入 B
public void enterB(String from, String to, FSMEvent event, Integer context) {
log.info("進入事件 {}=>{} on {} with {}.", from, to, event, context);
}
// =========== 退出 B
public void exitB(String from, String to, FSMEvent event, Integer context) {
log.info("退出事件 {}=>{} on {} with {}.", from, to, event, context);
}
// ==========================================================================================
// 如果不想用 DeclarativeEventListener 這種聲明在單獨類里的方法,可以直接重寫以下方法,效果是一樣的
// 兩者同時用也可以,為了代碼方便最好別這樣
// ==========================================================================================
@Override
protected void afterTransitionCausedException(Object fromState, Object toState, Object event, Object context) {
// super.afterTransitionCausedException(fromState, toState, event, context);
// 默認的實現是直接拋異常
log.info("Override 發生錯誤 {}", getLastException().getMessage());
}
@Override
protected void beforeTransitionBegin(Object fromState, Object event, Object context) {
// 轉換開始時被調用
System.out.println();
super.beforeTransitionBegin(fromState, event, context);
log.info("Override beforeTransitionBegin");
}
@Override
protected void afterTransitionCompleted(Object fromState, Object toState, Object event, Object context) {
// 轉換完成時被調用
super.afterTransitionCompleted(fromState, toState, event, context);
log.info("Override afterTransitionCompleted");
}
@Override
protected void afterTransitionEnd(Object fromState, Object toState, Object event, Object context) {
// 轉換結束時被調用
super.afterTransitionEnd(fromState, toState, event, context);
log.info("Override afterTransitionEnd");
System.out.println();
}
@Override
protected void afterTransitionDeclined(Object fromState, Object event, Object context) {
// 當轉換被拒絕時被調用。實際是調用 callMethod 中的方法被調用時,拋出異常時被調用
super.afterTransitionDeclined(fromState, event, context);
log.info("Override afterTransitionDeclined");
}
@Override
protected void beforeActionInvoked(Object fromState, Object toState, Object event, Object context) {
// 當轉換開始時被調用。實際是 callMethod 中的方法被調用時,類似於 AOP 的效果,運行一下即可知道
super.beforeActionInvoked(fromState, toState, event, context);
log.info("Override beforeActionInvoked");
}
@Override
protected void afterActionInvoked(Object fromState, Object toState, Object event, Object context) {
// 當轉換結束時被調用。實際是 callMethod 被調用時,類似於 AOP 的效果,運行一下即可知道
super.afterActionInvoked(fromState, toState, event, context);
log.info("Override afterActionInvoked");
}
public static void main(String[] args) {
// 構造 builder
StateMachineConfiguration stateMachineConfiguration = StateMachineConfiguration.create()
.enableAutoStart(false);
UntypedStateMachineBuilder builder = StateMachineBuilderFactory.create(StateMachineSample.class);
builder.setStateMachineConfiguration(stateMachineConfiguration);
// 配置狀態流轉時觸發的事件
builder.externalTransition().from("A").to("B").on(FSMEvent.ToB).callMethod("fromAToB");
builder.externalTransition().from("B").to("C").on(FSMEvent.ToC);
builder.onEntry("A");
builder.onExit("A");
builder.onEntry("B").callMethod("enterB");
builder.onExit("B");
// 使用狀態機
UntypedStateMachine fsm = builder.newStateMachine("A");
fsm.start();
// 添加監聽器
// fsm.addStateMachineListener(new StateMachineListener<UntypedStateMachine, Object, Object, Object>() {
// @Override
// public void stateMachineEvent(StateMachineEvent<UntypedStateMachine, Object, Object, Object> event) {
// log.info("lastState: " + event.getStateMachine().getLastState());
// }
// });
// fsm.addDeclarativeListener(new DeclarativeEventListener());
// 源碼中的日志 demo
// StateMachineLogger logger = new StateMachineLogger(fsm);
// logger.startLogging();
fsm.fire(FSMEvent.ToB, 1);
fsm.fire(FSMEvent.ToC);
System.out.println("Current state is " + fsm.getCurrentState());
}
}