Spring Statemachine 详解

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 提供了强大的状态管理能力,特别适合处理复杂的业务流程。通过合理设计状态模型、转换规则和业务动作,可以构建出高度可维护和可扩展的状态驱动应用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值