Squirrel(松鼠)状态机的使用
概述
其实对于英文好的同学来说,这个状态机的使用就非常简单了,参考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());
}
}
------------------------------我是博客签名------------------------------
座右铭:不要因为知识简单就忽略,不积跬步无以至千里。
版权声明:自由转载-非商用-非衍生-保持署名。
本作品采用知识共享署名 4.0 国际许可协议进行许可。
----------------------------------------------------------------------
座右铭:不要因为知识简单就忽略,不积跬步无以至千里。
版权声明:自由转载-非商用-非衍生-保持署名。
本作品采用知识共享署名 4.0 国际许可协议进行许可。
----------------------------------------------------------------------