状态机是有限状态自动机(Finite-state machine)的简称,是现实事物运行规则抽象而成的一个数学模型。
在业务系统中,通过应用状态机的方式,将所有的状态、事件、动作都抽离出来,对复杂的状态迁移逻辑进行统一管理,来取代冗长的 if else 判断,能使系统中的复杂问题得以解耦,变得直观、方便操作,使系统更加易于维护和管理。
有限状态机由其状态列表、初始状态和触发每个转换过程的输入动作组成
状态机的行为可以在现代社会的许多设备中观察到,这些设备根据所呈现的事件序列执行预定的动作序列。
简单的例子有:
由状态机建模的简单机制的一个示例是十字转门,用于控制地铁和游乐园的出入。
作为一个状态机,旋转门有两种可能的状态:
Locked和Unlocked。有两种可能的输入会影响其状态:将硬币放入槽中 (coin) 和推动悬臂 (push)
旋转门状态机可以用一个状态转换表来表示,显示每个可能的状态,它们之间的转换及每个输入产生的输出
| Current State | Input | Next State | Output |
|---|---|---|---|
| Locked | coin | Unlocked | 解锁旋转门,以便游客能够通过 |
| Locked | push | Locked | |
| Unlocked | coin | Unlocked | |
| Unlocked | push | Locked | 当游客通过时,锁定旋转门 |
旋转栅门状态机也可以由称为状态图的有向图表示:

Action一般就对应一个函数。动作是在给定时刻要进行的活动的描述。有多种类型的动作:
开源状态机对比(2022.11.5)
| 开源状态机 | 简介 | 活跃度 |
|---|---|---|
| squirrel-foundation | 旨在为企业使用提供一个轻量级、高度灵活和可扩展、可诊断、易于使用和类型安全的 Java 状态机实现 | star 2k |
| stateless4j | 直接在 java 代码中创建状态机和基于轻量级状态机的工作流 | star 756 |
| spring-statemachine | 旨在提供一个通用的基础设施来处理 Spring 应用程序中的状态机概念 | star 1.3k |
技术选型对比及示例可参考状态机技术选型的考量
Spring Statemachine 旨在提供以下功能:
Spring Application上下文之外使用的简易实例化Zookeeper的分布式状态机UML Eclipse Papyrus建模Spring IOC集成将bean与状态机相关联StateContext是使用状态机时最重要的对象之一,因为它被传递到各种方法和回调中以给出状态机的当前状态及其可能的去向
StateContext包含以下内容:
StateContext被传递到各种组件中,如Action和Guard
使用简单的构建器模式来构建类似的实例。通过使用字符串作为状态和事件,您可以使用此构建器模式在Spring应用程序上下文之外构建完全动态的状态机
StateMachine<String, String> buildMachine1() throws Exception {
Builder<String, String> builder = StateMachineBuilder.builder();
builder.configureStates()
.withStates()
.initial("S1")
.end("SF")
.states(new HashSet<String>(Arrays.asList("S1","S2","S3","S4")));
return builder.build();
}
builder.configureStates()、builder.configureTransitions()和builder.configureConfiguration()接口方法不能链接在一起,这意味着需要单独调用构建器方法
动作是最有用的组件之一,可用于与状态机交互和协作
可以在状态机及其状态生命周期的各个位置执行
Action,例如,进入或退出状态或在状态转换期间。
@Override
public void configure(StateMachineStateConfigurer<States, Events> states)
throws Exception {
states
.withStates()
.initial(States.SI)
.state(States.S1, action1(), action2())
.state(States.S2, action1(), action2())
.state(States.S3, action1(), action3());
}
满足Guard条件的状态机执行相应的方法,即为if else的用法
builder.configureStates()
.withStates()
.initial(S1)
.choice(S1)
.states(EnumSet.allOf(State.class));
builder.configureTransitions()
.withChoice()
.source(S1)
.first(S2, guard1(), action1())
.then(S3, guard2(), action2())
.last(S4, action3());
当对应执行的Action抛出了异常,状态机会调用相应的errorAction,可用于执行回滚等操作
builder.configureTransitions()
.withExternal()
.source(S1)
.target(S2)
.event(Events.FAIL)
.action(action1(), errorAction());
参考资料: