Cola状态机实战

一.简介

状态机模式通常用于定义一个对象在有限状态间流转的行为,比如常见的订单中,通常有待支付,已支付,已发货,已完成,已取消,已退款等, 且这些状态的转换都是提前定义好的。这样可以用状态机来定义各个状态间的流转事件和触发事件,比如从待支付到已支付需要触发支付操作,而在触发的事件里可以定义不同的操作,比如支付完成之后发放优惠券等。

二.依赖
 <dependency>
     <groupId>com.alibaba.cola</groupId>
     <artifactId>cola-component-statemachine</artifactId>
     <version>最新版本</version>
 </dependency>
三.实战

此处贴出我在项目中使用的状态机的UML图, 其中部分状态是在此项目中的特殊业务状态:

(1)定义状态枚举

状态枚举用于定义状态机会变更到的所有状态

public enum OrderState {

    INIT(1, "已创建"),
    WAITING_FOR_PAY(5, "待支付"),
    WAITING_FOR_ASSIGNED(9,"待分配"),
    ASSIGNED_PART(10,"部分分配"),
    WAITING_FOR_DELIVER(13, "待发货"),
    WAITING_FOR_LOCK(17, "待锁单"),
    COMPLETE(21, "已完成"),
    CANCEL(25, "已取消"),
    WAITING_FOR_REFUND(29, "待退款"),
    REFUNDED(33, "已退款"),
    ;


    private String msg;
    private int code;

    OrderState(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public int getCode() {
        return this.code;
    }

    public String getMsg() {
        return this.msg;
    }

    public static OrderState getInstance(int code) {

        for (OrderState value : values()) {
            if (value.code == code) {
                return value;
            }
        }
        return null;
    }
}
(2)定义事件枚举

事件枚举是状态机会触发的所有事件

public enum OrderEvent {

	CREATE_ORDER(1, "创建订单"),
	PAY(2, "支付"),
	CANCEL_ORDER(3, "取消订单"),
	ASSIGNED(4, "分配号码"),
	PART_ASSIGNED(5, "部分分配"),
	CANCEL_ASSIGNED(6, "取消分配"),
	PART_CANCEL_ASSIGNED(7, "部分取消分配"),
	DELIVERY(8, "发货"),
	LOCK(9, "锁单"),
	APPLY_FOR_REFUND(10, "申请退款"),
	REFUND(11, "退款"),
	;


	private String msg;

	private int code;

	OrderEvent(int code, String msg) {
		this.code = code;
		this.msg = msg;
	}

}
(3)状态机ID

状态机ID是每个状态机的唯一ID, 此处用枚举保存, 也可以用常量

public enum OrderStateMachineIdEnum {

	CARD_ORDER("ORDER_STATE_MACHINE", "订单状态机");

	private String machineId;

	private String name;

	OrderStateMachineIdEnum(String machineId, String name) {
		this.machineId = machineId;
		this.name = name;
	}

	public String getMachineId() {
		return this.machineId;
	}

	public String getName() {
		return this.name;
	}
}

StateMachine<OrderState, OrderEvent, OrderContext> orderStateMachine = StateMachineFactory.get(OrderStateMachineIdEnum.CARD_ORDER.name());

// 此方法用于获取状态机的UML图 生成的是字符串 需要使用工具转换成上面的UML图(直接找个在线工具即可)
System.out.println(orderStateMachine.generatePlantUML());

(4)context

context 是用于在状态机中传输数据的上下文

@Data
@AllArgsConstructor
@NoArgsConstructor
public class OrderContext {

	// 订单编号
	private String orderNo;

	// 其他参数 此处使用超类 Object 可以接收任意类型, 使用时根据类型转换
	private Object context;

}
(5)conditon

condition是用于定义从一个状态扭转到另一个状态的必须条件, 只有返回值为true会执行后续的action

@Slf4j
@Component
public class OrderCheckCancelCondition implements Condition<OrderContext> {


	@Override
	public boolean isSatisfied(OrderContext orderContext) {

		log.info("订单:{},取消前校验完成", orderContext.getOrderNo());
		return true;
	}

}

(6)action

action是用于定义从一个状态扭转到另一个状态之后触发的动作

@Slf4j
@Component
@AllArgsConstructor
public class OrderCreateAction implements Action<OrderState, OrderEvent, OrderContext> {

