Skip to content

消息流

一旦暴露了 STOMP 端点,Spring 应用程序就会成为已连接客户端的 STOMP 代理。本节描述服务器端的消息流。

spring-messaging 模块包含了对消息传递应用程序的基础支持。以下是几个核心抽象:

  • Message: 消息的简单表示,包括标头 (Headers) 和负载 (Payload)。
  • MessageHandler: 处理消息的契约。
  • MessageChannel: 发送消息的契约,实现生产者和消费者之间的解耦。
  • SubscribableChannel: 带有 MessageHandler 订阅者的 MessageChannel
  • ExecutorSubscribableChannel: 使用 Executor 交付消息的 SubscribableChannel

频道 (Channels) 与流程

无论通过 Java 配置还是 XML 配置,Spring 都会组装一个消息工作流。以下是启用简单内置消息代理(Simple Broker)时的组件示意:

消息流简单代理

图中包含三个核心消息频道:

  1. clientInboundChannel: 接收从 WebSocket 客户端发来的消息。
  2. clientOutboundChannel: 向 WebSocket 客户端发送服务器消息。
  3. brokerChannel: 用于从服务器端应用程序代码内部向消息代理发送消息。

当使用外部代理(如 RabbitMQ)时,流程如下:

消息流外部代理

主要的区别在于使用了“代理中继”(Broker Relay),它通过 TCP 将消息传递给外部 STOMP 代理,并将来自代理的消息传递给已订阅的客户端。

典型流程轨迹

  1. 接收消息: 从 WebSocket 连接接收到的消息被解码为 STOMP 帧,转为 Spring Message 表示,发送到 clientInboundChannel
  2. 路由方法: 目的地以 /app 开头的 STOMP 消息被路由到 @MessageMapping 控制器方法。
  3. 路由代理: 目的地以 /topic/queue 开头的消息直接路由到消息代理。
  4. 返回结果: 控制器方法返回的值变为 Message 发送到 brokerChannel,代理再通过 clientOutboundChannel 广播给匹配的订阅者。

补充教学

1. 这种架构的意义:解耦

Spring 将 WebSocket 原始连接与业务处理完全解耦。你的 Controller 处理的是标准的 Message 对象,并不需要知道它是从哪个物理连接、哪个 TCP 端口过来的。这种抽象使得同样的逻辑也可以应用于非 WebSocket 环境。

2. 拦截器 (Interceptors)

由于一切都流经 MessageChannel,你可以在这些频道上注册 ChannelInterceptor。例如,在 clientInboundChannel 上加一个拦截器,就可以在消息到达 Controller 之前进行统一的权限控制或日志记录。

3. 多线程处理

ExecutorSubscribableChannel 意味着消息的处理是异步的。Spring 默认配置了线程池来处理这些频道,这意味着高并发下的消息发送不会阻塞 Servlet 容器的主线程。

Based on Spring Framework.