🧩 整体架构概览
[Web 浏览器 / 客户端]
↓ (通过 WebSocket 连接)
[Spring Boot 应用]
↓ (通过 TCP 连接 STOMP 协议)
[RabbitMQ(启用了 STOMP 插件)]
- 客户端:通常是浏览器中的 JavaScript(如 SockJS + Stomp.js),通过 WebSocket 连接到 Spring Boot 应用。
- Spring Boot 应用:作为"网关"或"桥接器",它不自己处理消息持久化或广播,而是将 STOMP 消息转发给真正的消息中间件(RabbitMQ)。
- RabbitMQ :作为真正的消息代理(Message Broker),负责消息的存储、路由、广播、持久化、集群等。
🔍 各组件/角色详解
1. STOMP(Simple Text Oriented Messaging Protocol)
- 是一种轻量级的文本协议,用于在客户端和消息代理之间传递消息。
- 它定义了
CONNECT、SUBSCRIBE、SEND、DISCONNECT等命令。 - WebSocket 本身只是传输通道,而 STOMP 在其上提供语义化的消息格式(类似 HTTP 之于 TCP)。
✅ 所以:WebSocket 是传输层,STOMP 是应用层协议。
2. Spring Boot 内置的 Simple Broker vs. Relay Broker
✅ Simple Broker(内存代理)
- Spring 自己实现的一个简易消息代理。
- 只支持
/topic和/queue前缀。 - 不支持跨实例、无持久化、无集群,仅适合开发测试。
✅ Relay Broker(中继代理)
- Spring 不处理消息 ,而是将所有 STOMP 消息转发给外部消息中间件(如 RabbitMQ、ActiveMQ)。
- 外部中间件负责真正的消息路由、持久化、集群、高可用等。
- 适用于生产环境。
⚠️ 你配置的
.enableStompBrokerRelay(...)就是启用 Relay 模式。
3. RabbitMQ(作为 STOMP Broker)
默认 RabbitMQ 不支持 STOMP,需要手动启用插件:
rabbitmq-plugins enable rabbitmq_stomp
启用后,RabbitMQ 会监听一个 STOMP 端口(默认 61613),接受 STOMP 协议的连接。
注意:RabbitMQ 的 STOMP 插件会自动将 STOMP 的
/topic/xxx映射为 fanout exchange ,/queue/xxx映射为 direct queue。
4. 两个登录凭证的作用
.setClientLogin("admin").setClientPasscode("admin") // 客户端 → RabbitMQ
.setSystemLogin("admin").setSystemPasscode("admin") // Spring Boot → RabbitMQ
| 角色 | 谁在用? | 用途 |
|---|---|---|
| Client Login/Passcode | Spring Boot 代表前端客户端连接 RabbitMQ 时使用的凭据 | 当前端订阅 /topic/chat,Spring 会用这个账号在 RabbitMQ 上创建消费者 |
| System Login/Passcode | Spring Boot 自身连接 RabbitMQ 时使用的凭据 | 用于向 RabbitMQ 发送消息(比如 Controller 中调用 convertAndSend("/topic/notice", msg)) |
💡 实际上,Spring Boot 会维护两条到 RabbitMQ 的 STOMP 连接:
- 一条用 system 凭据 ,用于发送消息(生产者)
- 一条用 client 凭据 ,用于代表所有前端用户订阅消息(消费者)
🔄 消息流转示例
假设用户 A 发送一条聊天消息:
-
前端 JS 通过 WebSocket + STOMP 向 Spring Boot 发送:
stompClient.send("/app/chat", {}, JSON.stringify({text: "Hello"})); -
Spring Boot 的
@MessageMapping("/chat")方法收到消息。 -
方法内部调用:
simpMessagingTemplate.convertAndSend("/topic/chatroom", message); -
Spring Boot 使用 system 凭据 ,通过 STOMP 协议将消息发给 RabbitMQ 的
/topic/chatroom。 -
RabbitMQ 将消息广播给所有订阅了
/topic/chatroom的消费者。 -
Spring Boot 用 client 凭据 已经代表所有在线用户订阅了该 topic。
-
RabbitMQ 把消息推给 Spring Boot。
-
Spring Boot 再通过各自的 WebSocket 连接,把消息推送给每个前端用户。
✅ 所有消息实际都经过 RabbitMQ,Spring Boot 只是"代理转发"。
🛠️ 配置要点总结
| 项目 | 说明 |
|---|---|
setRelayHost("localhost") |
RabbitMQ 的 IP 或域名 |
setRelayPort(61613) |
RabbitMQ STOMP 插件监听的端口(不是 AMQP 的 5672) |
| 用户名/密码 | 必须在 RabbitMQ 中创建对应用户,并赋予 stomp 权限 |
目标前缀 /topic, /queue |
必须与 RabbitMQ STOMP 插件的默认 destination 映射规则一致 |
✅ 最佳实践建议
- 生产环境务必使用 Relay Broker + RabbitMQ/ActiveMQ,不要用 Simple Broker。
- RabbitMQ 需要:
- 启用
rabbitmq_stomp插件 - 创建专用用户(如
stomp-user),并授权 virtual host 和 STOMP 权限
- 启用
- Spring Security 要放行 WebSocket 端点(如
/ws-stomp/**) - 前端使用
SockJS + Stomp.js兼容性更好