	private final IOrderService orderService;


	@Override
	public void execute(OrderState from, OrderState to, OrderEvent orderEvent, OrderContext orderContext) {
		log.info("创建订单,订单编号:{}", orderContext.getOrderNo());
		CreateOrderDTO createOrderDTO = (CreateOrderDTO) orderContext.getContext();

		orderService.doCreateOrder(to, orderContext.getOrderNo(), createOrderDTO);

	}

}
(7)状态机配置

cola状态机可以定义内部状态流转,外部状态流转,批量状态流转

externalTransition用于定义外部状态流转, from表示当前状态, to表示扭转后的状态,when表示需要满足的条件, perform表示需要执行的动作(action)

internalTransition用于定于内部状态流转, within表示状态, 内部状态流转不用定义to

externalTransitions用于定义批量状态流转, 也就是从多个状态可以抵达同一个状态,比如: 订单在已发货,已锁单等状态都可以进行退款操作, fromAmong表示多个from的状态

@Component
@AllArgsConstructor
public class OrderStateMachine {

	private final OrderActionHelper orderActionHelper;
	private final OrderConditionHelper orderConditionHelper;


	@PostConstruct
	public StateMachine<OrderState, OrderEvent, OrderContext> createStateMachine() {
		// 创建状态机
		StateMachineBuilder<OrderState, OrderEvent, OrderContext> builder = StateMachineBuilderFactory.create();

		// 外部状态流转 从init到待支付 需要触发创建订单操作
		builder.externalTransition()
			.from(OrderState.INIT)
			.to(OrderState.WAITING_FOR_PAY)
			.on(OrderEvent.CREATE_ORDER)
			.when(orderConditionHelper.getOrderCheckCreateCondition())
			.perform(orderActionHelper.getOrderCreateAction());

		// 外部状态流转 从待支付到已取消 需要触发取消订单操作
		builder.externalTransition()
			.from(OrderState.WAITING_FOR_PAY)
			.to(OrderState.CANCEL)
			.on(OrderEvent.CANCEL_ORDER)
			.when(orderConditionHelper.getOrderCheckCancelCondition())
			.perform(orderActionHelper.getOrderCancelAction());

		// 外部状态流转 从待支付到待分配 需要触发支付操作
		builder.externalTransition()
			.from(OrderState.WAITING_FOR_PAY)
			.to(OrderState.WAITING_FOR_ASSIGNED)
			.on(OrderEvent.PAY)
			.when(orderConditionHelper.getOrderCheckPayCondition())
			.perform(orderActionHelper.getOrderPayAction());

		// 外部状态流转 从待分配到部分分配 需要触发部分分配操作
		builder.externalTransition()
			.from(OrderState.WAITING_FOR_ASSIGNED)
			.to(OrderState.ASSIGNED_PART)
			.on(OrderEvent.PART_ASSIGNED)
			.when(orderConditionHelper.getOrderCheckPartAssignCondition())
			.perform(orderActionHelper.getOrderPartAssignAction());

		// 内部状态流转 部分分配 需要触发部分分配操作
		builder.internalTransition().within(OrderState.ASSIGNED_PART)
			.on(OrderEvent.PART_ASSIGNED)
			.when(orderConditionHelper.getOrderCheckPartAssignCondition())
			.perform(orderActionHelper.getOrderPartAssignAction());

		// 外部状态流转 从待分配,部分分配到待发货 需要触发分配操作
		builder.externalTransitions()
			.fromAmong(OrderState.ASSIGNED_PART, OrderState.WAITING_FOR_ASSIGNED)
			.to(OrderState.WAITING_FOR_DELIVER)
			.on(OrderEvent.ASSIGNED)
			.when(orderConditionHelper.getOrderCheckAssignCondition())
			.perform(orderActionHelper.getOrderAssignAction());

		// 外部状态流转 从待发货到部分分配 需要触发部分取消分配事件
		builder.externalTransition()
			.from(OrderState.WAITING_FOR_DELIVER)
			.to(OrderState.ASSIGNED_PART)
			.on(OrderEvent.PART_CANCEL_ASSIGNED)
			.when(orderConditionHelper.getOrderCheckPartCancelAssignedCondition())
			.perform(orderActionHelper.getOrderPartCancelAssignAction());

		// 外部状态流转 从待发货,部分分配到待分配 需要触发取消分配事件
		builder.externalTransitions()
			.fromAmong(OrderState.WAITING_FOR_DELIVER, OrderState.ASSIGNED_PART)
			.to(OrderState.WAITING_FOR_ASSIGNED)
			.on(OrderEvent.CANCEL_ASSIGNED)
			.when(orderConditionHelper.getOrderCheckCancelAssignCondition())
			.perform(orderActionHelper.getOrderCancelAssignAction());

		// 内部状态流转 部分分配 需要触发部分取消分配操作
		builder.internalTransition().within(OrderState.ASSIGNED_PART)
			.on(OrderEvent.PART_CANCEL_ASSIGNED)
			.when(orderConditionHelper.getOrderCheckPartCancelAssignedCondition())
			.perform(orderActionHelper.getOrderPartCancelAssignAction());

		// 外部状态流转 从待发货到待锁单 需要触发发货事件
		builder.externalTransition()
			.from(OrderState.WAITING_FOR_DELIVER)
			.to(OrderState.WAITING_FOR_LOCK)
			.on(OrderEvent.DELIVERY)
			.when(orderConditionHelper.getOrderCheckDeliveryCondition())
			.perform(orderActionHelper.getOrderDeliveryAction());

		// 外部状态流转 从待锁单到已完成 需要触发锁单事件
		builder.externalTransition()
			.from(OrderState.WAITING_FOR_LOCK)
			.to(OrderState.COMPLETE)
			.on(OrderEvent.LOCK)
			.when(orderConditionHelper.getOrderCheckLockCondition())
			.perform(orderActionHelper.getOrderLockAction());

		// 外部状态流转 从待分配,部分分配,待发货,待锁单,已完成到待退款 需要触发申请退款事件
		builder.externalTransitions()
			.fromAmong(OrderState.WAITING_FOR_ASSIGNED, OrderState.ASSIGNED_PART, OrderState.WAITING_FOR_DELIVER,
				OrderState.WAITING_FOR_LOCK, OrderState.COMPLETE)
			.to(OrderState.WAITING_FOR_REFUND)
			.on(OrderEvent.APPLY_FOR_REFUND)
			.when(orderConditionHelper.getOrderCheckApplyForRefundedCondition())
			.perform(orderActionHelper.getOrderApplyForRefundedAction());

		// 外部状态流转 从待退款到已退款 需要触发退款事件
		builder.externalTransition()
			.from(OrderState.WAITING_FOR_REFUND)
			.to(OrderState.REFUNDED)
			.on(OrderEvent.REFUND)
			.when(orderConditionHelper.getOrderCheckRefundedCondition())
			.perform(orderActionHelper.getOrderRefundedAction());

		return builder.build(OrderStateMachineIdEnum.CARD_ORDER.getMachineId());
	}

}
(9) helper工具类

定义下面两个工具类的目的在于, 在状态机的配置类中就不需要分别注入依赖, 只需要注入这两个Bean就可以, 不想使用这种方式也可以在状态机配置类中分别注入


@Component
@AllArgsConstructor
public class OrderActionHelper {


