第一节 参考
https://github.com/hekailiang/squirrel
https://segmentfault.com/a/1190000009906469
第二节 状态机理论
一.应用范围
订单状态/合同规则状态切换,词法分析器,审批工作流,SQl语言解析,信息检索,爬虫
二.开源项目
jflex,smc,spring statemachine,jfsm,stateless4j,squirrel-foundation
三. 基本概念
字符:一个个字母或者非字母的字符
串/句子/字:字符的一个序列
语言:串的集合
字母表:符号的有穷非空集合
符号表:为每个标识符保存一个记录的数据结构,记录标识符/token的属性
单词/符号/标识符:形成记号的字符序列,可以是一个关键字,算符,字符串,标点符号等。支持连接,和,闭包,幂操作
模式:描述特定记号的单词集合的规则
token/记号:对单词进行模式匹配,返回的标记,一般通过一个id号表示,有记号具体值得属性。
正规式:通过正则表达式,表示模式匹配的一种方式,比如a|b*[cd]
正规定义:通过->推导定义的语言
转换图:通过圆圈(状态),带箭头的边(输入字符)表示自动机,边上可以有动作(触发状态切换事件时,做的操作)。
转换表:转换图用表格表示
有限自动机FA:通过状态集合,输入符号的集合,转换函数,唯一的开始状态,终止状态集合表示。
不确定的有限自动机NFA:当输入某个符号时,存在不止一种转换状态。可以通过子集构造法,把NFA转成DFA
确定的有限自动机DFA:当输入某个符号时,只有一种转换状态。
正则表达式:描述有穷自动机的相同模式的记号
第三节 Squirrel类结构图
第四节 源码流程
测试代码如下:
一.创建状态机
(一).
如代码
UntypedStateMachineBuilder builder = StateMachineBuilderFactory.create(StateMachineSample.class);
状态机的创建使用了builder模式。和普通builder不同,创建builder时,使用了工厂模式。
先调用StateMachineBuilderFactory.create()通过工厂模式创建一个状态机的builder,生成UntypedStateMachineBuilder对象。参数是通过@StateMachineParameters注解自己定义的一个状态机类,在状态机类中指定了状态的类型,事件的枚举类,动作执行时保存中间参数的Context对象,状态机类继承自AbstractUntypedStateMachine类。工厂模式通过SquirrelProvider.newInstance()反射创建对象,不是常用的通过字串或者枚举参数的形式。
(二).如代码
builder.externalTransition().from("A").to("B").on(FSMEvent.ToB).callMethod("fromAToB");
调用上一步的builder对象的builder.externalTransition().from("A").to("B").on(FSMEvent.ToB).callMethod("fromAToB")方法。
这一步是填充状态机builder对象的参数,以便后面传递给状态机。
1.UntypedStateMachineBuilder类继承自StateMachineBuilder。StateMachineBuilder.externalTransition()方法是这个父类的方法,返回的是Builder的类型ExternalTransitionBuilder,除了此类型,父类还支持MultiTransitionBuilder,LocalTransitionBuilder,InternalTransitionBuilder等其他类型的Builder,他们的次态可能是多个,即当前状态,给定一个输入可能跳转到多个不同的下一个状态。
2.ExternalTransitionBuilder是个接口,from()进入实现类TransitionBuilderImpl.from()定义状态切换的源状态,所有的状态都存在Map类型的TransitionBuilderImpl.states中.如果map中没有这个状态就添加进去。并且把原状态赋值给TransitionBuilderImpl.sourceState。from()方法返回fsm.builder.From对象。
3.调用fsm.builder.From.to()方法把目标状态添加到TransitionBuilderImpl.states中。并且把目标状态赋值给TransitionBuilderImpl.targetState。
4.调用TransitionBuilderImpl.on()方法。在源状态sourceState中添加转换事件"ToB".此时,创建一个MutableTransition接口,实现类为TransitionImpl添加到Map类型的StateImpl.transitions中,后面事件触发时,以事件枚举为Key,从装个map中取出这个转换。TransitionImpl对象中包含源sourceState,目标ImmutableState,事件event。on()方法返回builder.On接口.
5.On接口继承When接口,有方法when(),perform(),callMethod().调用callMethod("fromAToB"),根据方法名"fromAToB"创建MethodCallActionProxyImpl代理对象,MethodCallActionProxyImpl实现了Action接口,调用TransitionImpl.addAction()在TransitionImpl.actions成员中添加这个Action接口。
(三).如代码
builder.onEntry("B").callMethod("ontoB");
onEntry()进入StateMachineBuilderImpl.onEntry(),在StateMachineBuilderImpl.states中添加这个状态,通过反射生成EntryExitActionBuilderImpl对象,调用这个对象的EntryExitActionBuilderImpl.callMethod()方法,在EntryExitActionBuilderImpl.state源状态中添加这个action。
(四).如代码
UntypedStateMachine fsm = builder.newStateMachine("A");
反射创建状态机
二.状态机的状态转换
如代码fsm.fire(FSMEvent.ToB, 10);
进入AbstractStateMachine.internalFire().在这里先调用AbstractStateMachine.start()做初始化。然后把"ToB"事件添加到AbstractStateMachine.queuedEvents事件队列里面。最后调用AbstractStateMachine.processEvent()处理事件,进行状态转换,核心逻辑都在这个方法中。在这个方法里.
1.在AbstractStateMachine.start()中调用AbstractStateMachine.entryAll()把用户的事件"ToB"和绑定的动作添加到
2.在AbstractStateMachine.processEvent()中调用StateImpl.internalFire().先从StateImpl.transitions的map中以事件枚举为key,取出ImmutableTransition,前面创建状态机时已经提及如何存到这个map中的。遍历ImmutableTransition,因为当前状态的转换可能有多个。进入TransitionImpl.internalFire().在这个函数里先从context中取出条件啊,判断条件Condition是否满足,Squirrel支持条件事件.如果条件满足,调用TransitionImpl.doTransitInternal()进行状态切换.在source.getParentState() == target.getParentState()这个分支中处理。状态转换操作有三步操作,调用StateImpl.exit()退出当前状态,调用TransitionImpl.transit()转换状态,调用StateImpl.entry()进入新状态.
3.如果上一步的转换是可以接受的,调用AbstractExecutionService.doExecute().从AbstractExecutionService.actionBuckets成员中取出用户定义的Action动作执行.如下图