978 lines
27 KiB
Markdown
978 lines
27 KiB
Markdown
# Part 5: 架构重构实践
|
||
|
||
本文档详细记录 Ops 模块架构重构的完整实践过程,为未来的架构演进提供参考。
|
||
|
||
---
|
||
|
||
## 5.1 问题识别
|
||
|
||
在阶段2和阶段3的实施过程中,我们发现了一些架构问题,需要进行重构。
|
||
|
||
### 5.1.1 DispatchEngine 职责不清晰
|
||
|
||
**问题表现**:
|
||
|
||
DispatchEngine 接口定义了 13 个方法,但很多方法返回 null 或空实现:
|
||
|
||
```java
|
||
public interface DispatchEngine {
|
||
AssigneeRecommendation recommendAssignee(DispatchContext context);
|
||
|
||
// 以下方法职责不清晰
|
||
void autoDispatch(Long orderId); // 实际只是调用 orderQueueService.startExecution()
|
||
void handleOrderCompleted(Long orderId); // 业务逻辑,不应该在引擎中
|
||
void notifyAssignee(Long assigneeId); // 设备通知,不应该在引擎中
|
||
|
||
// 还有 10 个类似的方法...
|
||
}
|
||
```
|
||
|
||
**问题分析**:
|
||
|
||
1. **职责边界模糊**:派单引擎混合了决策、业务逻辑、设备通知等多种职责
|
||
2. **命名误导**:`autoDispatch` 看起来是自动派单,实际只是更新队列状态
|
||
3. **扩展困难**:新增业务类型时,需要修改 DispatchEngine 核心代码
|
||
|
||
**影响**:
|
||
- 开发人员困惑:不知道哪些功能应该放在 DispatchEngine 中
|
||
- 测试困难:职责过多导致单元测试复杂
|
||
- 维护成本高:修改一处可能影响多个功能
|
||
|
||
### 5.1.2 通用方法抽离不彻底
|
||
|
||
**问题表现**:
|
||
|
||
`OpsOrderService` 只有基础的 CRUD 操作,暂停/恢复等通用功能散落在各处:
|
||
|
||
```java
|
||
// OpsOrderService 中只有基础操作
|
||
public interface OpsOrderService {
|
||
Long createOrder(OrderCreateReqDTO reqDTO);
|
||
void updateOrder(OrderUpdateReqDTO reqDTO);
|
||
void deleteOrder(Long orderId);
|
||
OpsOrderRespDTO getOrder(Long orderId);
|
||
}
|
||
|
||
// 暂停/恢复逻辑直接在 CleanOrderService 中实现
|
||
@Service
|
||
public class CleanOrderServiceImpl {
|
||
|
||
public void pauseOrder(Long orderId) {
|
||
// 1. 更新工单状态
|
||
orderStateMachine.transition(order, PAUSED, ...);
|
||
|
||
// 2. 更新队列状态 - 手动保证同步
|
||
OrderQueueDTO queue = orderQueueService.getByOpsOrderId(orderId);
|
||
orderQueueService.pauseTask(queue.getId());
|
||
|
||
// 问题:状态同步逻辑需要业务层手动处理,容易遗漏
|
||
}
|
||
}
|
||
```
|
||
|
||
**问题分析**:
|
||
|
||
1. **重复代码**:每个业务类型都要实现一遍暂停/恢复逻辑
|
||
2. **一致性风险**:手动同步工单状态和队列状态,容易出现不一致
|
||
3. **缺少统一入口**:没有统一的生命周期管理
|
||
|
||
**影响**:
|
||
- 代码重复率高
|
||
- 容易出现状态不一致的 bug
|
||
- 新增业务类型时需要重复实现
|
||
|
||
### 5.1.3 Listener 设计不明确
|
||
|
||
**问题表现**:
|
||
|
||
监听器注册是全局的,无法区分业务类型,且存在循环依赖风险:
|
||
|
||
```java
|
||
@Component
|
||
public class CleanOrderStateChangeListener implements OrderStateChangeListener {
|
||
|
||
@Resource
|
||
private CleanOrderService cleanOrderService; // 依赖业务服务
|
||
|
||
@Override
|
||
public void onStateChanged(OrderStateChangedEvent event) {
|
||
// 问题1:无法区分业务类型,需要手动判断
|
||
if (!"CLEAN".equals(event.getOrderType())) {
|
||
return;
|
||
}
|
||
|
||
// 问题2:直接调用业务服务,可能产生循环依赖
|
||
cleanOrderService.handleStateChanged(event);
|
||
}
|
||
}
|
||
|
||
// CleanOrderService 同时依赖 DispatchEngine
|
||
@Service
|
||
public class CleanOrderServiceImpl {
|
||
@Resource
|
||
private DispatchEngine dispatchEngine; // 可能产生循环依赖
|
||
}
|
||
```
|
||
|
||
**问题分析**:
|
||
|
||
1. **监听器注册全局化**:所有监听器都会收到所有事件,需要手动过滤
|
||
2. **缺少优先级定义**:多个监听器执行顺序不确定
|
||
3. **循环依赖风险**:Listener → Service → Engine → Listener
|
||
|
||
**影响**:
|
||
- 性能浪费(全局广播)
|
||
- 循环依赖导致启动失败
|
||
- 难以控制执行顺序
|
||
|
||
### 5.1.4 状态与队列状态同步问题
|
||
|
||
**问题表现**:
|
||
|
||
工单状态(`WorkOrderStatusEnum`)和队列状态(`OrderQueueStatusEnum`)是两个独立的状态机:
|
||
|
||
```java
|
||
// 工单状态
|
||
PENDING → ASSIGNED → ARRIVED → PAUSED → COMPLETED
|
||
|
||
// 队列状态
|
||
WAITING → PROCESSING → PAUSED → REMOVED
|
||
```
|
||
|
||
**同步困难**:
|
||
|
||
```java
|
||
// 暂停工单时,需要同时更新两个状态
|
||
public void pauseOrder(Long orderId) {
|
||
// 步骤1:更新工单状态
|
||
orderStateMachine.transition(order, WorkOrderStatusEnum.PAUSED, ...);
|
||
|
||
// 步骤2:查询队列
|
||
OrderQueueDTO queue = orderQueueService.getByOpsOrderId(orderId);
|
||
|
||
// 步骤3:更新队列状态
|
||
orderQueueService.updateStatus(queue.getId(), OrderQueueStatusEnum.PAUSED);
|
||
|
||
// 问题:如果步骤3失败,会导致状态不一致
|
||
}
|
||
```
|
||
|
||
**问题分析**:
|
||
|
||
1. **双写一致性**:需要手动保证两个状态的同步
|
||
2. **事务边界不清晰**:状态更新可能跨越多个服务
|
||
3. **缺少统一协调**:没有统一的地方管理状态同步
|
||
|
||
**影响**:
|
||
- 容易出现状态不一致
|
||
- 调试困难
|
||
- 数据修复成本高
|
||
|
||
---
|
||
|
||
## 5.2 重构方案设计
|
||
|
||
### 5.2.1 核心设计原则
|
||
|
||
**1. 单一职责原则(SRP)**:
|
||
- 每个组件只负责一个明确的职责
|
||
- DispatchEngine 只负责决策
|
||
- OrderStateMachine 只负责状态管理
|
||
- OrderLifecycleManager 负责状态同步
|
||
|
||
**2. 开闭原则(OCP)**:
|
||
- 通过接口和策略模式支持扩展
|
||
- 新增业务类型不需要修改核心代码
|
||
|
||
**3. 依赖倒置原则(DIP)**:
|
||
- 业务层依赖通用层的抽象接口
|
||
- 通用层不依赖具体业务实现
|
||
|
||
**4. 清晰分层**:
|
||
- 通用能力下沉(状态机、队列、派单引擎)
|
||
- 业务能力上浮(业务规则、事件处理)
|
||
|
||
### 5.2.2 组件职责重新定义
|
||
|
||
**DispatchEngine(派单引擎)- 纯决策层**:
|
||
|
||
```java
|
||
public interface DispatchEngine {
|
||
/**
|
||
* 推荐执行人员(核心职责)
|
||
*/
|
||
AssigneeRecommendation recommendAssignee(DispatchContext context);
|
||
|
||
/**
|
||
* 判断是否可以打断当前任务
|
||
*/
|
||
InterruptDecision evaluateInterrupt(Long currentAssigneeId, DispatchContext urgentContext);
|
||
|
||
/**
|
||
* 注册派单策略
|
||
*/
|
||
void registerStrategy(String businessType, AssignStrategy strategy);
|
||
}
|
||
```
|
||
|
||
**职责**:
|
||
- ✅ 根据上下文推荐最合适的执行人员
|
||
- ✅ 评估是否可以打断当前任务
|
||
- ✅ 管理派单策略
|
||
- ❌ 不负责状态管理
|
||
- ❌ 不负责设备通知
|
||
- ❌ 不负责业务逻辑
|
||
|
||
**OrderLifecycleManager(生命周期管理)- 新增组件**:
|
||
|
||
```java
|
||
public interface OrderLifecycleManager {
|
||
/**
|
||
* 暂停工单(同步更新工单状态和队列状态)
|
||
*/
|
||
void pauseOrder(Long orderId, Long operatorId, String reason);
|
||
|
||
/**
|
||
* 恢复工单
|
||
*/
|
||
void resumeOrder(Long orderId, Long operatorId);
|
||
|
||
/**
|
||
* 打断工单(P0紧急任务场景)
|
||
*/
|
||
void interruptOrder(Long orderId, Long urgentOrderId, Long operatorId);
|
||
|
||
/**
|
||
* 完成工单
|
||
*/
|
||
void completeOrder(Long orderId, Long operatorId);
|
||
}
|
||
```
|
||
|
||
**职责**:
|
||
- ✅ 统一管理工单状态和队列状态的同步变更
|
||
- ✅ 保证状态一致性(事务)
|
||
- ✅ 发布状态变更事件
|
||
- ❌ 不包含业务特定逻辑
|
||
|
||
**OrderStateMachine(状态机)- 优化**:
|
||
|
||
```java
|
||
public interface OrderStateMachine {
|
||
/**
|
||
* 执行状态转换(不触发业务逻辑)
|
||
*/
|
||
TransitionResult transition(OpsOrderDO order,
|
||
WorkOrderStatusEnum newStatus,
|
||
OperatorTypeEnum operatorType,
|
||
Long operatorId,
|
||
String remark);
|
||
|
||
/**
|
||
* 检查状态转换是否合法
|
||
*/
|
||
boolean canTransition(WorkOrderStatusEnum from, WorkOrderStatusEnum to);
|
||
}
|
||
```
|
||
|
||
**职责**:
|
||
- ✅ 验证状态转换规则
|
||
- ✅ 记录状态变更事件
|
||
- ❌ 不再包含监听器机制(移除)
|
||
- ❌ 不触发任何业务逻辑
|
||
|
||
**OrderEventPublisher(事件发布器)- 新增组件**:
|
||
|
||
```java
|
||
public interface OrderEventPublisher {
|
||
/**
|
||
* 发布状态变更事件
|
||
*/
|
||
void publishStateChanged(OrderStateChangedEvent event);
|
||
|
||
/**
|
||
* 发布工单创建事件
|
||
*/
|
||
void publishOrderCreated(OrderCreatedEvent event);
|
||
}
|
||
```
|
||
|
||
**职责**:
|
||
- ✅ 发布工单相关的领域事件
|
||
- ✅ 实现业务解耦
|
||
|
||
### 5.2.3 新架构设计图
|
||
|
||
**重构前**:
|
||
```
|
||
┌─────────────────────────────────────┐
|
||
│ DispatchEngine │
|
||
│ (职责混乱,13个方法) │
|
||
│ - 推荐人员 │
|
||
│ - 自动派单 │
|
||
│ - 设备通知 │
|
||
│ - 业务逻辑 │
|
||
└─────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────┐
|
||
│ OrderStateMachine │
|
||
│ (包含监听器,触发业务逻辑) │
|
||
└─────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────────────────────┐
|
||
│ CleanOrderService │
|
||
│ (手动同步状态,容易出错) │
|
||
└─────────────────────────────────────┘
|
||
```
|
||
|
||
**重构后**:
|
||
```
|
||
┌──────────────────┐ ┌──────────────────┐
|
||
│ DispatchEngine │ │ OrderLifecycle │
|
||
│ (纯决策层) │ │ Manager │
|
||
│ - 推荐执行人 │ │ (状态同步器) │
|
||
│ - 评估打断 │ │ - 暂停/恢复 │
|
||
└────────┬─────────┘ │ - 打断/完成 │
|
||
│ └────────┬─────────┘
|
||
│ │
|
||
▼ ▼
|
||
┌────────────────────────────────────┐
|
||
│ OrderStateMachine │
|
||
│ (纯状态管理,不触发业务逻辑) │
|
||
└────────┬───────────────────────────┘
|
||
│
|
||
▼
|
||
┌────────────────────────────────────┐
|
||
│ OrderEventPublisher │
|
||
│ (事件发布器) │
|
||
└────────┬───────────────────────────┘
|
||
│
|
||
▼
|
||
┌────────────────────────────────────┐
|
||
│ CleanOrderEventHandler │
|
||
│ (保洁业务事件处理器) │
|
||
└────────────────────────────────────┘
|
||
```
|
||
|
||
### 5.2.4 重构前后对比
|
||
|
||
| 方面 | 重构前 | 重构后 |
|
||
|------|--------|--------|
|
||
| 职责划分 | 模糊,混合多种职责 | 清晰,单一职责 |
|
||
| 状态同步 | 业务层手动同步 | OrderLifecycleManager 统一管理 |
|
||
| 业务扩展 | 修改核心代码 | 实现事件处理器 |
|
||
| 循环依赖 | 存在风险 | 通过事件解耦 |
|
||
| 测试难度 | 困难,职责过多 | 容易,职责单一 |
|
||
|
||
---
|
||
|
||
## 5.3 重构实施过程
|
||
|
||
### 5.3.1 Phase 1: 基础重构
|
||
|
||
**任务 1:重构 DispatchEngine 接口**
|
||
|
||
**Before**:
|
||
```java
|
||
public interface DispatchEngine {
|
||
AssigneeRecommendation recommendAssignee(DispatchContext context);
|
||
void autoDispatch(Long orderId);
|
||
void handleOrderCompleted(Long orderId);
|
||
void notifyAssignee(Long assigneeId);
|
||
// ... 还有 9 个方法
|
||
}
|
||
```
|
||
|
||
**After**:
|
||
```java
|
||
public interface DispatchEngine {
|
||
/**
|
||
* 推荐执行人员(核心方法)
|
||
*/
|
||
AssigneeRecommendation recommendAssignee(DispatchContext context);
|
||
|
||
/**
|
||
* 评估是否可以打断
|
||
*/
|
||
InterruptDecision evaluateInterrupt(Long currentAssigneeId, DispatchContext urgentContext);
|
||
|
||
/**
|
||
* 注册派单策略
|
||
*/
|
||
void registerStrategy(String businessType, AssignStrategy strategy);
|
||
}
|
||
```
|
||
|
||
**任务 2:创建 OrderLifecycleManager**
|
||
|
||
```java
|
||
@Service
|
||
@Slf4j
|
||
public class OrderLifecycleManagerImpl implements OrderLifecycleManager {
|
||
|
||
@Resource
|
||
private OrderStateMachine orderStateMachine;
|
||
|
||
@Resource
|
||
private OrderQueueService orderQueueService;
|
||
|
||
@Resource
|
||
private OrderEventPublisher eventPublisher;
|
||
|
||
@Override
|
||
@Transactional(rollbackFor = Exception.class)
|
||
public void pauseOrder(Long orderId, Long operatorId, String reason) {
|
||
// 1. 查询工单和队列
|
||
OpsOrderDO order = getOrderByOrderId(orderId);
|
||
OrderQueueDTO queueDTO = orderQueueService.getByOpsOrderId(orderId);
|
||
|
||
// 2. 验证状态
|
||
validateCanPause(order, queueDTO);
|
||
|
||
// 3. 同步转换状态(事务保证原子性)
|
||
orderStateMachine.transition(order, PAUSED, operatorType, operatorId, reason);
|
||
|
||
if (queueDTO != null) {
|
||
orderQueueService.pauseTask(queueDTO.getId());
|
||
}
|
||
|
||
// 4. 发布事件
|
||
eventPublisher.publishStateChanged(OrderStateChangedEvent.builder()
|
||
.orderId(orderId)
|
||
.orderType(order.getOrderType())
|
||
.oldStatus(ARRIVED)
|
||
.newStatus(PAUSED)
|
||
.operatorId(operatorId)
|
||
.build());
|
||
}
|
||
|
||
// ... 其他方法实现
|
||
}
|
||
```
|
||
|
||
**任务 3:重构 OrderStateMachine(移除监听器)**
|
||
|
||
**Before**:
|
||
```java
|
||
@Service
|
||
public class OrderStateMachine {
|
||
|
||
private List<OrderStateChangeListener> listeners = new ArrayList<>();
|
||
|
||
public void registerListener(OrderStateChangeListener listener) {
|
||
listeners.add(listener);
|
||
}
|
||
|
||
@Transactional
|
||
public void transition(OpsOrderDO order, WorkOrderStatusEnum newStatus, ...) {
|
||
// 更新状态
|
||
order.setStatus(newStatus.name());
|
||
orderMapper.updateById(order);
|
||
|
||
// 触发监听器
|
||
for (OrderStateChangeListener listener : listeners) {
|
||
listener.onStateChanged(new OrderStateChangedEvent(...));
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
**After**:
|
||
```java
|
||
@Component
|
||
public class OrderStateMachine {
|
||
|
||
@Resource
|
||
private OrderEventPublisher eventPublisher; // 改为使用事件发布器
|
||
|
||
@Transactional
|
||
public void transition(OpsOrderDO order, WorkOrderStatusEnum newStatus, ...) {
|
||
// 1. 验证状态转换
|
||
validateTransition(currentStatus, newStatus);
|
||
|
||
// 2. 更新状态
|
||
order.setStatus(newStatus.name());
|
||
orderMapper.updateById(order);
|
||
|
||
// 3. 记录事件
|
||
eventService.recordEvent(orderId, oldStatus, newStatus, ...);
|
||
|
||
// 4. 发布事件(替代监听器)
|
||
eventPublisher.publishStateChanged(OrderStateChangedEvent.builder()
|
||
.orderId(order.getId())
|
||
.oldStatus(oldStatus)
|
||
.newStatus(newStatus)
|
||
.build());
|
||
}
|
||
}
|
||
```
|
||
|
||
**任务 4:创建 OrderEventPublisher**
|
||
|
||
```java
|
||
@Service
|
||
@Slf4j
|
||
public class OrderEventPublisherImpl implements OrderEventPublisher {
|
||
|
||
@Resource
|
||
private ApplicationEventPublisher applicationEventPublisher;
|
||
|
||
@Override
|
||
@Async // 异步发布,不阻塞主流程
|
||
public void publishStateChanged(OrderStateChangedEvent event) {
|
||
try {
|
||
applicationEventPublisher.publishEvent(event);
|
||
log.info("状态变更事件已发布: orderId={}, {} -> {}",
|
||
event.getOrderId(), event.getOldStatus(), event.getNewStatus());
|
||
} catch (Exception e) {
|
||
log.error("状态变更事件发布失败: orderId={}", event.getOrderId(), e);
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 5.3.2 Phase 2: 业务层改造
|
||
|
||
**任务 1:创建事件处理器替代监听器**
|
||
|
||
**Before(Listener)**:
|
||
```java
|
||
@Component
|
||
public class CleanOrderStateChangeListener implements OrderStateChangeListener {
|
||
|
||
@Resource
|
||
private CleanOrderService cleanOrderService;
|
||
|
||
@Override
|
||
public void onStateChanged(OrderStateChangedEvent event) {
|
||
if (!"CLEAN".equals(event.getOrderType())) {
|
||
return;
|
||
}
|
||
cleanOrderService.handleStateChanged(event);
|
||
}
|
||
}
|
||
```
|
||
|
||
**After(EventHandler)**:
|
||
```java
|
||
@Component
|
||
public class CleanOrderEventHandler {
|
||
|
||
@Resource
|
||
private CleanerStatusService cleanerStatusService;
|
||
|
||
@Resource
|
||
private BadgeNotificationService badgeNotificationService;
|
||
|
||
@EventListener
|
||
public void onStateChanged(OrderStateChangedEvent event) {
|
||
// 只处理保洁类型的工单
|
||
if (!"CLEAN".equals(event.getOrderType())) {
|
||
return;
|
||
}
|
||
|
||
switch (event.getNewStatus()) {
|
||
case ARRIVED:
|
||
handleArrived(event);
|
||
break;
|
||
case PAUSED:
|
||
handlePaused(event);
|
||
break;
|
||
case COMPLETED:
|
||
handleCompleted(event);
|
||
break;
|
||
}
|
||
}
|
||
|
||
private void handleArrived(OrderStateChangedEvent event) {
|
||
// 更新保洁员状态为 BUSY
|
||
cleanerStatusService.updateStatus(event.getOperatorId(), CleanerStatusEnum.BUSY);
|
||
|
||
// 发送工牌通知
|
||
badgeNotificationService.notifyWorkStart(event.getOperatorId(), event.getOrderId());
|
||
}
|
||
|
||
private void handleCompleted(OrderStateChangedEvent event) {
|
||
// 更新保洁员状态为 IDLE
|
||
cleanerStatusService.updateStatus(event.getOperatorId(), CleanerStatusEnum.IDLE);
|
||
|
||
// 自动派发下一个任务
|
||
dispatchEngine.autoDispatchNext(event.getOrderId(), event.getOperatorId());
|
||
}
|
||
}
|
||
```
|
||
|
||
**任务 2:重构 CleanOrderService**
|
||
|
||
**Before**:
|
||
```java
|
||
@Service
|
||
public class CleanOrderServiceImpl {
|
||
|
||
public void pauseOrder(Long orderId) {
|
||
// 手动同步状态
|
||
orderStateMachine.transition(order, PAUSED, ...);
|
||
OrderQueueDTO queue = orderQueueService.getByOpsOrderId(orderId);
|
||
orderQueueService.pauseTask(queue.getId());
|
||
}
|
||
}
|
||
```
|
||
|
||
**After**:
|
||
```java
|
||
@Service
|
||
public class CleanOrderServiceImpl {
|
||
|
||
@Resource
|
||
private OrderLifecycleManager orderLifecycleManager; // 使用生命周期管理器
|
||
|
||
public void pauseOrder(Long orderId, String reason) {
|
||
// 委托给生命周期管理器,保证状态同步
|
||
orderLifecycleManager.pauseOrder(orderId, SecurityUtils.getLoginUserId(), reason);
|
||
|
||
// 业务特定逻辑
|
||
updateCleanerStatus(orderId, CleanerStatusEnum.PAUSED);
|
||
}
|
||
}
|
||
```
|
||
|
||
### 5.3.3 Phase 3: 优化与验证
|
||
|
||
**任务 1:性能优化**
|
||
|
||
**优化点 1:事件异步发布**
|
||
```java
|
||
@Service
|
||
public class OrderEventPublisherImpl {
|
||
|
||
@Async("eventExecutor") // 使用独立线程池
|
||
public void publishStateChanged(OrderStateChangedEvent event) {
|
||
applicationEventPublisher.publishEvent(event);
|
||
}
|
||
}
|
||
|
||
@Configuration
|
||
public class AsyncConfig {
|
||
|
||
@Bean("eventExecutor")
|
||
public Executor eventExecutor() {
|
||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||
executor.setCorePoolSize(5);
|
||
executor.setMaxPoolSize(10);
|
||
executor.setQueueCapacity(100);
|
||
executor.setThreadNamePrefix("event-");
|
||
executor.initialize();
|
||
return executor;
|
||
}
|
||
}
|
||
```
|
||
|
||
**优化点 2:批量状态更新**
|
||
```java
|
||
public void batchPauseOrders(List<Long> orderIds, String reason) {
|
||
// 批量更新,减少数据库交互
|
||
orderLifecycleManager.batchPause(orderIds, operatorId, reason);
|
||
}
|
||
```
|
||
|
||
**任务 2:集成测试**
|
||
|
||
```java
|
||
@SpringBootTest
|
||
class OrderLifecycleManagerIntegrationTest {
|
||
|
||
@Resource
|
||
private OrderLifecycleManager orderLifecycleManager;
|
||
|
||
@Resource
|
||
private OpsOrderMapper orderMapper;
|
||
|
||
@Resource
|
||
private OpsOrderQueueMapper queueMapper;
|
||
|
||
@Test
|
||
void testPauseOrder_ShouldSyncBothStatuses() {
|
||
// Given
|
||
Long orderId = createTestOrder();
|
||
|
||
// When
|
||
orderLifecycleManager.pauseOrder(orderId, 1L, "测试暂停");
|
||
|
||
// Then
|
||
OpsOrderDO order = orderMapper.selectById(orderId);
|
||
assertEquals("PAUSED", order.getStatus());
|
||
|
||
OpsOrderQueueDO queue = queueMapper.selectByOpsOrderId(orderId);
|
||
assertEquals("PAUSED", queue.getQueueStatus());
|
||
}
|
||
}
|
||
```
|
||
|
||
**任务 3:文档更新**
|
||
|
||
更新以下文档:
|
||
- [x] part2-架构演进史.md - 添加重构历程
|
||
- [x] part3-核心架构设计.md - 更新服务职责
|
||
- [ ] part5-架构重构实践.md - 本文档
|
||
- [ ] API 文档 - 更新接口说明
|
||
|
||
---
|
||
|
||
## 5.4 重构收获与反思
|
||
|
||
### 5.4.1 成功经验
|
||
|
||
**1. 职责分离带来清晰度**
|
||
|
||
重构后,每个组件的职责非常明确:
|
||
- DispatchEngine:只做决策,不管执行
|
||
- OrderLifecycleManager:只管状态同步,不管业务逻辑
|
||
- OrderEventPublisher:只管事件发布,不管事件处理
|
||
- EventHandler:只处理特定业务的事件
|
||
|
||
**收益**:
|
||
- 新人快速理解代码
|
||
- 单元测试简单明确
|
||
- 问题定位更快
|
||
|
||
**2. 事件驱动架构提升扩展性**
|
||
|
||
通过事件驱动,新增业务类型只需:
|
||
```java
|
||
// 1. 实现事件处理器
|
||
@Component
|
||
public class RepairOrderEventHandler {
|
||
@EventListener
|
||
public void onStateChanged(OrderStateChangedEvent event) {
|
||
if (!"REPAIR".equals(event.getOrderType())) {
|
||
return;
|
||
}
|
||
// 处理维修工单的特定逻辑
|
||
}
|
||
}
|
||
|
||
// 2. 无需修改核心引擎代码
|
||
```
|
||
|
||
**收益**:
|
||
- 核心引擎稳定,无需修改
|
||
- 业务团队独立开发
|
||
- 新功能上线快
|
||
|
||
**3. 兼容性保证平滑迁移**
|
||
|
||
保留旧实现作为兼容层:
|
||
```java
|
||
@Deprecated
|
||
public class OldDispatchEngine {
|
||
// 保留旧接口,内部委托给新实现
|
||
public void autoDispatch(Long orderId) {
|
||
orderLifecycleManager.dispatch(orderId);
|
||
}
|
||
}
|
||
```
|
||
|
||
**收益**:
|
||
- 业务流程不中断
|
||
- 逐步迁移,风险可控
|
||
- 回滚方案简单
|
||
|
||
### 5.4.2 踩坑记录
|
||
|
||
**坑 1:循环依赖问题**
|
||
|
||
**问题**:
|
||
```java
|
||
@Service
|
||
public class DispatchEngineImpl {
|
||
@Resource
|
||
private CleanOrderService cleanOrderService; // DispatchEngine -> CleanOrderService
|
||
}
|
||
|
||
@Service
|
||
public class CleanOrderServiceImpl {
|
||
@Resource
|
||
private DispatchEngine dispatchEngine; // CleanOrderService -> DispatchEngine
|
||
}
|
||
|
||
// 启动报错:Circular dependency detected
|
||
```
|
||
|
||
**解决方案**:
|
||
```java
|
||
@Service
|
||
public class DispatchEngineImpl {
|
||
@Lazy // 使用延迟注入
|
||
@Resource
|
||
private CleanOrderService cleanOrderService;
|
||
}
|
||
```
|
||
|
||
**更好的解决方案**:
|
||
```java
|
||
// 通过事件解耦,避免直接依赖
|
||
@Component
|
||
public class CleanOrderEventHandler {
|
||
@EventListener
|
||
public void onOrderDispatched(OrderDispatchedEvent event) {
|
||
// 处理派单事件
|
||
}
|
||
}
|
||
```
|
||
|
||
**坑 2:状态同步的事务边界**
|
||
|
||
**问题**:
|
||
```java
|
||
@Transactional
|
||
public void pauseOrder(Long orderId) {
|
||
// 更新工单状态(在事务内)
|
||
orderStateMachine.transition(order, PAUSED, ...);
|
||
|
||
// 更新队列状态(调用另一个服务,可能在另一个事务)
|
||
orderQueueService.pauseTask(queueId); // 如果失败,工单状态已提交
|
||
}
|
||
```
|
||
|
||
**解决方案**:
|
||
```java
|
||
@Transactional(rollbackFor = Exception.class) // 确保所有异常都回滚
|
||
public void pauseOrder(Long orderId) {
|
||
// 所有数据库操作在同一个事务中
|
||
orderStateMachine.transition(order, PAUSED, ...);
|
||
orderQueueService.pauseTask(queueId);
|
||
|
||
// 事件发布在事务提交后(使用 @TransactionalEventListener)
|
||
eventPublisher.publishStateChanged(...);
|
||
}
|
||
```
|
||
|
||
**坑 3:事件处理器的执行顺序**
|
||
|
||
**问题**:
|
||
```java
|
||
@Component
|
||
public class CleanOrderEventHandler {
|
||
@EventListener
|
||
public void onStateChanged(OrderStateChangedEvent event) {
|
||
// 处理器A:更新保洁员状态
|
||
}
|
||
}
|
||
|
||
@Component
|
||
public class CleanOrderNotificationHandler {
|
||
@EventListener
|
||
public void onStateChanged(OrderStateChangedEvent event) {
|
||
// 处理器B:发送通知
|
||
// 问题:可能在处理器A之前执行
|
||
}
|
||
}
|
||
```
|
||
|
||
**解决方案**:
|
||
```java
|
||
@Component
|
||
public class CleanOrderEventHandler {
|
||
|
||
@EventListener
|
||
@Order(1) // 优先级1,先执行
|
||
public void onStateChanged(OrderStateChangedEvent event) {
|
||
// 更新保洁员状态
|
||
}
|
||
}
|
||
|
||
@Component
|
||
public class CleanOrderNotificationHandler {
|
||
|
||
@EventListener
|
||
@Order(2) // 优先级2,后执行
|
||
public void onStateChanged(OrderStateChangedEvent event) {
|
||
// 发送通知
|
||
}
|
||
}
|
||
```
|
||
|
||
### 5.4.3 改进建议
|
||
|
||
**1. 从设计阶段就明确职责**
|
||
|
||
在编码前:
|
||
- 使用 UML 类图展示组件关系
|
||
- 定义清晰的接口契约
|
||
- 明确依赖方向
|
||
|
||
**2. 持续重构,不要积累技术债务**
|
||
|
||
建立机制:
|
||
- 每季度进行架构 Review
|
||
- 及时重构不合理的设计
|
||
- 不要等到问题严重才重构
|
||
|
||
**3. 完善测试,保证重构质量**
|
||
|
||
测试策略:
|
||
- 单元测试覆盖核心逻辑
|
||
- 集成测试覆盖端到端流程
|
||
- 重构前后对比测试
|
||
|
||
---
|
||
|
||
## 5.5 兼容性处理
|
||
|
||
### 5.5.1 保证平滑迁移
|
||
|
||
**兼容层设计**:
|
||
|
||
```java
|
||
@Deprecated
|
||
@Service("oldDispatchEngine")
|
||
public class DispatchEngineAdapter implements OldDispatchEngine {
|
||
|
||
@Resource
|
||
private DispatchEngine newDispatchEngine;
|
||
|
||
@Resource
|
||
private OrderLifecycleManager orderLifecycleManager;
|
||
|
||
@Override
|
||
public void autoDispatch(Long orderId) {
|
||
// 委托给新实现
|
||
orderLifecycleManager.dispatch(orderId);
|
||
}
|
||
|
||
@Override
|
||
public void notifyAssignee(Long assigneeId) {
|
||
// 废弃方法,记录警告
|
||
log.warn("notifyAssignee() is deprecated, please use EventHandler instead");
|
||
}
|
||
}
|
||
```
|
||
|
||
### 5.5.2 逐步切换策略
|
||
|
||
**阶段 1:保留旧接口**
|
||
- 新旧实现并存
|
||
- 旧接口内部调用新实现
|
||
- 添加 @Deprecated 注解
|
||
|
||
**阶段 2:迁移业务代码**
|
||
- 逐个模块迁移到新接口
|
||
- 测试验证功能正常
|
||
|
||
**阶段 3:清理旧代码**
|
||
- 确认所有业务已迁移
|
||
- 删除旧接口和兼容层
|
||
|
||
### 5.5.3 版本兼容性
|
||
|
||
**版本规划**:
|
||
- v2.0: 新架构发布,旧接口标记为 Deprecated
|
||
- v2.1: 旧接口保留,持续迁移
|
||
- v3.0: 删除旧接口
|
||
|
||
---
|
||
|
||
**下一章**:[Part 6: 性能与可靠性](./part6-性能与可靠性.md)
|