	private final OrderCreateAction orderCreateAction;
	private final OrderCancelAction orderCancelAction;
	private final OrderPayAction orderPayAction;
	private final OrderPartAssignAction orderPartAssignAction;
	private final OrderAssignAction orderAssignAction;
	private final OrderPartCancelAssignAction orderPartCancelAssignAction;
	private final OrderCancelAssignAction orderCancelAssignAction;
	private final OrderDeliveryAction orderDeliveryAction;
	private final OrderLockAction orderLockAction;
	private final OrderApplyForRefundedAction orderApplyForRefundedAction;
	private final OrderRefundedAction orderRefundedAction;

	public Action<OrderState, OrderEvent, OrderContext> getOrderCreateAction() {
		return orderCreateAction;
	}

	public Action<OrderState, OrderEvent, OrderContext> getOrderCancelAction() {
		return orderCancelAction;
	}

	public Action<OrderState, OrderEvent, OrderContext> getOrderPayAction() {
		return orderPayAction;
	}

	public Action<OrderState, OrderEvent, OrderContext> getOrderPartAssignAction() {
		return orderPartAssignAction;
	}

	public Action<OrderState, OrderEvent, OrderContext> getOrderAssignAction() {
		return orderAssignAction;
	}

	public Action<OrderState, OrderEvent, OrderContext> getOrderPartCancelAssignAction() {
		return orderPartCancelAssignAction;
	}

