Spring Statemachine 详解
Spring Statemachine 是一个强大的状态机框架,用于在 Spring 应用中实现复杂的状态转换逻辑。它特别适合管理具有多种状态和转换的业务流程,如订单系统、工作流引擎、设备控制等。
一、核心概念
1. 状态机基本元素
- 状态(State):系统所处的特定条件
- 事件(Event):触发状态转换的动作
- 转换(Transition):状态之间的迁移
- 守卫(Guard):转换的条件判断
- 动作(Action):状态转换时执行的业务逻辑
2. 状态类型
- 初始状态(Initial State):状态机的起点
- 结束状态(End State):状态机的终点
- 普通状态(Normal State):常规状态
- 选择状态(Choice State):基于条件的分支
- 叉状态(Fork State):并行执行分支
- 连接状态(Join State):合并并行分支
- 历史状态(History State):记录并恢复之前状态
二、依赖配置
Maven 依赖
<dependency>
<groupId>org.springframework.statemachine</groupId>
<artifactId>spring-statemachine-core</artifactId>
<version>3.2.0</version>
</dependency>
Gradle 依赖
implementation 'org.springframework.statemachine:spring-statemachine-core:3.2.0'
三、基础配置
1. 定义状态和事件枚举
public enum States {
SI, // 初始状态
S1,
S2,
SF // 最终状态
}
public enum Events {
E1,
E2
}
2. 配置状态机
@Configuration
@EnableStateMachine
public class StateMachineConfig
extends EnumStateMachineConfigurerAdapter<States, Events> {
@Override
public void configure(StateMachineStateConfigurer<States, Events> states)
throws Exception {
states
.withStates()
.initial(States.SI)
.states(EnumSet.allOf(States.class))
.end(States.SF);
}
@Override
public void configure(StateMachineTransitionConfigurer<States, Events> transitions)
throws Exception {
transitions
.withExternal()
.source(States.SI)
.target(States.S1)
.event(Events.E1)
.and()
.withExternal()
.source(States.S1)
.target(States.S2)
.event(Events.E2);
}
}
四、高级特性
1. 守卫(Guard)实现条件转换
public class MyGuard implements Guard<States, Events> {
@Override
public boolean evaluate(StateContext<States, Events> context) {
// 检查转换条件
return context.getMessageHeader("key") != null;
}
}
// 在配置中添加守卫
transitions
.withExternal()
.source(States.S1)
.target(States.S2)
.event(Events.E2)
.guard(new MyGuard());
2. 动作(Action)执行业务逻辑
public class MyAction implements Action<States, Events> {
@Override
public void execute(StateContext<States, Events> context) {
// 执行状态转换时的业务逻辑
System.out.println("Transition action executed");
}
}
// 在配置中添加动作
transitions
.withExternal()
.source(States.SI)
.target(States.S1)
.event(Events.E1)
.action(new MyAction());
3. 层次状态(Hierarchical States)
@Override
public void configure(StateMachineStateConfigurer<States, Events> states)
throws Exception {
states
.withStates()
.initial(States.SI)
.state(States.S1)
.and()
.withStates()
.parent(States.S1)
.initial(States.S11)
.state(States.S12);
}
4. 并行状态(Fork/Join)
@Override
public void configure(StateMachineStateConfigurer<States, Events> states)
throws Exception {
states
.withStates()
.initial(States.SI)
.fork(States.SFORK)
.join(States.SJOIN)
.and()
.withStates()
.parent(States.SFORK)
.initial(States.S1)
.end(States.S1END)
.and()
.withStates()
.parent(States.SFORK)
.initial(States.S2)
.end(States.S2END);
}
@Override
public void configure(StateMachineTransitionConfigurer<States, Events> transitions)
throws Exception {
transitions
.withFork()
.source(States.SFORK)
.target(States.S1)
.target(States.S2)
.and()
.withJoin()
.source(States.S1END)
.source(States.S2END)
.target(States.SJOIN);
}
5. 状态机监听器
@Component
public class StateMachineListener
extends StateMachineListenerAdapter<States, Events> {
@Override
public void stateChanged(State<States, Events> from, State<States, Events> to) {
System.out.println("State changed from " + from + " to " + to);
}
@Override
public void eventNotAccepted(Message<Events> event) {
System.err.println("Event not accepted: " + event.getPayload());
}
}
五、持久化状态机
1. 配置持久化仓库
@Bean
public StateMachineRuntimePersister<States, Events, String> stateMachineRuntimePersister() {
return new JpaStateMachineRuntimePersister<>();
}
2. 启用持久化
@Configuration
@EnableStateMachineFactory
public class PersistConfig
extends StateMachineConfigurerAdapter<States, Events> {
@Autowired
private StateMachineRuntimePersister<States, Events, String> stateMachineRuntimePersister;
@Override
public void configure(StateMachineConfigurationConfigurer<States, Events> config)
throws Exception {
config
.withPersistence()
.runtimePersister(stateMachineRuntimePersister);
}
}
3. 保存和恢复状态
// 保存状态
stateMachinePersist.persist(stateMachine, "machineId");
// 恢复状态
StateMachine<States, Events> stateMachine =
stateMachineFactory.getStateMachine("machineId");
stateMachinePersist.restore(stateMachine, "machineId");
六、状态机可视化
1. 导出UML状态图
UmlStateMachineModelProducer modelProducer = new UmlStateMachineModelProducer();
Model model = modelProducer.produce(stateMachine.getStateMachineModel());
UmlStateMachineModelConverter converter = new UmlStateMachineModelConverter();
String uml = converter.convertToString(model);
System.out.println(uml);
2. 生成PlantUML图
@startuml
[*] --> SI
SI --> S1 : E1
S1 --> S2 : E2
S2 --> SF : E3
SF --> [*]
@enduml
七、完整示例:订单状态机
1. 定义状态和事件
public enum OrderStates {
CREATED, // 订单创建
PAYMENT_PENDING, // 待支付
PAYMENT_RECEIVED,// 已支付
PROCESSING, // 处理中
SHIPPED, // 已发货
DELIVERED, // 已送达
CANCELLED, // 已取消
RETURNED // 已退货
}
public enum OrderEvents {
INITIATE_PAYMENT, // 发起支付
PAYMENT_SUCCESS, // 支付成功
PAYMENT_FAILED, // 支付失败
PROCESS_ORDER, // 处理订单
SHIP_ORDER, // 发货
DELIVER_ORDER, // 送达
CANCEL_ORDER, // 取消订单
RETURN_ORDER // 退货
}
2. 配置状态机
@Configuration
@EnableStateMachineFactory
public class OrderStateMachineConfig
extends EnumStateMachineConfigurerAdapter<OrderStates, OrderEvents> {
@Override
public void configure(StateMachineStateConfigurer<OrderStates, OrderEvents> states)
throws Exception {
states
.withStates()
.initial(OrderStates.CREATED)
.state(OrderStates.PAYMENT_PENDING)
.state(OrderStates.PAYMENT_RECEIVED)
.state(OrderStates.PROCESSING)
.state(OrderStates.SHIPPED)
.state(OrderStates.DELIVERED)
.end(OrderStates.CANCELLED)
.end(OrderStates.RETURNED);
}
@Override
public void configure(StateMachineTransitionConfigurer<OrderStates, OrderEvents> transitions)
throws Exception {
transitions
// 从创建到待支付
.withExternal()
.source(OrderStates.CREATED)
.target(OrderStates.PAYMENT_PENDING)
.event(OrderEvents.INITIATE_PAYMENT)
.and()
// 支付成功
.withExternal()
.source(OrderStates.PAYMENT_PENDING)
.target(OrderStates.PAYMENT_RECEIVED)
.event(OrderEvents.PAYMENT_SUCCESS)
.and()
// 支付失败
.withExternal()
.source(OrderStates.PAYMENT_PENDING)
.target(OrderStates.CANCELLED)
.event(OrderEvents.PAYMENT_FAILED)
.and()
// 开始处理订单
.withExternal()
.source(OrderStates.PAYMENT_RECEIVED)
.target(OrderStates.PROCESSING)
.event(OrderEvents.PROCESS_ORDER)
.and()
// 发货
.withExternal()
.source(OrderStates.PROCESSING)
.target(OrderStates.SHIPPED)
.event(OrderEvents.SHIP_ORDER)
.and()
// 送达
.withExternal()
.source(OrderStates.SHIPPED)
.target(OrderStates.DELIVERED)
.event(OrderEvents.DELIVER_ORDER)
.and()
// 取消订单(在特定状态下)
.withExternal()
.source(OrderStates.CREATED)
.target(OrderStates.CANCELLED)
.event(OrderEvents.CANCEL_ORDER)
.and()
.withExternal()
.source(OrderStates.PAYMENT_PENDING)
.target(OrderStates.CANCELLED)
.event(OrderEvents.CANCEL_ORDER)
.and()
// 退货
.withExternal()
.source(OrderStates.DELIVERED)
.target(OrderStates.RETURNED)
.event(OrderEvents.RETURN_ORDER);
}
}
3. 使用状态机服务
@Service
public class OrderService {
@Autowired
private StateMachineFactory<OrderStates, OrderEvents> factory;
private final Map<Long, StateMachine<OrderStates, OrderEvents>> machines =
new ConcurrentHashMap<>();
public void createOrder(Long orderId) {
StateMachine<OrderStates, OrderEvents> sm = buildStateMachine(orderId);
sm.sendEvent(OrderEvents.INITIATE_PAYMENT);
}
public void processPayment(Long orderId, boolean success) {
StateMachine<OrderStates, OrderEvents> sm = machines.get(orderId);
if (sm != null) {
sm.sendEvent(success ?
OrderEvents.PAYMENT_SUCCESS :
OrderEvents.PAYMENT_FAILED);
}
}
public void shipOrder(Long orderId) {
StateMachine<OrderStates, OrderEvents> sm = machines.get(orderId);
if (sm != null && sm.getState().getId() == OrderStates.PROCESSING) {
sm.sendEvent(OrderEvents.SHIP_ORDER);
}
}
private StateMachine<OrderStates, OrderEvents> buildStateMachine(Long orderId) {
StateMachine<OrderStates, OrderEvents> sm = factory.getStateMachine();
sm.start();
machines.put(orderId, sm);
return sm;
}
}
八、最佳实践
1. 状态机设计原则
- 保持状态简单:每个状态应有明确的含义
- 限制状态数量:避免状态爆炸(State Explosion)
- 使用层次状态:管理复杂状态关系
- 合理使用守卫:确保转换条件清晰
- 分离业务逻辑:动作应调用服务而非包含复杂逻辑
2. 性能优化
- 重用状态机实例:避免频繁创建
- 异步事件处理:使用
sendEvent(Message)
异步接口 - 合理持久化:只在必要时持久化状态
- 缓存守卫结果:避免重复计算
3. 错误处理
@Component
public class ErrorStateMachineListener
extends StateMachineListenerAdapter<OrderStates, OrderEvents> {
@Override
public void stateMachineError(
StateMachine<OrderStates, OrderEvents> stateMachine,
Exception exception) {
// 记录错误并处理
System.err.println("State machine error: " + exception.getMessage());
stateMachine.stop();
}
@Override
public void eventNotAccepted(Message<OrderEvents> event) {
// 处理不被接受的事件
System.err.println("Event not accepted: " + event.getPayload());
}
}
九、测试状态机
JUnit 测试示例
@SpringBootTest
public class OrderStateMachineTest {
@Autowired
private StateMachineFactory<OrderStates, OrderEvents> factory;
@Test
public void testOrderFlow() {
StateMachine<OrderStates, OrderEvents> sm = factory.getStateMachine();
sm.start();
// 初始状态应为CREATED
assertEquals(OrderStates.CREATED, sm.getState().getId());
// 发起支付
sm.sendEvent(OrderEvents.INITIATE_PAYMENT);
assertEquals(OrderStates.PAYMENT_PENDING, sm.getState().getId());
// 支付成功
sm.sendEvent(OrderEvents.PAYMENT_SUCCESS);
assertEquals(OrderStates.PAYMENT_RECEIVED, sm.getState().getId());
// 处理订单
sm.sendEvent(OrderEvents.PROCESS_ORDER);
assertEquals(OrderStates.PROCESSING, sm.getState().getId());
// 发货
sm.sendEvent(OrderEvents.SHIP_ORDER);
assertEquals(OrderStates.SHIPPED, sm.getState().getId());
// 送达
sm.sendEvent(OrderEvents.DELIVER_ORDER);
assertEquals(OrderStates.DELIVERED, sm.getState().getId());
}
}
十、常见问题解决
1. 事件未被处理
- 检查状态:确保当前状态支持该事件
- 验证守卫:检查守卫条件是否满足
- 查看日志:启用DEBUG日志查看状态机内部处理
2. 状态机不启动
- 检查配置:确保
@EnableStateMachine
或@EnableStateMachineFactory
已启用 - 手动启动:调用
stateMachine.start()
- 验证依赖:确保所有必需依赖已正确配置
3. 并发问题
- 使用同步:对状态机操作加锁
- 消息队列:使用消息队列顺序处理事件
- 状态机池:创建状态机实例池
4. 持久化失败
- 检查序列化:确保状态和事件可序列化
- 数据库配置:验证持久化仓库配置正确
- 事务管理:确保在事务边界内操作状态机
Spring Statemachine 提供了强大的状态管理能力,特别适合处理复杂的业务流程。通过合理设计状态模型、转换规则和业务动作,可以构建出高度可维护和可扩展的状态驱动应用。