Files
rui-docs/backend/specs/2026-06-04-mq-unified-push-design.md
vifo 19de7e24ec docs: 迁移 spring-ai 通用文档到 rui-docs
从 docs-local 迁移以下文档:

- backend/guides/: AI开发环境配置、Nacos配置、GitNexus指南、OpenCode工作流等

- backend/templates/: Superpowers设计模板、计划模板、审查清单

- backend/config-templates/: 应用配置模板、Nacos配置

- backend/design/: 数据库表结构规划

- backend/specs/: 项目文档治理、MQ统一推送设计

- backend/: 代码分析报告、Feign分析报告、文档治理报告

- frontend/design/: Admin-UI分模块打包设计
2026-06-04 09:34:03 +08:00

237 lines
8.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# MQ 统一推送入口设计文档
> **设计日期**: 2026-06-04
> **版本**: v1.0
> **状态**: 已批准
> **目标**: 创建统一消息队列推送入口 MqClient,封装多 Provider 路由、Action 注入、异常兜底,对标 spring-rui MqDefaultClient
---
## 一、背景与目标
### 1.1 现状分析
当前项目已有基础 MQ 能力:
- `MqService` 接口:提供 `send()` 方法,面向业务开发者直接使用
- `Message<T>` 模型:含 id, topic, payload, headers, timestamp, retryCount
- `RedisMqService` / `RabbitMqService`:分别基于 Redis Pub/Sub 和 RabbitMQ 的实现
- `MqTopic` 注解:用于方法级消息订阅
**存在的问题**
1. 缺乏统一推送门面:业务代码需要直接注入 `MqService` 并选择实现,无法自动按 Provider 路由
2. 无 Provider 抽象:无法在多环境(开发用 Redis、生产用 RabbitMQ)间平滑切换
3. 无 Action 语义:消息缺乏"添加/删除/更新"等业务动作标识
4. 异常处理分散:各实现自行处理异常,缺乏统一兜底
### 1.2 目标定义
1. 创建 `MqClient` 门面类,作为业务层唯一推送入口
2. 引入 `MqPublisher` Provider 接口,实现多 MQ 后端自动路由
3. 扩展 `Message` 模型,支持 action、provider、exchange、delay 等高级字段
4. 保持现有 `MqService` 接口不变,确保向后兼容
5. 所有推送操作统一异常捕获和日志记录
---
## 二、详细设计
### 2.1 整体架构
```
┌─────────────────────────────────────────────────────────────┐
│ 业务层 (Business) │
│ MqClient.publish(...) │
└──────────────────────────┬──────────────────────────────────┘
┌──────────────────────────▼──────────────────────────────────┐
│ MqClient (门面/统一入口) │
│ · 自动从 Spring 容器获取所有 MqPublisher 实现 │
│ · 按 support(MqProvider) 过滤匹配的 Publisher │
│ · 自动注入 action 到 payload │
│ · 统一 try-catch + 日志 │
└──────────────────────────┬──────────────────────────────────┘
┌───────────────┼───────────────┐
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ RedisMqPublisher │ │ RabbitMqPublisher│ │ FutureProvider │
│ (Redis实现) │ │ (RabbitMQ实现) │ │ (可扩展) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
```
### 2.2 核心组件
| 组件 | 职责 | 位置 |
|------|------|------|
| `MqClient` | 统一推送门面,业务层唯一入口 | `rui-common-mq` |
| `MqPublisher` | Provider 能力接口,定义 support + publish | `rui-common-mq` |
| `MqProvider` | Provider 枚举(RABBITMQ, REDIS | `rui-common-mq` |
| `MqProperties` | 配置属性(默认 provider、topic prefix | `rui-common-mq` |
| `MqAction` | 消息动作枚举(ADDED, DELETED 等) | `rui-common-mq` |
| `Message<T>` | 扩展后的消息模型 | `rui-common-mq` |
### 2.3 数据流
```
启动阶段 (一次)
Spring 注入 List<MqPublisher> → 遍历注册到 EnumMap
publisherMap = { RABBITMQ: RabbitMqPublisher, REDIS: RedisMqPublisher }
运行时 (每次 publish)
MqClient.publish(String topic, MqAction action, T payload)
├─ 1. 构造 Message<T>
├─ 2. 若 action != NONE,将 action 序列化后注入 payload
├─ 3. 若 message.provider == null,使用 MqProperties 默认值
├─ 4. publisherMap.get(provider) → O(1) 直接取到 Publisher
├─ 5. 调用 publisher.publish(message)
└─ 6. catch Exception → log.error,不抛异常
```
### 2.4 接口设计
**MqClient(门面类)**
采用**构造器注入 + 启动预构建 EnumMap**,避免运行时遍历:
```java
@Component
@Slf4j
public class MqClient {
private final MqProperties properties;
private final EnumMap<MqProvider, MqPublisher> publisherMap = new EnumMap<>(MqProvider.class);
public MqClient(MqProperties properties, List<MqPublisher> publishers) {
this.properties = properties;
for (MqPublisher p : publishers) {
publisherMap.put(p.getProvider(), p); // O(1) 注册
}
}
/** 使用默认 Provider 推送 */
public <T> void publish(String topic, T payload);
/** 使用默认 Provider 推送,带 Action */
public <T> void publish(String topic, MqAction action, T payload);
/** 指定 Provider 推送 */
public <T> void publish(MqProvider provider, String topic, T payload);
/** 指定 Provider 推送,带 Action */
public <T> void publish(MqProvider provider, String topic, MqAction action, T payload);
/** 完整 Message 推送 */
public <T> void publish(Message<T> message);
private MqPublisher resolve(MqProvider provider) {
return publisherMap.get(provider); // O(1) 查找
}
}
```
**MqPublisherProvider 接口)**
```java
public interface MqPublisher {
/** 返回该 Publisher 支持的 Provider 类型 */
MqProvider getProvider();
/** 基础推送 */
<T> void publish(String topic, T payload);
/** 完整消息推送 */
<T> void publish(Message<T> message);
}
```
**MqProvider(枚举)**
```java
public enum MqProvider {
RABBITMQ,
REDIS
}
```
**MqProperties(配置)**
```java
@ConfigurationProperties(prefix = "mq")
@Data
public class MqProperties {
private MqProvider provider = MqProvider.RABBITMQ;
private String prefix = "rui";
public String enTopic(String topic) { ... }
public String deTopic(String topic) { ... }
}
```
**MqAction(动作枚举,精简版)**
```java
public enum MqAction {
NONE, ADDED, DELETED, UPDATED, CREATED,
CANCEL, ENABLED, SUCCESSFUL, FAILURE
}
```
### 2.5 扩展现有实现
**RedisMqService** 调整:
- 实现 `MqPublisher` 接口
- `support(MqProvider.REDIS)` 返回 true
- `publish()` 复用现有 `send()` 逻辑
**RabbitMqService** 调整:
- 实现 `MqPublisher` 接口
- `support(MqProvider.RABBITMQ)` 返回 true
- `publish()` 复用现有 `send()` 逻辑
### 2.6 错误处理
- **异常策略**`MqClient` 所有 publish 方法统一 try-catch,记录 error 日志,不抛异常给业务层
- **Provider 不匹配**:若找不到支持该 Provider 的 Publisher,记录 warn 日志
- **Payload 为空**:自动创建空 JSON 对象 `{}`
---
## 三、验收标准
- [ ] `MqClient` 可正常注入并调用 `publish()` 发送消息
- [ ] 通过配置 `mq.provider=redis` 可自动切换到 Redis 实现
- [ ] `publish(topic, MqAction.ADDED, payload)` 发送的消息包含 action 字段
- [ ] 发送异常时不抛异常,仅记录日志
- [ ] 现有 `MqService.send()` 调用不受影响,向后兼容
- [ ] 项目可正常编译通过
---
## 四、风险与依赖
| 风险 | 影响 | 缓解措施 |
|------|------|---------|
| 现有 `MqService` 被多处使用 | 中 | 不修改 `MqService`,新建 `MqPublisher` 接口 |
| `Message<T>` 扩展后序列化兼容性 | 低 | 新增字段均为可空,不影响现有序列化 |
| SpringUtil 在静态方法中可能未初始化 | 低 | MqClient 通过构造器注入,非静态调用 |
---
## 五、对标分析
| 维度 | spring-rui (MqDefaultClient) | 本设计 (MqClient) |
|------|------------------------------|-------------------|
| 门面类名 | `MqDefaultClient` | `MqClient`(更简洁) |
| Provider 接口 | `MqService`(含 support/publish | `MqPublisher`(不冲突现有 `MqService` |
| 配置类名 | `MqAutoConfiguration` | `MqProperties`(更语义化) |
| JSON 框架 | fastjson2 | Jackson(适配本项目) |
| Provider 支持 | MQTT, RABBITMQ, REDIS | RABBITMQ, REDISMQTT 暂不需要) |
| Action 枚举 | `Actions`80+ 项) | `MqAction`(精简 9 项) |
| 包名 | `org.rui.common.mq` | `com.rui.common.mq` |