状态机是什么
状态机用于描述一个系统在不同状态(State)之间,根据事件(Event)或输入(Input)发生转移(Transition)的行为。
即在项目于开发中便是根据不同状态+事件,触发状态流转,是状态模式的一种体现。
状态机的好处
1. 逻辑清晰,提升可读性
- 将隐式的状态流转逻辑显式化,用“状态 + 事件 → 新状态”的规则表达业务流程。
- 开发者、产品经理、测试人员可通过状态图或配置表直观理解系统行为,降低沟通成本。
✅ 例如:订单从“待支付”到“已发货”的路径一目了然,避免在代码中翻找 if-else。
2. 防止非法状态转移,增强健壮性
- 状态机只允许预定义的合法转移,自动拒绝非法操作。
- 可通过 Guard(守卫条件) 在转移前校验业务规则(如“仅未发货订单可取消”)。
✅ 避免出现“已收货的订单被取消”等业务漏洞。
3. 解耦流程控制与业务逻辑
- 状态流转由状态机引擎管理,具体操作(如发通知、扣库存)封装在 Action 中。
- 符合“关注点分离”原则,便于单元测试和逻辑复用。
✅ 修改通知方式不影响状态流转规则。
4. 易于维护与扩展
- 新增状态或事件只需添加新的转移规则,无需修改已有代码(符合开闭原则)。
- 支持通过配置文件(YAML/JSON)或 DSL 定义状态机,实现流程可配置化,甚至热更新。
✅ 促销活动临时增加“定金锁定”状态?只需加几行配置!
5. 支持可视化与审计追踪
- 状态机模型可自动生成状态转移图,用于文档、培训或合规审查。
- 每次状态变更可记录日志,便于问题回溯、监控告警和数据分析。
✅ 运维可快速定位“订单卡在‘待支付’超时未释放”的原因。
状态机将混乱的流程控制转化为结构化、可验证、可演进的规则引擎,是应对复杂业务状态管理的最佳实践之一。
自定义状态机
# 状态枚举类
public enum StateEnum {
START,
INTHEAUDIT,
END;
}
# 事件枚举类
public enum EventEnum {
COMMIT,
APPROVAL;
}
# 自定义状态转换类
public class CcerState implements BaseState<StateEnum,EventEnum>{
static HashMap<String,StateEnum> map = new HashMap<String,StateEnum>();
static {
map.put(StateEnum.START+"-"+EventEnum.COMMIT,StateEnum.INTHEAUDIT);
map.put(StateEnum.INTHEAUDIT+"-"+EventEnum.APPROVAL,StateEnum.END);
}
# 状态转化实现
@Override
public StateEnum tran(StateEnum stateEnum, EventEnum eventEnum) {
if (map.containsKey(stateEnum+"-"+eventEnum)){
return map.get(stateEnum+"-"+eventEnum);
}
throw new RuntimeException("状态转换错误");
}
}
通过上述实现简单Demo,我们也可以看出状态机的部分优势,即状态清晰,触发流转只根据状态与事件即可。 后续新增状态也方便排查, 不过仍然少状态流转后的触发动作,比如增加日志、修改数据库数据等,而且也少了部分校验,需要在业务代码中校验不同条件。
Cola状态机的使用
COLA 状态机是阿里巴巴开源的 COLA(Clean Object-oriented and Layered Architecture)架构 中的一个核心组件,全称为 cola-component-statemachine。它是一个轻量级、无侵入、事件驱动的有限状态机(FSM)实现,专门用于管理复杂业务对象的状态流转逻辑。
关键组成(泛型参数)
S:State(状态类型),如OrderStatus.DRAFTE:Event(事件类型),如OrderEvent.SUBMITC:Context(上下文),即业务对象本身,如Order order
使用示例(订单状态流转)
// 1. 构建状态机,工厂方法构造
StateMachineBuilder<OrderStatus, OrderEvent, Order> builder = StateMachineBuilderFactory.create();
builder.externalTransition()
.from(OrderStatus.CREATED)
.to(OrderStatus.PAID)
.on(OrderEvent.PAY_SUCCESS)
.when(ctx -> ctx.getAmount() > 0) // Guard:金额必须大于0
.perform((from, to, event, ctx) -> { // Action:执行副作用
messageService.sendPaymentSuccess(ctx.getCustomerId());
});
StateMachine<OrderStatus, OrderEvent, Order> sm = builder.build("orderSM");
// 2. 触发状态转移
boolean allowed = sm.fireEvent(order.getStatus(), OrderEvent.PAY_SUCCESS, order);
if (allowed) {
order.setStatus(OrderStatus.PAID); // 注意:状态变更由调用方显式完成
orderRepository.save(order);
}
⚠️ 重要设计原则:COLA 状态机只决策是否允许转移并执行动作,不直接修改业务对象状态。状态更新由应用层(Application Layer)负责,符合“状态机是决策引擎,不是状态存储”的理念。
底层源码
create()
# 通过工厂模式进行对象创建
public class StateMachineBuilderFactory {
public static <S, E, C> StateMachineBuilder<S, E, C> create(){
return new StateMachineBuilderImpl<>();
}
}
public class StateMachineBuilderImpl<S, E, C> implements StateMachineBuilder<S, E, C> {
/**
* 利用map保持状态---》状态、事件、上下文
*/
private final Map<S, State< S, E, C>> stateMap = new ConcurrentHashMap<>();
private final StateMachineImpl<S, E, C> stateMachine = new StateMachineImpl<>(stateMap);
# 一对一状态转变,利用率最高
@Override
public ExternalTransitionBuilder<S, E, C> externalTransition() {
return new TransitionBuilderImpl<>(stateMap, TransitionType.EXTERNAL);
}
# 多对一进行状态流转,利用率较低
@Override
public ExternalTransitionsBuilder<S, E, C> externalTransitions() {
return new TransitionsBuilderImpl<>(stateMap, TransitionType.EXTERNAL);
}
# 内部状态流转,如催发货、催提交等
@Override
public InternalTransitionBuilder<S, E, C> internalTransition() {
return new TransitionBuilderImpl<>(stateMap, TransitionType.INTERNAL);
}
# 构建好之后进行全局处理
@Override
public StateMachine<S, E, C> build(String machineId) {
stateMachine.setMachineId(machineId);
stateMachine.setReady(true);
StateMachineFactory.register(stateMachine);
return stateMachine;
}
/**
* 工厂全局注册
*/
public class StateMachineFactory {
# 唯一id---->状态机
static Map<String /* machineId */, StateMachine> stateMachineMap = new ConcurrentHashMap<>();
public static <S, E, C> void register(StateMachine<S, E, C> stateMachine){
String machineId = stateMachine.getMachineId();
if(stateMachineMap.get(machineId) != null){
throw new StateMachineException("The state machine with id ["+machineId+"] is already built, no need to build again");
}
stateMachineMap.put(stateMachine.getMachineId(), stateMachine);
}
public static <S, E, C> StateMachine<S, E, C> get(String machineId){
StateMachine stateMachine = stateMachineMap.get(machineId);
if(stateMachine == null){
throw new StateMachineException("There is no stateMachine instance for "+machineId+", please build it first");
}
return stateMachine;
}
}
综上所述,Cola的底层实现还是较为简单的,通过两层Map,第一层为全局状态机注册,第二层为状态--->改状态的所有转移规则。
Demo案例
// 定义状态枚举
enum OrderStatus {
CREATED, PAID, SHIPPED, COMPLETED, CANCELLED
}
// 定义事件枚举
enum OrderEvent {
PAY_SUCCESS, SHIP, COMPLETE, CANCEL, REMIND_SHIPMENT
}
// 订单上下文
class Order {
private String customerId;
private double amount;
private OrderStatus status;
public Order(String customerId, double amount) {
this.customerId = customerId;
this.amount = amount;
this.status = OrderStatus.CREATED;
}
// Getter 和 Setter 方法
public String getCustomerId() { return customerId; }
public double getAmount() { return amount; }
public OrderStatus getStatus() { return status; }
public void setStatus(OrderStatus status) { this.status = status; }
}
public class StateMachineDemo {
public static void main(String[] args) {
// 1. 构建状态机
StateMachineBuilder<OrderStatus, OrderEvent, Order> builder = StateMachineBuilderFactory.create();
// 一对一流转: CREATED -> PAID on PAY_SUCCESS when amount > 0
builder.externalTransition()
.from(OrderStatus.CREATED)
.to(OrderStatus.PAID)
.on(OrderEvent.PAY_SUCCESS)
.when(order -> order.getAmount() > 0)
.perform((from, to, event, ctx) -> System.out.println("Order paid successfully."));
// 多对一流转: PAID or SHIPPED -> COMPLETED on COMPLETE
builder.externalTransitions()
.fromAmong(OrderStatus.PAID, OrderStatus.SHIPPED)
.to(OrderStatus.COMPLETED)
.on(OrderEvent.COMPLETE)
.perform((from, to, event, ctx) -> System.out.println("Order completed."));
// 内部流转: 在任何状态下都可以收到 REMIND_SHIPMENT 事件但不改变状态
builder.internalTransition()
.within(OrderStatus.values())
.on(OrderEvent.REMIND_SHIPMENT)
.perform((from, to, event, ctx) -> System.out.println("Reminder sent for shipment."));
// 构建并注册状态机
StateMachine<OrderStatus, OrderEvent, Order> sm = builder.build("orderStateMachine");
// 创建订单实例
Order order = new Order("user123", 99.99);
// 测试状态流转
testStateMachine(sm, order);
}
private static void testStateMachine(StateMachine<OrderStatus, OrderEvent, Order> sm, Order order) {
boolean allowed;
// 尝试支付成功(一对一)
allowed = sm.fireEvent(order.getStatus(), OrderEvent.PAY_SUCCESS, order);
if (allowed) {
order.setStatus(OrderStatus.PAID);
System.out.println("Order status updated to PAID");
} else {
System.out.println("Failed to update order status.");
}
// 发货(假设直接发货)
allowed = sm.fireEvent(order.getStatus(), OrderEvent.SHIP, order);
if (allowed) {
order.setStatus(OrderStatus.SHIPPED);
System.out.println("Order status updated to SHIPPED");
} else {
System.out.println("Failed to update order status.");
}
// 完成订单(多对一)
allowed = sm.fireEvent(order.getStatus(), OrderEvent.COMPLETE, order);
if (allowed) {
order.setStatus(OrderStatus.COMPLETED);
System.out.println("Order status updated to COMPLETED");
} else {
System.out.println("Failed to update order status.");
}
// 发送催发货提醒(内部流转)
allowed = sm.fireEvent(order.getStatus(), OrderEvent.REMIND_SHIPMENT, order);
if (allowed) {
System.out.println("Shipment reminder processed without changing state.");
} else {
System.out.println("Failed to process shipment reminder.");
}
}
}