引言:状态管理的困境与解决方案
你是否还在为业务系统中的状态流转逻辑混乱而头疼?订单从创建到支付再到发货的状态变化,用户从注册到认证再到活跃的生命周期管理,这些复杂的状态流转往往导致代码中充斥着大量的if-else判断和状态检查,不仅难以维护,还容易引发bug。
一、状态机核心概念与COLA组件架构
状态机基础概念
状态机(State Machine)是一种数学模型,用于描述对象在其生命周期中的状态变化过程。在软件工程中,状态机模式常用于处理具有复杂状态转换的业务逻辑。核心概念包括:
- 状态(State):对象在特定时间点的状况,如订单的"待支付"、"已支付"状态
- 事件(Event):触发状态转换的动作或条件,如"支付成功"事件
- 转换(Transition):从一个状态到另一个状态的变化过程
- 动作(Action):在状态转换过程中执行的业务逻辑
- 条件(Condition):判断是否允许执行某个状态转换的规则
二、cola-statemachine介绍
COLA框架的状态机组件是一种轻量级的、无状态的、基于注解的状态机实现,可以方便地管理订单等业务对象的状态转换。COLA框架的状态机使用了连贯接口(Fluent Interfaces)来定义状态和事件,以及对应的动作和检查。COLA框架的状态机是COLA 4.0应用架构的一部分,旨在控制复杂度,提高开发效率。
COLA框架的状态机的优势有以下几点:
- 简化了状态转换的逻辑,避免了大量的if-else判断
- 提高了代码的可读性和可维护性,方便了单元测试和重构
- 支持多种状态机模式,如同步、异步、延迟等
- 与COLA框架的其他组件协同工作,实现领域驱动设计和六边形架构
2.2 COLA状态机基础模型
在Cola-StateMachine组件中有如下的抽象概念模型:
- 1.State:状态
- 2.Event:事件,状态由事件触发,引起变化
- 3.Transition:流转,表示从一个状态到另一个状态
- 4.External Transition:外部流转,两个不同状态之间的流转
- 5.Internal Transition:内部流转,同一个状态之间的流转
- 6.Condition:条件,表示是否允许到达某个状态
- 7.Action:动作,到达某个状态之后,可以做什么
- 8.StateMachine:状态机
2.3 COLA状态机组件架构
COLA框架的状态机组件(cola-component-statemachine)采用面向对象设计,提供了灵活的状态流转建模能力。其核心接口关系如下:

主要接口功能说明:
- StateMachine:状态机核心接口,提供事件触发、状态验证等方法
- State:状态接口,管理从该状态出发的所有转换
- Transition:转换接口,定义状态间的转换规则和行为
- StateMachineFactory:状态机工厂类,负责状态机的注册和获取
2.4 Cola-StateMachine链路图

