
状态机,就像现实中的交通信号灯控制器,绿灯(通行)→ 黄灯(过渡)→ 红灯(停止), 这种状态变化的规则就是状态机的典型应用。
Spring 状态机 是基于 Spring 框架的状态机实现,通过 spring-statemachine-core 组件(2.5.0 + 版本),能够帮助我们:
• 规范定义程序状态集合 :如订单的待支付、已支付、配送中、已完成等状态。
• 精准管理状态转换规则 :例如支付事件触发待支付 → 已支付的转换。
• 高效处理状态转换时的业务逻辑 :在状态变化过程中执行相应的操作。
当你的程序面临以下场景时,Spring 状态机将是一个绝佳的选择:
• 业务流程复杂 :涉及多个状态和事件交互,传统 if-else 实现方式难以维护。
• 状态转换规则频繁变化 :需要灵活调整状态转换逻辑,避免代码大量修改。
• 需要对状态进行集中管控 :以便统一监控和管理业务流程的状态变化。
传统 if-else 实现方式存在诸多痛点,例如:
if(currentState == "待支付"){ if(event == "支付"){ if(金额校验通过){ currentState = "已支付"; } } } else if(currentState == "已支付"){ }
这种代码结构随着业务复杂度增加,会变得难以维护和扩展。
在项目中引入 Spring 状态机的依赖,添加以下代码至 pom.xml 文件:
<dependency> <groupId>org.springframework.statemachine</groupId> <artifactId>spring-statemachine-starter</artifactId> <version>3.2.0</version> </dependency>
注解 :
1.该依赖引入了 Spring 状态机的核心功能,为项目提供了状态机的实现和相关 API。
2.版本选择应根据项目实际需求和兼容性进行确定,3.2.0 版本具有良好的稳定性和功能支持。
接下来,定义状态和事件:
public enum OrderStates { UNPAID("待支付"), PAID("已支付"), DELIVERING("配送中"), COMPLETED("已完成"); private final String stateDesc; OrderStates(String stateDesc) { this.stateDesc = stateDesc; } public String getStateDesc() { return stateDesc; } } public enum OrderEvents { PAY("支付"), DELIVER("发货"), CONFIRM_RECEIVE("确认收货"); privatefinal String eventDesc; OrderEvents(String eventDesc) { this.eventDesc = eventDesc; } public String getEventDesc() { return eventDesc; } }
注解 :
1.OrderStates 枚举类定义了订单的四种状态,并为每个状态提供了描述信息,方便后续业务理解和展示。
2.OrderEvents 枚举类定义了订单的三种事件,同样添加了事件描述,使代码更具可读性。
然后,配置状态机:
public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderStates, OrderEvents> { @Override public void configure(StateMachineStateConfigurer<OrderStates, OrderEvents> states)throws Exception { states .withStates() .initial(OrderStates.UNPAID) // 设置初始状态为待支付 .states(EnumSet.allOf(OrderStates.class )); // 添加所有状态 } @Override public void configure(StateMachineTransitionConfigurer<OrderStates, OrderEvents> transitions)throws Exception { transitions .withExternal() // 定义外部转换 .source(OrderStates.UNPAID) // 源状态:待支付 .target(OrderStates.PAID) // 目标状态:已支付 .event(OrderEvents.PAY) // 触发事件:支付 .and() .withExternal() .source(OrderStates.PAID) .target(OrderStates.DELIVERING) .event(OrderEvents.DELIVER) .and() .withExternal() .source(OrderStates.DELIVERING) .target(OrderStates.COMPLETED) .event(OrderEvents.CONFIRM_RECEIVE); } }
注解 :
1.EnumStateMachineConfigurerAdapter 是 Spring 状态机的配置适配器,用于简化状态机的配置过程。
2.在 configure 方法中,通过 withStates() 设置初始状态和所有状态,明确状态机的初始位置和可到达的状态范围。
3.在另一个 configure 方法中,使用 withExternal() 定义外部状态转换规则,依次设置源状态、目标状态和触发事件,清晰地展示了订单在不同状态之间的转换路径。
在业务逻辑中使用状态机:
public class OrderService { private StateMachine<OrderStates, OrderEvents> stateMachine; public OrderService(StateMachine<OrderStates, OrderEvents> stateMachine) { this.stateMachine = stateMachine; } public void handleEvent(OrderEvents event) { stateMachine.sendEvent(event); // 发送事件,触发状态转换 OrderStatescurrentState= stateMachine.getState().getId(); System.out.println("[状态跟踪] 当前订单状态:" + currentState.getStateDesc()); } }
注解 :
1.通过构造方法注入状态机实例,使其能够在业务逻辑中使用。
2.handleEvent 方法接收事件并发送给状态机,利用状态机的 sendEvent 方法触发状态转换。
3.获取当前状态并输出其描述信息,便于实时跟踪订单状态变化。
实现状态机监听器:
public class StateMachineListener extends StateMachineListenerAdapter<OrderStates, OrderEvents> { @Override public void transition(Transition<OrderStates, OrderEvents> transition) { System.out.printf("[状态机日志] 开始转换:%s -> %s (事件:%s)%n", transition.getSource().getId().getStateDesc(), transition.getTarget().getId().getStateDesc(), transition.getTrigger().getEvent().getEventDesc()); } @Override public void stateChanged(State<OrderStates, OrderEvents> from, State<OrderStates, OrderEvents> to) { System.out.println("[状态机日志] 转换完成,当前状态:" + to.getId().getStateDesc()); } }
注解 :
1.继承 StateMachineListenerAdapter 类,重写 transition 和 stateChanged 方法,实现对状态转换过程的监听。
2.在 transition 方法中,获取转换的源状态、目标状态和触发事件的描述信息,输出转换开始日志。
3.在 stateChanged 方法中,输出转换完成后的当前状态描述,方便对状态变化进行监控和记录。
Spring 状态机通过规范化的状态管理,能够有效提升复杂业务流程的可维护性。
它将业务流程中的状态和事件进行清晰的定义和管理,使得代码结构更加清晰、易于理解和维护。
以上内容对 Spring 状态机进行了简单介绍,希望对你有所帮助。
本文作者:Allen Tang
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!