一、基本概念
状态机(state machine) 是一种行为模型,定义了一组状态、状态之间的转换(事件驱动)、以及在状态转换时触发的动作。spring statemachine 提供了强大的框架支持,帮助开发者管理和驱动复杂的状态流。
核心要素:
- state(状态):对象所处的不同阶段。
- event(事件):触发状态转换的动作。
- transition(转换):状态之间的转换过程。
- action(动作):状态转换时执行的业务逻辑。
二、核心组件
- statemachine:状态机核心接口,负责状态管理和事件驱动。
- statemachineconfigureradapter:状态机配置适配器,用户自定义状态、事件、转换逻辑。
- statemachinefactory:状态机工厂,创建状态机实例。
- actions:状态转换时执行的具体业务逻辑。
- guards:转换前的条件判断。
三、引入依赖
<!-- maven依赖 -->
<dependency>
<groupid>org.springframework.statemachine</groupid>
<artifactid>spring-statemachine-core</artifactid>
<version>4.0.0</version>
</dependency>四、定义状态和事件
以订单流程为例:
public enum orderstates {
created, paid, shipped, completed, cancelled
}
public enum orderevents {
pay, ship, complete, cancel
}五、配置状态机
通过继承 statemachineconfigureradapter 进行配置:
@configuration
@enablestatemachine
public class orderstatemachineconfig extends statemachineconfigureradapter<orderstates, orderevents> {
@override
public void configure(statemachinestateconfigurer<orderstates, orderevents> states) throws exception {
states
.withstates()
.initial(orderstates.created)
.states(enumset.allof(orderstates.class));
}
@override
public void configure(statemachinetransitionconfigurer<orderstates, orderevents> transitions) throws exception {
transitions
.withexternal().source(orderstates.created).target(orderstates.paid).event(orderevents.pay)
.and()
.withexternal().source(orderstates.paid).target(orderstates.shipped).event(orderevents.ship)
.and()
.withexternal().source(orderstates.shipped).target(orderstates.completed).event(orderevents.complete)
.and()
.withexternal().source(orderstates.created).target(orderstates.cancelled).event(orderevents.cancel)
.and()
.withexternal().source(orderstates.paid).target(orderstates.cancelled).event(orderevents.cancel);
}
}六、使用状态机
注入并驱动状态机:
@autowired
private statemachine<orderstates, orderevents> statemachine;
public void processorder() {
statemachine.start();
statemachine.sendevent(orderevents.pay);
statemachine.sendevent(orderevents.ship);
statemachine.sendevent(orderevents.complete);
}七、添加动作和条件
1. 动作(action)
@bean
public action<orderstates, orderevents> payaction() {
return context -> {
system.out.println("订单已支付,执行相关业务逻辑");
};
}
@override
public void configure(statemachinetransitionconfigurer<orderstates, orderevents> transitions) throws exception {
transitions
.withexternal()
.source(orderstates.created).target(orderstates.paid).event(orderevents.pay)
.action(payaction())
// 其他转换...
}2. 条件(guard)
@bean
public guard<orderstates, orderevents> payguard() {
return context -> {
// 只有金额大于0才能支付
integer amount = (integer) context.getmessageheader("amount");
return amount != null && amount > 0;
};
}
@override
public void configure(statemachinetransitionconfigurer<orderstates, orderevents> transitions) throws exception {
transitions
.withexternal()
.source(orderstates.created).target(orderstates.paid).event(orderevents.pay)
.guard(payguard())
// 其他转换...
}八、持久化状态机(可选)
spring statemachine 支持状态持久化,可用 redis、jpa 等存储状态,适合分布式场景。
九、最佳实践
- 合理拆分状态与事件,避免过于复杂的状态流。
- 利用动作和条件,实现业务与状态解耦。
- 持久化状态机,保证高可用和一致性。
- 结合 @withstatemachine 注解,方便事件监听与回调。
十一、进阶用法
1. 状态监听器(statemachinelistener)
可以通过监听器获取状态变化、事件处理、异常等回调:
@component
public class orderstatemachinelistener extends statemachinelisteneradapter<orderstates, orderevents> {
@override
public void statechanged(state<orderstates, orderevents> from, state<orderstates, orderevents> to) {
system.out.println("状态从 " + (from == null ? "none" : from.getid()) + " 变为 " + to.getid());
}
@override
public void eventnotaccepted(message<orderevents> event) {
system.out.println("事件未被接受: " + event.getpayload());
}
}注册监听器:
@autowired
private statemachine<orderstates, orderevents> statemachine;
@autowired
private orderstatemachinelistener listener;
@postconstruct
public void addlistener() {
statemachine.addstatelistener(listener);
}2. 状态机嵌套(子状态机)
spring statemachine 支持嵌套状态(hierarchical states),适合复杂流程。
@override
public void configure(statemachinestateconfigurer<orderstates, orderevents> states) throws exception {
states
.withstates()
.initial(orderstates.created)
.state(orderstates.paid)
.and()
.withstates()
.parent(orderstates.paid)
.initial(orderstates.paid_sub1)
.state(orderstates.paid_sub2);
}3. 状态机持久化
以 redis 为例,持久化状态机:
@bean
public statemachinepersister<orderstates, orderevents, string> persister(
redisstatemachinepersister<orderstates, orderevents> persister) {
return persister;
}
// 保存状态
persister.persist(statemachine, "orderid-123");
// 恢复状态
persister.restore(statemachine, "orderid-123");4. 多实例状态机
对于每个业务对象(如订单),建议为每个对象创建独立的状态机实例:
@autowired
private statemachinefactory<orderstates, orderevents> factory;
public void handleorder(string orderid) {
statemachine<orderstates, orderevents> sm = factory.getstatemachine(orderid);
sm.start();
sm.sendevent(orderevents.pay);
}5. 结合spring事件机制
可以通过监听 statemachineevent,实现解耦的业务响应。
十二、常见问题
状态未切换?
- 检查事件是否正确发送,状态机是否
start(),guard 是否返回 true。
- 检查事件是否正确发送,状态机是否
状态机线程安全?
- 默认是线程不安全的,业务并发场景下请为每个业务对象创建独立状态机实例。
如何调试?
- 打开日志:
logging.level.org.springframework.statemachine=debug,方便追踪状态流转。
- 打开日志:
如何与数据库结合?
- 利用持久化接口,将状态机状态存入数据库,保证分布式一致性。
十三、实战建议
- 不要把所有业务逻辑都塞到 action,只做与状态相关的处理,复杂逻辑建议外部调用。
- 事件驱动:外部只需发事件,状态机自动处理后续流转。
- 解耦:状态机只关注流程和状态,业务逻辑在合适的位置实现。
- 测试:多写单元测试,覆盖各个状态和异常流转。
十四、完整示例
1. 配置类
@configuration
@enablestatemachinefactory
public class orderstatemachineconfig extends statemachineconfigureradapter<orderstates, orderevents> {
// 状态、事件、转移配置同上
}2. 业务调用
@service
public class orderservice {
@autowired
private statemachinefactory<orderstates, orderevents> factory;
public void payorder(string orderid) {
statemachine<orderstates, orderevents> sm = factory.getstatemachine(orderid);
sm.start();
sm.sendevent(orderevents.pay);
// 可持久化 sm
}
}3. 持久化(可选)
@autowired
private statemachinepersister<orderstates, orderevents, string> persister;
public void savestate(statemachine<orderstates, orderevents> sm, string orderid) throws exception {
persister.persist(sm, orderid);
}
public void restorestate(statemachine<orderstates, orderevents> sm, string orderid) throws exception {
persister.restore(sm, orderid);
}到此这篇关于spring statemachine 使用小结的文章就介绍到这了,更多相关spring statemachine 使用内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论