Spring State Machine1、概述2、简单示例2.1、引入依赖2.2、定义状态与事件枚举2.3、编写状态机配置类3、分布式状态持久化4、业务层Service优雅调用5、Spring StateMachine 的高阶特性5.1、伪状态分支选择Choice / Junction5.2、嵌套状态Substates / Hierarchical States5.3、并行区域Orthogonal Regions6、总结1、概述相比于轻量级的 Cola-StateMachineSpring State MachineSpring 状态机 是 Spring 生态中功能最强大、最完备同时也是体量最重的状态机框架。它不仅支持基础的状态流转还支持嵌套状态Substates、并行状态Orthogonal Regions、状态持久化、伪状态Choice/Junction、事件监听拦截器以及与 Spring Security、Spring Shell的无缝集成。在需要严格事务控制、分布式状态恢复以及复杂工作流的大型企业级架构中它是不可替代的利器。在开始写代码前必须理清 Spring StateMachine 的根本设计哲学它是**“有状态Stateful”的**。Cola-StateMachine单例运行状态机只存规则不存当前状态每次调用要传入当前状态。Spring StateMachine每一个订单实体在内存中都对应一个独立的、有生命周期的状态机实例。它死死记得自己当前在哪个状态你只需要对它 sendEvent(Event)它自己就会在内存中推进。2、简单示例2.1、引入依赖dependencygroupIdorg.springframework.statemachine/groupIdartifactIdspring-statemachine-starter/artifactIdversion3.2.0/version/dependency2.2、定义状态与事件枚举publicenumOrderState{//待付款PENDING_PAY,//待发货PENDING_DELIVER,//待收货PENDING_RECEIVE,//待评价PENDING_COMMENT,//已完成COMPLETED,//已取消CANCELLED}publicenumOrderEvent{//用户支付USER_PAY,//商家发货MERCHANT_DELIVER,//收到包裹RECEIVE_PACKAGE,//评价COMMENT,//超时未评COMMENT_TIMEOUT,//手动取消MANUAL_CANCEL,//超时未支付PAY_TIMEOUT}2.3、编写状态机配置类我们需要继承 StateMachineConfigurerAdapter全面配置状态机的三大要素初始状态所有状态节点流转规则拦截器Guard/Action。importorg.springframework.context.annotation.Configuration;importorg.springframework.statemachine.config.EnableStateMachineFactory;importorg.springframework.statemachine.config.EnumStateMachineConfigurerAdapter;importorg.springframework.statemachine.config.builders.StateMachineStateConfigurer;importorg.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;importorg.springframework.statemachine.guard.Guard;importorg.springframework.statemachine.action.Action;importjava.util.EnumSet;Configuration// 注意企业级开发中绝不要用 EnableStateMachine单例必须用 EnableStateMachineFactory状态机工厂EnableStateMachineFactory(nameorderStateMachineFactory)publicclassStateMachineConfigextendsEnumStateMachineConfigurerAdapterOrderState,OrderEvent{/** * 1. 配置状态节点的初始化与终态 */Overridepublicvoidconfigure(StateMachineStateConfigurerOrderState,OrderEventstates)throwsException{states.withStates().initial(OrderState.PENDING_PAY)// 对应图中的 [开始] - 进入 [待付款].end(OrderState.COMPLETED)// 终态 [已完成] - 对应图中的 [结束].end(OrderState.CANCELLED)// 终态 [已取消] - 对应图中的 [结束].states(EnumSet.allOf(OrderState.class));// 注册所有状态}/** * 2. 配置状态流转路由规则完全对应你的状态图 */Overridepublicvoidconfigure(StateMachineTransitionConfigurerOrderState,OrderEventtransitions)throwsException{transitions// 待付款 - 待发货 (用户支付).withExternal().source(OrderState.PENDING_PAY).target(OrderState.PENDING_DELIVER).event(OrderEvent.USER_PAY).guard(checkPayGuard())// 准入条件校验 (相当于Cola的Condition).action(doPayAction())// 核心业务动作 执行.and()// 待付款 - 已取消 (手动取消).withExternal().source(OrderState.PENDING_PAY).target(OrderState.CANCELLED).event(OrderEvent.MANUAL_CANCEL).action(doCancelAction()).and()// 待付款 - 已取消 (超时未支付).withExternal().source(OrderState.PENDING_PAY).target(OrderState.CANCELLED).event(OrderEvent.PAY_TIMEOUT).action(doCancelAction()).and()// 待发货 - 待收货 (商家发货).withExternal().source(OrderState.PENDING_DELIVER).target(OrderState.PENDING_RECEIVE).event(OrderEvent.MERCHANT_DELIVER).and()// 待收货 - 待评价 (收到包裹).withExternal().source(OrderState.PENDING_RECEIVE).target(OrderState.PENDING_COMMENT).event(OrderEvent.RECEIVE_PACKAGE).and()// 待评价 - 已完成 (评价).withExternal().source(OrderState.PENDING_COMMENT).target(OrderState.COMPLETED).event(OrderEvent.COMMENT).and()// 待评价 - 已完成 (超时未评).withExternal().source(OrderState.PENDING_COMMENT).target(OrderState.COMPLETED).event(OrderEvent.COMMENT_TIMEOUT);}// 守卫/条件 (Guard) privateGuardOrderState,OrderEventcheckPayGuard(){returncontext-{// 从状态机消息头中拿到业务传参StringorderIdcontext.getMessageHeaders().get(orderId,String.class);System.out.println(【Guard校验】检查订单: orderId 是否有真实的支付流水...);returntrue;// 返回 true 允许放行false 阻断};}// 动作执行 (Action) privateActionOrderState,OrderEventdoPayAction(){returncontext-{StringorderIdcontext.getMessageHeaders().get(orderId,String.class);System.out.println(【Action核心业务】订单: orderId 扣减真实库存推进状态机...);};}privateActionOrderState,OrderEventdoCancelAction(){returncontext-System.out.println(【Action核心业务】释放库存关闭订单。);}}3、分布式状态持久化由于 Spring StateMachine 是在内存中维持状态的分布式部署时每次操作都必须先从数据库捞出订单状态 - 还原恢复内存状态机 - 发送事件推进 - 把新状态存回数据库。Spring 提供了 StateMachineRuntimePersister 机制来实现这一闭环。编写自定义的持久化拦截器我们利用基础的 DefaultStateMachineContext在状态机发生质变流转、准备写入内存前拦截它并直接同步修改数据库。importorg.springframework.messaging.Message;importorg.springframework.statemachine.StateMachine;importorg.springframework.statemachine.state.State;importorg.springframework.statemachine.support.StateMachineInterceptorAdapter;importorg.springframework.statemachine.transition.Transition;importorg.springframework.stereotype.Component;ComponentpublicclassOrderStateMachineInterceptorextendsStateMachineInterceptorAdapterOrderState,OrderEvent{// 假设这是你的数据库操作 Mapper// Autowired private OrderMapper orderMapper;OverridepublicvoidpreStateChange(StateOrderState,OrderEventstate,MessageOrderEventmessage,TransitionOrderState,OrderEventtransition,StateMachineOrderState,OrderEventstateMachine,StateMachineOrderState,OrderEventrootStateMachine){if(message!nullmessage.getHeaders().containsKey(orderId)){LongorderIdmessage.getHeaders().get(orderId,Long.class);OrderStatetargetStatestate.getId();// 【核心持久化步子】状态机即将发生质变前强制同步更新数据库System.out.println(【持久化拦截器】开始持久化订单ID: orderId新状态更新为: targetState);// orderMapper.updateStatus(orderId, targetState.name());}}}4、业务层Service优雅调用在 Service 层我们要利用 StateMachineFactory 动态去 new/获取状态机同时在推进前必须强制用持久化拦截器将数据库的历史状态塞进状态机中进行重置恢复。importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.messaging.Message;importorg.springframework.messaging.support.MessageBuilder;importorg.springframework.statemachine.StateMachine;importorg.springframework.statemachine.config.StateMachineFactory;importorg.springframework.statemachine.support.DefaultStateMachineContext;importorg.springframework.stereotype.Service;ServicepublicclassOrderServiceImplimplementsOrderService{AutowiredprivateStateMachineFactoryOrderState,OrderEventorderStateMachineFactory;AutowiredprivateOrderStateMachineInterceptororderStateMachineInterceptor;publicvoidfireEvent(LongorderId,OrderEventevent){// 1. 从工厂中获取一台全新的状态机实例根据机器ID区分StateMachineOrderState,OrderEventstateMachineorderStateMachineFactory.getStateMachine(String.valueOf(orderId));// 2. 【极其重要】停机并解构状态机强制注入数据库里当前的真实状态进行恢复// 模拟从数据库查出来的是 OrderState.PENDING_PAYOrderStatedbStateOrderState.PENDING_PAY;stateMachine.stopReactively().block();stateMachine.getStateMachineAccessor().doWithAllRegions(accessor-{// 挂载我们上面写的数据库持久化拦截器accessor.addStateMachineInterceptor(orderStateMachineInterceptor);// 充能恢复内存状态accessor.resetStateMachineReactively(newDefaultStateMachineContext(dbState,null,null,null)).block();});stateMachine.startReactively().block();// 3. 构造带业务参数的消息体透传给 Action 和 Guard 使用MessageOrderEventmessageMessageBuilder.withPayload(event).setHeader(orderId,orderId).build();// 4. 发送事件驱动流转booleansuccessstateMachine.sendEvent(message);if(!success){thrownewRuntimeException(订单状态流转失败不合法的操作事件);}}}5、Spring StateMachine 的高阶特性5.1、伪状态分支选择Choice / Junction在状态图里面“用户支付”直接去了“待发货”。但在实际业务中用户付完钱后可能触发风控拦截。Spring 支持类似代码中 if-else 的图纸节点// 配置流转时使用 choicetransitions.withChoice().source(OrderState.PENDING_PAY).first(OrderState.PENDING_DELIVER,checkStockGuard())// 库存够去待发货.last(OrderState.CANCELLED);// 库存不够直接去已取消5.2、嵌套状态Substates / Hierarchical States比如“退款中”是一个大状态但里面又细分为“买家寄出”、“商家驳回”、“等待小二介入”等子状态。Spring StateMachine 支持在一张图里套另一张图子状态未能处理的事件会自动向上冒泡给父状态处理。5.3、并行区域Orthogonal Regions一个复杂的实体如汽车出厂检查需要同时满足“外观检查完成”和“发动机检测完成”这两个并行的、互不干扰的状态轴最后会合Join后才能进入“允许出厂”。Spring 状态机可以在单台机器里同时跑多根独立的状态流转线。6、总结维度Spring StateMachineola-StateMachine开销与性能较重。每次请求都要经历创建/获取 - 停止 - 内存恢复 - 启动 - 发送事件 - 拦截写库的全生命周期高并发下对内存和性能有一定损耗。极轻。纯无状态静态路由表单例运行几乎没有额外开销。能丰富度天花板级别。只有你想不到没有它做不到的复杂拓扑图。仅支持基础的外部流转、内部流转。上手难度较高API 较为复杂全面转向响应式编程 Reactive Streams。极低十分钟即可上手。
状态机——Spring State Machine
发布时间:2026/5/19 23:50:55
Spring State Machine1、概述2、简单示例2.1、引入依赖2.2、定义状态与事件枚举2.3、编写状态机配置类3、分布式状态持久化4、业务层Service优雅调用5、Spring StateMachine 的高阶特性5.1、伪状态分支选择Choice / Junction5.2、嵌套状态Substates / Hierarchical States5.3、并行区域Orthogonal Regions6、总结1、概述相比于轻量级的 Cola-StateMachineSpring State MachineSpring 状态机 是 Spring 生态中功能最强大、最完备同时也是体量最重的状态机框架。它不仅支持基础的状态流转还支持嵌套状态Substates、并行状态Orthogonal Regions、状态持久化、伪状态Choice/Junction、事件监听拦截器以及与 Spring Security、Spring Shell的无缝集成。在需要严格事务控制、分布式状态恢复以及复杂工作流的大型企业级架构中它是不可替代的利器。在开始写代码前必须理清 Spring StateMachine 的根本设计哲学它是**“有状态Stateful”的**。Cola-StateMachine单例运行状态机只存规则不存当前状态每次调用要传入当前状态。Spring StateMachine每一个订单实体在内存中都对应一个独立的、有生命周期的状态机实例。它死死记得自己当前在哪个状态你只需要对它 sendEvent(Event)它自己就会在内存中推进。2、简单示例2.1、引入依赖dependencygroupIdorg.springframework.statemachine/groupIdartifactIdspring-statemachine-starter/artifactIdversion3.2.0/version/dependency2.2、定义状态与事件枚举publicenumOrderState{//待付款PENDING_PAY,//待发货PENDING_DELIVER,//待收货PENDING_RECEIVE,//待评价PENDING_COMMENT,//已完成COMPLETED,//已取消CANCELLED}publicenumOrderEvent{//用户支付USER_PAY,//商家发货MERCHANT_DELIVER,//收到包裹RECEIVE_PACKAGE,//评价COMMENT,//超时未评COMMENT_TIMEOUT,//手动取消MANUAL_CANCEL,//超时未支付PAY_TIMEOUT}2.3、编写状态机配置类我们需要继承 StateMachineConfigurerAdapter全面配置状态机的三大要素初始状态所有状态节点流转规则拦截器Guard/Action。importorg.springframework.context.annotation.Configuration;importorg.springframework.statemachine.config.EnableStateMachineFactory;importorg.springframework.statemachine.config.EnumStateMachineConfigurerAdapter;importorg.springframework.statemachine.config.builders.StateMachineStateConfigurer;importorg.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;importorg.springframework.statemachine.guard.Guard;importorg.springframework.statemachine.action.Action;importjava.util.EnumSet;Configuration// 注意企业级开发中绝不要用 EnableStateMachine单例必须用 EnableStateMachineFactory状态机工厂EnableStateMachineFactory(nameorderStateMachineFactory)publicclassStateMachineConfigextendsEnumStateMachineConfigurerAdapterOrderState,OrderEvent{/** * 1. 配置状态节点的初始化与终态 */Overridepublicvoidconfigure(StateMachineStateConfigurerOrderState,OrderEventstates)throwsException{states.withStates().initial(OrderState.PENDING_PAY)// 对应图中的 [开始] - 进入 [待付款].end(OrderState.COMPLETED)// 终态 [已完成] - 对应图中的 [结束].end(OrderState.CANCELLED)// 终态 [已取消] - 对应图中的 [结束].states(EnumSet.allOf(OrderState.class));// 注册所有状态}/** * 2. 配置状态流转路由规则完全对应你的状态图 */Overridepublicvoidconfigure(StateMachineTransitionConfigurerOrderState,OrderEventtransitions)throwsException{transitions// 待付款 - 待发货 (用户支付).withExternal().source(OrderState.PENDING_PAY).target(OrderState.PENDING_DELIVER).event(OrderEvent.USER_PAY).guard(checkPayGuard())// 准入条件校验 (相当于Cola的Condition).action(doPayAction())// 核心业务动作 执行.and()// 待付款 - 已取消 (手动取消).withExternal().source(OrderState.PENDING_PAY).target(OrderState.CANCELLED).event(OrderEvent.MANUAL_CANCEL).action(doCancelAction()).and()// 待付款 - 已取消 (超时未支付).withExternal().source(OrderState.PENDING_PAY).target(OrderState.CANCELLED).event(OrderEvent.PAY_TIMEOUT).action(doCancelAction()).and()// 待发货 - 待收货 (商家发货).withExternal().source(OrderState.PENDING_DELIVER).target(OrderState.PENDING_RECEIVE).event(OrderEvent.MERCHANT_DELIVER).and()// 待收货 - 待评价 (收到包裹).withExternal().source(OrderState.PENDING_RECEIVE).target(OrderState.PENDING_COMMENT).event(OrderEvent.RECEIVE_PACKAGE).and()// 待评价 - 已完成 (评价).withExternal().source(OrderState.PENDING_COMMENT).target(OrderState.COMPLETED).event(OrderEvent.COMMENT).and()// 待评价 - 已完成 (超时未评).withExternal().source(OrderState.PENDING_COMMENT).target(OrderState.COMPLETED).event(OrderEvent.COMMENT_TIMEOUT);}// 守卫/条件 (Guard) privateGuardOrderState,OrderEventcheckPayGuard(){returncontext-{// 从状态机消息头中拿到业务传参StringorderIdcontext.getMessageHeaders().get(orderId,String.class);System.out.println(【Guard校验】检查订单: orderId 是否有真实的支付流水...);returntrue;// 返回 true 允许放行false 阻断};}// 动作执行 (Action) privateActionOrderState,OrderEventdoPayAction(){returncontext-{StringorderIdcontext.getMessageHeaders().get(orderId,String.class);System.out.println(【Action核心业务】订单: orderId 扣减真实库存推进状态机...);};}privateActionOrderState,OrderEventdoCancelAction(){returncontext-System.out.println(【Action核心业务】释放库存关闭订单。);}}3、分布式状态持久化由于 Spring StateMachine 是在内存中维持状态的分布式部署时每次操作都必须先从数据库捞出订单状态 - 还原恢复内存状态机 - 发送事件推进 - 把新状态存回数据库。Spring 提供了 StateMachineRuntimePersister 机制来实现这一闭环。编写自定义的持久化拦截器我们利用基础的 DefaultStateMachineContext在状态机发生质变流转、准备写入内存前拦截它并直接同步修改数据库。importorg.springframework.messaging.Message;importorg.springframework.statemachine.StateMachine;importorg.springframework.statemachine.state.State;importorg.springframework.statemachine.support.StateMachineInterceptorAdapter;importorg.springframework.statemachine.transition.Transition;importorg.springframework.stereotype.Component;ComponentpublicclassOrderStateMachineInterceptorextendsStateMachineInterceptorAdapterOrderState,OrderEvent{// 假设这是你的数据库操作 Mapper// Autowired private OrderMapper orderMapper;OverridepublicvoidpreStateChange(StateOrderState,OrderEventstate,MessageOrderEventmessage,TransitionOrderState,OrderEventtransition,StateMachineOrderState,OrderEventstateMachine,StateMachineOrderState,OrderEventrootStateMachine){if(message!nullmessage.getHeaders().containsKey(orderId)){LongorderIdmessage.getHeaders().get(orderId,Long.class);OrderStatetargetStatestate.getId();// 【核心持久化步子】状态机即将发生质变前强制同步更新数据库System.out.println(【持久化拦截器】开始持久化订单ID: orderId新状态更新为: targetState);// orderMapper.updateStatus(orderId, targetState.name());}}}4、业务层Service优雅调用在 Service 层我们要利用 StateMachineFactory 动态去 new/获取状态机同时在推进前必须强制用持久化拦截器将数据库的历史状态塞进状态机中进行重置恢复。importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.messaging.Message;importorg.springframework.messaging.support.MessageBuilder;importorg.springframework.statemachine.StateMachine;importorg.springframework.statemachine.config.StateMachineFactory;importorg.springframework.statemachine.support.DefaultStateMachineContext;importorg.springframework.stereotype.Service;ServicepublicclassOrderServiceImplimplementsOrderService{AutowiredprivateStateMachineFactoryOrderState,OrderEventorderStateMachineFactory;AutowiredprivateOrderStateMachineInterceptororderStateMachineInterceptor;publicvoidfireEvent(LongorderId,OrderEventevent){// 1. 从工厂中获取一台全新的状态机实例根据机器ID区分StateMachineOrderState,OrderEventstateMachineorderStateMachineFactory.getStateMachine(String.valueOf(orderId));// 2. 【极其重要】停机并解构状态机强制注入数据库里当前的真实状态进行恢复// 模拟从数据库查出来的是 OrderState.PENDING_PAYOrderStatedbStateOrderState.PENDING_PAY;stateMachine.stopReactively().block();stateMachine.getStateMachineAccessor().doWithAllRegions(accessor-{// 挂载我们上面写的数据库持久化拦截器accessor.addStateMachineInterceptor(orderStateMachineInterceptor);// 充能恢复内存状态accessor.resetStateMachineReactively(newDefaultStateMachineContext(dbState,null,null,null)).block();});stateMachine.startReactively().block();// 3. 构造带业务参数的消息体透传给 Action 和 Guard 使用MessageOrderEventmessageMessageBuilder.withPayload(event).setHeader(orderId,orderId).build();// 4. 发送事件驱动流转booleansuccessstateMachine.sendEvent(message);if(!success){thrownewRuntimeException(订单状态流转失败不合法的操作事件);}}}5、Spring StateMachine 的高阶特性5.1、伪状态分支选择Choice / Junction在状态图里面“用户支付”直接去了“待发货”。但在实际业务中用户付完钱后可能触发风控拦截。Spring 支持类似代码中 if-else 的图纸节点// 配置流转时使用 choicetransitions.withChoice().source(OrderState.PENDING_PAY).first(OrderState.PENDING_DELIVER,checkStockGuard())// 库存够去待发货.last(OrderState.CANCELLED);// 库存不够直接去已取消5.2、嵌套状态Substates / Hierarchical States比如“退款中”是一个大状态但里面又细分为“买家寄出”、“商家驳回”、“等待小二介入”等子状态。Spring StateMachine 支持在一张图里套另一张图子状态未能处理的事件会自动向上冒泡给父状态处理。5.3、并行区域Orthogonal Regions一个复杂的实体如汽车出厂检查需要同时满足“外观检查完成”和“发动机检测完成”这两个并行的、互不干扰的状态轴最后会合Join后才能进入“允许出厂”。Spring 状态机可以在单台机器里同时跑多根独立的状态流转线。6、总结维度Spring StateMachineola-StateMachine开销与性能较重。每次请求都要经历创建/获取 - 停止 - 内存恢复 - 启动 - 发送事件 - 拦截写库的全生命周期高并发下对内存和性能有一定损耗。极轻。纯无状态静态路由表单例运行几乎没有额外开销。能丰富度天花板级别。只有你想不到没有它做不到的复杂拓扑图。仅支持基础的外部流转、内部流转。上手难度较高API 较为复杂全面转向响应式编程 Reactive Streams。极低十分钟即可上手。