	public Action<OrderState, OrderEvent, OrderContext> getOrderCancelAssignAction() {
		return orderCancelAssignAction;
	}

	public Action<OrderState, OrderEvent, OrderContext> getOrderDeliveryAction() {
		return orderDeliveryAction;
	}

	public Action<OrderState, OrderEvent, OrderContext> getOrderLockAction() {
		return orderLockAction;
	}

	public Action<OrderState, OrderEvent, OrderContext> getOrderApplyForRefundedAction() {
		return orderApplyForRefundedAction;
	}

	public Action<OrderState, OrderEvent, OrderContext> getOrderRefundedAction() {
		return orderRefundedAction;
	}
}


@Component
@AllArgsConstructor
public class OrderConditionHelper {

	private final OrderCheckCreateCondition orderCheckCreateCondition;
	private final OrderCheckCancelCondition orderCheckCancelCondition;
	private final OrderCheckPayCondition orderCheckPayCondition;
	private final OrderCheckPartAssignCondition orderCheckPartAssignCondition;
	private final OrderCheckAssignCondition orderCheckAssignCondition;
	private final OrderCheckPartCancelAssignedCondition orderCheckPartCancelAssignedCondition;
	private final OrderCheckCancelAssignCondition orderCheckCancelAssignCondition;
	private final OrderCheckDeliveryCondition orderCheckDeliveryCondition;
	private final OrderCheckLockCondition orderCheckLockCondition;
	private final OrderCheckApplyForRefundedCondition orderCheckApplyForRefundedCondition;
	private final OrderCheckRefundedCondition orderCheckRefundedCondition;

	public Condition<OrderContext> getOrderCheckCreateCondition() {
		return orderCheckCreateCondition;
	}

	public Condition<OrderContext> getOrderCheckCancelCondition() {
		return orderCheckCancelCondition;
	}

	public Condition<OrderContext> getOrderCheckPayCondition() {
		return orderCheckPayCondition;
	}

	public Condition<OrderContext> getOrderCheckPartAssignCondition() {
		return orderCheckPartAssignCondition;
	}

	public Condition<OrderContext> getOrderCheckAssignCondition() {
		return orderCheckAssignCondition;
	}

	public Condition<OrderContext> getOrderCheckPartCancelAssignedCondition() {
		return orderCheckPartCancelAssignedCondition;
	}

	public Condition<OrderContext> getOrderCheckCancelAssignCondition() {
		return orderCheckCancelAssignCondition;
	}

	public Condition<OrderContext> getOrderCheckDeliveryCondition() {
		return orderCheckDeliveryCondition;
	}

	public Condition<OrderContext> getOrderCheckLockCondition() {
		return orderCheckLockCondition;
	}

	public Condition<OrderContext> getOrderCheckApplyForRefundedCondition() {
		return orderCheckApplyForRefundedCondition;
	}

	public Condition<OrderContext> getOrderCheckRefundedCondition() {
		return orderCheckRefundedCondition;
	}
}

(10)示例触发事件

通过fireEvent()方法可以触发事件, 如果需要对操作进行加锁, 可以直接对此方法加锁

