实际的企业应用中状态机的流程会更加复杂,而我们最常用到的就是choice。它类似于java的if语句,作为条件判断的分支而存在,让我们先看一张图:
这张图表现的是一个表单(form)的整个状态流程:
- 创建初始的空白表单( BLANK_FORM)
- 填写(WRITE)表单,成为填充完表单(FULL_FORM)
- 检查(CHEKC)表单
- 如果是表单名(formName)不为null,表单成为待提交表单(CONFIRM_FROM)
- 提交(SUBMIT)表单,成为成功提交表单(SUCCESS_FORM)
- 检查(CHECK)表单
- 如果表单名为null,表单成为待处理表单(DEAL_FORM),修改formName
- 处理(DEAL)表单
- 如果表单名还是null或者里面有个“坏”字,表单状态变成废单(FAILED_FORM)
- 如果表单名称没问题,表单状态变成填充完表单状态(FULL_FORM),重新走流程
大家不要在意这个例子的幼稚,毕竟它还是能用简单的方式体现出流程的复杂性(这话多么的辩证统一)。它有判断分支(还有两个),还有流程的循环,还有分支判断后的直接失败和分支判断后的后续环节,后面我们会在代码中告诉大家这里面需要注意的东西。
代码实现
先上状态机的四件套:States,Events,Builder和EventConfig(spring statemachine还是蛮简单的,来来回回就这几样东西)
public enum ComplexFormStates {
BLANK_FORM, // 空白表单
FULL_FORM, // 填写完表单
CHECK_CHOICE,//表单校验判断
DEAL_CHOICE,//表单处理校验
DEAL_FORM,//待处理表单
CONFIRM_FORM, // 校验完表单
SUCCESS_FORM,// 成功表单
FAILED_FORM//失败表单
}
注意一点,choice判断分支本身也是一种状态,要声明出来,这里是CHECK_CHOICE和DEAL_CHOICE
public enum ComplexFormEvents {
WRITE, // 填写
CHECK,//校验
DEAL,//处理
SUBMIT // 提交
}
同样的分支事件也要声明,这里是CHECK和DEAL。
大头是MachineBuilder,这个代码就比较多,大家最好对照着上面这张图来看,会比较清晰
/**
* 复杂订单状态机构建器
*/
@Component
public class ComplexFormStateMachineBuilder {
private final static String MACHINEID = "complexFormMachine";
/**
* 构建状态机
*
* @param beanFactory
* @return
* @throws Exception
*/
public StateMachine<ComplexFormStates, ComplexFormEvents> build(BeanFactory beanFactory) throws Exception {
StateMachineBuilder.Builder<ComplexFormStates, ComplexFormEvents> builder = StateMachineBuilder.builder();
System.out.println("构建复杂表单状态机");
builder.configureConfiguration()
.withConfiguration()
.machineId(MACHINEID)
.beanFactory(beanFactory);
builder.configureStates()
.withStates()
.initial(ComplexFormStates.BLANK_FORM)
.choice(ComplexFormStates.CHECK_CHOICE)
.choice(ComplexFormStates.DEAL_CHOICE)
.states(EnumSet.allOf(ComplexFormStates.class));
builder.configureTransitions()
.withExternal()
.source(ComplexFormStates.BLANK_FORM).target(ComplexFormStates.FULL_FORM)
.event(ComplexFormEvents.WRITE)
.and()
.withExternal()
.source(ComplexFormStates.FULL_FORM).target(ComplexFormStates.CHECK_CHOICE)
.event(ComplexFormEvents.CHECK)
.and()
.withChoice()
.source(ComplexFormStates.CHECK_CHOICE)
.first(ComplexFormStates.CONFIRM_FORM, new ComplexFormCheckChoiceGuard())
.last(ComplexFormStates.DEAL_FORM)
.and()
.withExternal()
.source(ComplexFormStates.CONFIRM_FORM).target(ComplexFormStates.SUCCESS_FORM)
.event(ComplexFormEvents.SUBMIT)
.and()
.withExternal()
.source(ComplexFormStates.DEAL_FORM).target(ComplexFormStates.DEAL_CHOICE)
.event(ComplexFormEvents.DEAL)
.and()
.withChoice()
.source(ComplexFormStates.DEAL_CHOICE)
.first(ComplexFormStates.FULL_FORM, new ComplexFormDealChoiceGuard())
.last(ComplexFormStates.FAILED_FORM);
return builder.build();
}
}
- 在我们熟悉的withExternal之后,我们迎来了为choice专门准备的withChoice()和跟随它的first(),last()。这两个代表的就是分支判断时TRUE和FALSE的状态流程去处,这里面涉及到的一个问题就是,TRUE和FALSE的判断条件是什么呢,根据啥来判断呢?
- Guard就承担了这个判断的功能,看名字似乎不像。它在spring statemachine本来是用来保护这个状态跳转过程的,所以用guard,但在choice里面,它就是作为判断代码而存在的,代码如下:
public class ComplexFormCheckChoiceGuard implements Guard<ComplexFormStates, ComplexFormEvents> {
@Override
public boolean evaluate(StateContext<ComplexFormStates, ComplexFormEvents> context) {
boolean returnValue = false;
Form form = context.getMessage().getHead