状态机思考-Cola源码分析

73 阅读5分钟

状态机是什么

状态机用于描述一个系统在不同状态(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.DRAFT
  • E:Event(事件类型),如 OrderEvent.SUBMIT
  • C: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.");
        }
    }
}