	public void cancelOrder(String orderNo) {

		StateMachine<OrderState, OrderEvent, OrderContext> orderStateMachine = StateMachineFactory.get(OrderStateMachineIdEnum.CARD_ORDER.getMachineId());

		// 此处使用分布式锁处理
		orderUtil.handlerWithLock(orderNo, () -> {

			OrderRecordEntity order = getByOrderNo(orderNo);
			checkOrderExists(order);

			OrderContext orderContext = new OrderContext();
			orderContext.setOrderNo(orderNo);
			orderContext.setOrder(order);

			OrderState orderState = orderStateMachine.fireEvent(OrderState.getInstance(order.getStatus()), OrderEvent.CANCEL_ORDER, orderContext);

			if (OrderState.CANCEL.getCode() != orderState.getCode()) {
				throw new ServiceException("此状态无法取消订单!");
			}
		});


	}
	/**
	 * 阻塞式获取锁处理订单
	 * @param orderNo
	 * @param runnable
	 */
	public void handlerWithLock(String orderNo, Runnable runnable) {

		RLock orderLock = redissonClient.getLock(orderNo);

		orderLock.lock();

		try {

			runnable.run();

		} finally {

			orderLock.unlock();

		}

	}
### COLA 架构中的状态机实现与使用 COLA(Component Oriented Layered Architecture)是一种面向组件分层的架构设计模式,广泛应用于复杂系统的开发中。在 COLA 中,状态机的设计通常用于处理业务流程的状态转换逻辑。以下是关于 COLA 架构下状态机实现和使用的详细介绍。 #### 状态机的核心概念 状态机是一种数学模型,用来描述对象在其生命周期内的不同状态以及这些状态之间的转换关系。在一个典型的状态机中,主要涉及以下几个核心要素[^1]: - **State (状态)**: 对象可能处于的不同条件或阶段。 - **Event (事件)**: 导致状态变化的触发器。 - **Transition (转换)**: 由某个事件引发的一个状态到另一个状态的变化过程。 - **Action (动作)**: 转换发生时执行的操作。 #### COLA 架构下的状态机实现 在 COLA 架构中,状态机可以被封装成独立的服务或者领域对象的一部分。这种设计使得状态管理更加模块化和可维护。具体实现方式如下: ##### 配置驱动的方式 通过配置文件定义状态及其转换规则,这种方式能够提高灵活性并减少硬编码的可能性。例如,在 XML 或 JSON 文件中定义状态机结构: ```json { "states": ["PENDING", "APPROVED", "REJECTED"], "transitions": [ {"from": "PENDING", "to": "APPROVED", "event": "approve"}, {"from": "PENDING", "to": "REJECTED", "event": "reject"} ] } ``` 上述代码片段展示了如何利用 JSON 来表示简单的状态转移图。 ##### 编程接口的支持 除了静态配置外,还可以提供动态编程接口来操作状态机实例。这允许开发者根据运行时需求调整行为。下面是一个基于 Java 的伪代码例子展示如何创建和调用状态机服务: ```java public class StateMachineService { private Map<String, String> stateTransitions; public void initialize(Map<String, String> transitions){ this.stateTransitions = transitions; } public boolean trigger(String currentState, String event) throws InvalidStateException { if(stateTransitions.containsKey(currentState)){ String nextState = stateTransitions.get(event); // 执行实际的动作... return true; } throw new InvalidStateException("No valid transition found"); } } // 使用示例 StateMachineService service = new StateMachineService(); service.initialize(Collections.singletonMap("approve", "APPROVED")); try { System.out.println(service.trigger("PENDING", "approve")); } catch(InvalidStateException e){ System.err.println(e.getMessage()); } ``` 此段代码说明了如何初始化一个简单状态机并通过特定事件改变其内部状态。 #### COLA 架构中状态机的最佳实践 为了使状态机更易于理解和扩展,在 COLA 架构中有几个推荐的做法: - 将复杂的业务逻辑拆分为多个小型、专注的任务型状态节点。 - 利用 AOP(Aspect-Oriented Programming)技术拦截状态变更前后的额外处理工作。 - 定期审查现有状态集是否仍然满足当前应用的需求,并适时重构。 #### 总结 综上所述,COLA 架构提供了强大的工具支持去构建高效灵活的状态管理系统。无论是采用声明式的配置还是程序化的控制流,都可以显著提升软件项目的质量与性能表现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值