第2篇:Spring Boot + WebSocket + 消息队列STOMP协议(Rabbitmq) 架构原理

🧩 整体架构概览

复制代码
[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 发送一条聊天消息:

  1. 前端 JS 通过 WebSocket + STOMP 向 Spring Boot 发送:

    复制代码
    stompClient.send("/app/chat", {}, JSON.stringify({text: "Hello"}));
  2. Spring Boot 的 @MessageMapping("/chat") 方法收到消息。

  3. 方法内部调用:

    复制代码
    simpMessagingTemplate.convertAndSend("/topic/chatroom", message);
  4. Spring Boot 使用 system 凭据 ,通过 STOMP 协议将消息发给 RabbitMQ 的 /topic/chatroom。

  5. RabbitMQ 将消息广播给所有订阅了 /topic/chatroom 的消费者。

  6. Spring Boot 用 client 凭据 已经代表所有在线用户订阅了该 topic。

  7. RabbitMQ 把消息推给 Spring Boot。

  8. Spring Boot 再通过各自的 WebSocket 连接,把消息推送给每个前端用户。

✅ 所有消息实际都经过 RabbitMQ,Spring Boot 只是"代理转发"。


🛠️ 配置要点总结

项目 说明
setRelayHost("localhost") RabbitMQ 的 IP 或域名
setRelayPort(61613) RabbitMQ STOMP 插件监听的端口(不是 AMQP 的 5672)
用户名/密码 必须在 RabbitMQ 中创建对应用户,并赋予 stomp 权限
目标前缀 /topic, /queue 必须与 RabbitMQ STOMP 插件的默认 destination 映射规则一致

✅ 最佳实践建议

  1. 生产环境务必使用 Relay Broker + RabbitMQ/ActiveMQ,不要用 Simple Broker。
  2. RabbitMQ 需要:
    • 启用 rabbitmq_stomp 插件
    • 创建专用用户(如 stomp-user),并授权 virtual host 和 STOMP 权限
  3. Spring Security 要放行 WebSocket 端点(如 /ws-stomp/**)
  4. 前端使用 SockJS + Stomp.js 兼容性更好

相关推荐
子兮曰2 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰2 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
爱勇宝2 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
胡写代码2 天前
别再前后端各写一套表单校验了
java·后端
大勇前进3 天前
原生 PHP 还是 Laravel?小项目到底要不要上框架
后端
yuzhi_liu3 天前
我用 LangGraph4j 实现 Multi-Agent Supervisor
后端
alsmile3 天前
Node-RED 之外,国产规则引擎的新方案:基于标准语法,Go 先行实现
后端·开源·go
大白803 天前
PHP 内存溢出排查思路:看懂报错日志,精准定位问题
后端
二月龙3 天前
PHP 接口返回统一响应封装,让前后端对接更省心
后端
只睡四小时3 天前
Canvas 弹道联机实战:700 行 + 固定时间步长
python·websocket·html5·游戏开发·canvas