三、快速入门:构建你的第一个状态机
3.1 基本状态机实现步骤
使用COLA状态机构建业务流转系统通常遵循以下步骤:
- 定义状态和事件枚举:确定业务领域中的状态集合和触发事件
- 创建上下文对象:封装状态转换过程中需要传递的数据
- 构建状态机:使用构建器定义状态间的转换规则
- 注册并获取状态机实例:通过工厂类管理状态机
- 触发事件并处理结果:在业务逻辑中调用状态机处理状态转换
3.2 环境准备与依赖引入
要使用COLA状态机组件,首先需要在项目中引入依赖:
<dependency>
<groupId>com.alibaba.cola</groupId>
<artifactId>cola-component-statemachine</artifactId>
<version>最新版本</version>
</dependency>
3.3 定义订单的实体类、订单状态的枚举值、订单事件的枚举值
@Getter
@AllArgsConstructor
public enum OrderState {
CREATED(0,"已创建"),
PAID(1,"已支付"),
SHIPPED(2,"已发货"),
DELIVERED(3,"已送达"),
CANCELLED(4,"已取消"),
;
private final Integer code;
private final String msg;
}
@Getter
@AllArgsConstructor
public enum OrderEvent {
PAY(0,"支付"),
SHIP(1,"发货"),
DELIVER(2,"送达"),
CANCEL(3,"取消"),
;
private final Integer code;
private final String msg;
}
@Data
@Builder
public class OrderContext {
@ApiModelProperty("订单ID")
private Integer orderId;
@ApiModelProperty("用户ID")
private String userId;
@ApiModelProperty("订单金额")
private BigDecimal amount;
@ApiModelProperty("备注信息")
private String remark;
}
3.4 ColaStateMachineConfig,主要负责 Cola StateMachine 的配置
public class ColaStateMachineConfig {
public StateMachineBuilder<OrderState, OrderEvent, OrderContext> createBuilder() {
// 3.1 创建状态机构建器
StateMachineBuilder<OrderState, OrderEvent, OrderContext> builder =
StateMachineBuilderFactory.create();
// 3.2 定义状态转换规则
// 已创建 -> 已支付 (支付事件)
builder.externalTransition()
.from(OrderState.CREATED)
.to(OrderState.PAID)
.on(OrderEvent.PAY)
.when(checkPaymentCondition())
.perform(updateOrderStatusAction());
// 已支付 -> 已发货 (发货事件)
builder.externalTransition()
.from(OrderState.PAID)
.to(OrderState.SHIPPED)
.on(OrderEvent.SHIP)
.when(checkStockCondition())
.perform(createShipmentAction());
// 已发货 -> 已送达 (送达事件)
builder.externalTransition()
.from(OrderState.SHIPPED)
.to(OrderState.DELIVERED)
.on(OrderEvent.DELIVER)
.perform(completeOrderAction());
// 已创建 -> 已取消 (取消事件)
builder.externalTransition()
.from(OrderState.CREATED)
.to(OrderState.CANCELLED)
.on(OrderEvent.CANCEL)
.when(checkCancelCondition())
.perform(cancelOrderAction());
return builder;
}
// 条件判断:检查支付条件
private static Condition<OrderContext> checkPaymentCondition() {
return context -> {
// 实际业务中可能检查余额、支付方式等
System.out.println("检查订单[" + context.getOrderId() + "]的支付条件");
return context.getAmount().compareTo(BigDecimal.ZERO) > 0;
};
}
// 条件判断:检查库存条件
private static Condition<OrderContext> checkStockCondition() {
return context -> {
// 实际业务中可能检查商品库存
System.out.println("检查订单[" + context.getOrderId() + "]的库存状况");
return true;
};
}
// 条件判断:检查取消条件
private static Condition<OrderContext> checkCancelCondition() {
return context -> {
// 实际业务中可能检查取消时限、权限等
System.out.println("检查订单[" + context.getOrderId() + "]的取消条件");
return true;
};
}
// 动作:更新订单状态
private static Action<OrderState, OrderEvent, OrderContext> updateOrderStatusAction() {
return (from, to, event, context) -> {
System.out.println("执行订单[" + context.getOrderId() + "]状态更新: " + from + " -> " + to);
// 实际业务中可能更新数据库记录、发送通知等
};
}
// 动作:创建物流单
private static Action<OrderState, OrderEvent, OrderContext> createShipmentAction() {
return (from, to, event, context) -> {
System.out.println("为订单[" + context.getOrderId() + "]创建物流单");
// 实际业务中可能调用物流系统API
};
}
// 动作:完成订单
private static Action<OrderState, OrderEvent, OrderContext> completeOrderAction() {
return (from, to, event, context) -> {
System.out.println("订单[" + context.getOrderId() + "]已完成,执行后续处理");
// 实际业务中可能触发积分发放、评价提醒等
};
}
// 动作:取消订单
private static Action<OrderState, OrderEvent, OrderContext> cancelOrderAction() {
return (from, to, event, context) -> {
System.out.println("订单[" + context.getOrderId() + "]已取消,执行取消处理");
// 实际业务中可能触发退款、库存释放等
};
}
}
3.5 ColaStateMachineService,主要是封装了状态机的调用入口
@Service
@Slf4j
public class ColaStateMachineService {
private static final String MACHINE_ID = "orderStateMachine";
private StateMachine<OrderState, OrderEvent, OrderContext> stateMachine;
@PostConstruct
public void init() {
ColaStateMachineConfig config = new ColaStateMachineConfig();
StateMachineBuilder<OrderState, OrderEvent, OrderContext> stateMachineBuilder = config.createBuilder();
// 3.3 构建并注册状态机
stateMachine = stateMachineBuilder.build(MACHINE_ID);
//StateMachineFactory.register(stateMachine);
}
public String getMachineId(){
return stateMachine.getMachineId();
}
public String generatePlantUML(){
return stateMachine.generatePlantUML();
}
public OrderState fireEvent(OrderState source, OrderEvent event, OrderContext context) {
return stateMachine.fireEvent(source, event, context);
}
public Boolean verify(OrderState source, OrderEvent event) {
return stateMachine.verify(source, event);
}
}
3.6 定义一个 controller 的操作接口
@RequestMapping("/order")
@RestController
@Slf4j
public class OrderOperaController {
@Resource
private ColaStateMachineService colaStateMachineService;
/**
* 场景1-用户支付订单
*
* @return {@link Boolean}
*/
@PostMapping("/pay")
public Boolean pay() {
String machineId = colaStateMachineService.getMachineId();
System.out.println(machineId);
OrderContext order = OrderContext.builder().orderId(1).userId("USER_123").amount(new BigDecimal("99.99")).build();
OrderState orderState = colaStateMachineService.fireEvent(OrderState.CREATED, OrderEvent.PAY, order);
System.out.println(orderState.toString());
return true;
}
/**
* 场景2-订单发货
*
* @return {@link Boolean}
*/
@PostMapping("/ship")
public Boolean ship() {
String machineId = colaStateMachineService.getMachineId();
System.out.println(machineId);
OrderContext order = OrderContext.builder().orderId(1).userId("USER_123").amount(new BigDecimal("99.99")).build();
OrderState orderState = colaStateMachineService.fireEvent(OrderState.PAID, OrderEvent.SHIP, order);
System.out.println(orderState.toString());
return true;
}
/**
* 场景3-订单送达
*
* @return {@link Boolean}
*/
@PostMapping("/deliver")
public Boolean deliver() {
String machineId = colaStateMachineService.getMachineId();
System.out.println(machineId);
OrderContext order = OrderContext.builder().orderId(1).userId("USER_123").amount(new BigDecimal("99.99")).build();
boolean canShip = colaStateMachineService.verify(OrderState.SHIPPED, OrderEvent.DELIVER);
System.out.println(canShip);
OrderState orderState = colaStateMachineService.fireEvent(OrderState.SHIPPED, OrderEvent.DELIVER, order);
System.out.println(orderState.toString());
return true;
}
/**
* 场景4-检查错误关闭订单
*
* @return {@link Boolean}
*/
@PostMapping("/cancel")
public Boolean cancel() {
String machineId = colaStateMachineService.getMachineId();
System.out.println(machineId);
OrderContext order = OrderContext.builder().orderId(1).userId("USER_123").amount(new BigDecimal("99.99")).build();
OrderState orderState = colaStateMachineService.fireEvent(OrderState.CREATED, OrderEvent.CANCEL, order);
System.out.println(orderState.toString());
return true;
}
}
上述代码定义了一个简单的订单状态机,包含从创建到支付、发货、送达的正常流程,以及从创建到取消的异常流程。每个状态转换都定义了触发事件、前置条件和执行动作,使业务逻辑更加清晰和可维护。
四、COLA状态机核心接口详解
4.1 StateMachine接口
StateMachine接口是COLA状态机组件的核心,定义了状态机的基本操作:
public interface StateMachine<S, E, C> extends Visitable {
/**
* 验证事件是否可以从当前状态触发
* @param sourceStateId 当前状态
* @param event 要触发的事件
* @return 如果可以触发则返回true,否则返回false
*/
boolean verify(S sourceStateId, E event);
/**
* 触发事件并执行状态转换
* @param sourceState 源状态
* @param event 要触发的事件
* @param ctx 上下文对象
* @return 转换后的目标状态
*/
S fireEvent(S sourceState, E event, C ctx);
/**
* 触发并行事件,返回多个目标状态
* @param sourceState 源状态
* @param event 要触发的事件
* @param ctx 上下文对象
* @return 转换后的多个目标状态列表
*/
List<S> fireParallelEvent(S sourceState, E event, C ctx);
/**
* 获取状态机ID
* @return 状态机唯一标识符
*/
String getMachineId();
/**
* 显示状态机结构
*/
void showStateMachine();
/**
* 生成PlantUML描述
* @return PlantUML格式的状态机描述字符串
*/
String generatePlantUML();
}
关键方法解析
- verify():在实际触发事件前验证转换是否合法,避免无效的状态转换尝试
- fireEvent():核心方法,处理单一路径的状态转换
- fireParallelEvent():处理并行分支的状态转换,返回多个目标状态
- generatePlantUML():生成可视化描述,便于状态机结构的理解和调试
4.2 State和Transition接口
- State接口表示状态机中的一个状态节点,管理从该状态出发的所有转换:
public interface State<S, E, C> extends Visitable {
/**
* 获取状态ID
* @return 状态标识符
*/
S getId();
/**
* 为状态添加转换规则
* @param event 触发事件
* @param target 目标状态
* @param transitionType 转换类型
* @return 新创建的转换对象
*/
Transition<S, E, C> addTransition(E event, State<S, E, C> target, TransitionType transitionType);
/**
* 获取指定事件的所有转换
* @param event 事件
* @return 转换列表
*/
List<Transition<S, E, C>> getEventTransitions(E event);
/**
* 获取该状态的所有转换
* @return 转换集合
*/
Collection<Transition<S, E, C>> getAllTransitions();
}
- Transition接口表示从一个状态到另一个状态的转换:
public interface Transition<S, E, C> {
/**
* 获取源状态
* @return 源状态
*/
State<S, E, C> getSource();
/**
* 获取触发事件
* @return 事件
*/
E getEvent();
/**
* 获取目标状态
* @return 目标状态
*/
State<S, E, C> getTarget();
/**
* 获取转换条件
* @return 条件对象
*/
Condition<C> getCondition();
/**
* 获取转换动作
* @return 动作对象
*/
Action<S, E, C> getAction();
/**
* 执行状态转换
* @param ctx 上下文对象
* @param checkCondition 是否检查条件
* @return 转换后的目标状态
*/
State<S, E, C> transit(C ctx, boolean checkCondition);
}
4.3 状态机工厂与构建器
COLA提供了StateMachineBuilder和StateMachineFactory来简化状态机的创建和管理:
// 创建状态机构建器
StateMachineBuilder<OrderState, OrderEvent, OrderContext> builder =
StateMachineBuilderFactory.create();
// 构建状态机
StateMachine<OrderState, OrderEvent, OrderContext> stateMachine =
builder.build(MACHINE_ID);
// 注册状态机
StateMachineFactory.register(stateMachine);
// 获取状态机实例
StateMachine<OrderState, OrderEvent, OrderContext> orderMachine =
StateMachineFactory.get(MACHINE_ID);
五、复杂业务流转场景实现
5.1 条件分支与选择转换
在实际业务中,常常需要根据不同条件执行不同的状态转换。例如,订单支付后根据金额大小决定后续处理流程:
// 定义订单金额阈值
BigDecimal VIP_THRESHOLD = new BigDecimal("1000");
// 已支付 -> 普通处理流程 (金额 < 1000)
builder.externalTransition()
.from(OrderState.PAID)
.to(OrderState.PROCESSING_NORMAL)
.on(OrderEvent.PROCESS)
.when(ctx -> ctx.getAmount().compareTo(VIP_THRESHOLD) < 0)
.perform(normalProcessingAction());
// 已支付 -> VIP处理流程 (金额 >= 1000)
builder.externalTransition()
.from(OrderState.PAID)
.to(OrderState.PROCESSING_VIP)
.on(OrderEvent.PROCESS)
.when(ctx -> ctx.getAmount().compareTo(VIP_THRESHOLD) >= 0)
.perform(vipProcessingAction());
上述代码中,相同的PROCESS事件根据订单金额触发不同的状态转换,实现了条件分支逻辑。
5.2 并行分支与合并
某些业务场景需要从一个状态同时转换到多个状态,然后在后续步骤中合并。例如,订单支付后同时触发物流和财务两个并行流程:
// 并行分支示例:支付后同时触发物流和财务流程
builder.externalParallelTransition()
.from(OrderState.PAID)
.toAmong(OrderState.LOGISTICS_PROCESSING, OrderState.FINANCE_PROCESSING)
.on(OrderEvent.PROCESS)
.when(checkParallelCondition())
.perform(parallelProcessAction());
// 物流流程完成
builder.externalTransition()
.from(OrderState.LOGISTICS_PROCESSING)
.to(OrderState.LOGISTICS_COMPLETED)
.on(OrderEvent.LOGISTICS_DONE)
.perform(logisticsCompletedAction());
// 财务流程完成
builder.externalTransition()
.from(OrderState.FINANCE_PROCESSING)
.to(OrderState.FINANCE_COMPLETED)
.on(OrderEvent.FINANCE_DONE)
.perform(financeCompletedAction());
// 两个并行流程都完成后合并
builder.externalTransitions()
.fromAmong(OrderState.LOGISTICS_COMPLETED, OrderState.FINANCE_COMPLETED)
.to(OrderState.ALL_PROCESSED)
.on(OrderEvent.MERGE)
.when(checkAllCompletedCondition())
.perform(mergeProcessAction());
触发并行事件并处理结果:
// 触发并行事件
List<OrderState> parallelStates = orderMachine.fireParallelEvent(
OrderState.PAID, OrderEvent.PROCESS, context);
// 输出并行分支状态
System.out.println("并行分支状态:");
for (OrderState state : parallelStates) {
System.out.println("- " + state);
}
// 输出:
// 并行分支状态:
// - LOGISTICS_PROCESSING
// - FINANCE_PROCESSING
5.3 自循环与内部转换
内部转换(Internal Transition)是指不改变当前状态但执行某些动作的转换,常用于状态的自循环更新:
// 内部转换示例:订单处理中超时提醒
builder.internalTransition()
.within(OrderState.PROCESSING)
.on(OrderEvent.REMIND)
.when(checkProcessingTimeCondition())
.perform(sendReminderAction());
触发内部转换:
// 当前状态不变,但执行提醒动作
OrderState currentState = OrderState.PROCESSING;
OrderState newState = orderMachine.fireEvent(currentState, OrderEvent.REMIND, context);
System.out.println("订单状态: " + newState); // 输出: 订单状态: PROCESSING
5.4 历史状态与子状态机
对于复杂业务领域,可以将状态机分层设计,通过历史状态记录和子状态机实现更高级的状态管理:
// 定义子状态机:退款流程
StateMachine<RefundState, RefundEvent, RefundContext> refundMachine = buildRefundSubMachine();
// 在主状态机中引用子状态机
builder.externalTransition()
.from(OrderState.PAID)
.to(OrderState.REFUND_PROCESSING)
.on(OrderEvent.REFUND)
.when(checkRefundCondition())
.perform(ctx -> {
// 调用子状态机处理退款流程
RefundContext refundCtx = convertToRefundContext(ctx);
refundMachine.fireEvent(RefundState.INITIATED, RefundEvent.PROCESS, refundCtx);
});
六、可视化与调试
6.1 生成PlantUML状态图
COLA状态机提供了generatePlantUML()方法,可以生成PlantUML格式的状态图描述,便于可视化和调试:
// 生成PlantUML描述
String plantUml = stateMachine.generatePlantUML();
System.out.println(plantUml);
- 生成的PlantUML描述可以通过PlantUML工具渲染为状态图,例如:
@startuml
[*] --> CREATED
CREATED --> PAID : PAY
CREATED --> CANCELLED : CANCEL
PAID --> SHIPPED : SHIP
SHIPPED --> DELIVERED : DELIVER
@enduml
上述描述渲染后将显示完整的订单状态流转图。
6.2 状态机结构展示
通过showStateMachine()方法可以在控制台打印状态机结构:
stateMachine.showStateMachine();
- 输出示例:
StateMachine: orderStateMachine
States:
CREATED
Transitions:
On: PAY, To: PAID, Type: EXTERNAL
On: CANCEL, To: CANCELLED, Type: EXTERNAL
PAID
Transitions:
On: SHIP, To: SHIPPED, Type: EXTERNAL
SHIPPED
Transitions:
On: DELIVER, To: DELIVERED, Type: EXTERNAL
DELIVERED
CANCELLED
七、性能优化与最佳实践
状态机设计最佳实践
- 状态粒度控制:状态划分过细会增加复杂度,过粗则失去状态机的优势,需找到平衡点
- 单一职责原则:一个状态机只负责一个业务领域的状态流转
- 事件命名规范:使用动词或动词短语命名事件(如PAY、SHIP),清晰表达触发动作
- 状态命名规范:使用形容词或过去分词命名状态(如PAID、SHIPPED),表示对象状态
性能优化技巧
- 状态机复用:通过StateMachineFactory共享状态机实例,避免重复创建
- 条件缓存:对于复杂且频繁执行的条件判断,考虑添加缓存机制
- 异步处理:对于耗时的动作,在Action中使用异步处理模式
- 状态预加载:系统启动时预加载常用状态机,避免运行时构建开销
线程安全考量
COLA状态机组件本身是线程安全的,可以在多线程环境下共享使用。但需要注意:
- 1.上下文对象(Context)可能被多个线程访问,需要确保其线程安全性
- 2.Action中的业务逻辑应避免共享可变状态,或采取适当的同步措施
*3. 并行触发同一状态机实例的不同事件是安全的,但同一业务对象的状态转换应保证串行执行
总结与展望
COLA状态机组件通过StateMachine接口提供了一种优雅的方式来处理复杂业务流转逻辑,将传统的if-else判断转换为清晰的状态转换规则,显著提升了代码的可读性和可维护性。本文介绍的核心内容包括:
- 状态机的核心概念及COLA状态机组件的架构设计
- 使用StateMachine接口构建基本状态流转的方法
- 处理条件分支、并行流程等复杂业务场景的技巧
- 状态机的可视化调试和性能优化策略
随着业务复杂度的增长,状态机模式的优势将更加明显。未来可以进一步探索状态机与事件驱动架构(EDA)的结合,以及基于状态机的业务流程自动化。
通过将状态机思想应用到实际业务系统中,开发团队可以构建更加健壮、灵活且易于扩展的业务流转系统,有效应对复杂多变的业务需求。
参考:
https://gitcode.com/gh_mirrors/col/COLA
https://blog.csdn.net/gitblog_00735/article/details/151329646
https://blog.csdn.net/qq_40890575/article/details/129495003
https://segmentfault.com/a/1190000044529545