|
对于最新稳定版本,请使用 Spring Framework 7.0.6! |
消息流
一旦暴露了 STOMP 端点,Spring 应用程序就成为已连接客户端的 STOMP 代理。本节描述服务器端的消息流转过程。
spring-messaging 模块包含了对消息传递应用程序的基础支持,
这些支持最初源自 Spring Integration,
后来被提取出来并整合到 Spring Framework 中,以便在众多
Spring 项目和应用场景中更广泛地使用。
以下列表简要描述了一些可用的消息传递抽象:
-
Message: 消息的简单表示形式,包含头部和有效载荷。
-
MessageHandler: 用于处理消息的契约。
-
MessageChannel: 用于发送消息的契约,可实现生产者与消费者之间的松耦合。
-
SubscribableChannel: 带有
MessageChannel订阅者的MessageHandler。 -
ExecutorSubscribableChannel: 使用
SubscribableChannel来传递消息的Executor。
Java 配置(即 @EnableWebSocketMessageBroker)和 XML 命名空间配置(即 <websocket:message-broker>)均使用上述组件来组装消息工作流。下图展示了启用内置简单消息代理时所使用的组件:
上图显示了三个消息通道:
-
clientInboundChannel:用于传递从 WebSocket 客户端接收到的消息。 -
clientOutboundChannel:用于向 WebSocket 客户端发送服务器消息。 -
brokerChannel:用于从服务器端应用程序代码中向消息代理发送消息。
下图展示了在配置外部代理(例如 RabbitMQ)用于管理订阅和广播消息时所使用的组件:
上述两个图之间的主要区别在于使用了“代理中继”(broker relay),通过 TCP 将消息传递给外部 STOMP 代理,并将消息从代理传递给已订阅的客户端。
当从 WebSocket 连接接收到消息时,这些消息会被解码为 STOMP 帧,
转换成 Spring 的 Message 表示形式,并发送到
clientInboundChannel 以进行进一步处理。例如,目标地址头(destination header)以 /app 开头的 STOMP 消息
可能会被路由到带注解控制器中的 @MessageMapping 方法,而 /topic 和 /queue 消息则可能直接路由到消息代理。
一个带有注解的 @Controller 可以处理来自客户端的 STOMP 消息,并通过 brokerChannel 向消息代理发送消息,随后该代理通过 clientOutboundChannel 将消息广播给匹配的订阅者。同一个控制器也可以在响应 HTTP 请求时执行相同的操作,因此客户端可以发起一个 HTTP POST 请求,然后由一个 @PostMapping 方法向消息代理发送消息,以广播给已订阅的客户端。
我们可以通过一个简单的示例来追踪流程。请看以下示例,它设置了一个服务器:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/portfolio");
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/app");
registry.enableSimpleBroker("/topic");
}
}
@Controller
public class GreetingController {
@MessageMapping("/greeting")
public String handle(String greeting) {
return "[" + getTimestamp() + ": " + greeting;
}
}
前面的示例支持以下流程:
-
客户端连接到
localhost:8080/portfolio,一旦 WebSocket 连接建立,STOMP 帧就开始在其上流动。 -
客户端发送一个 SUBSCRIBE 帧,其 destination 头部为
/topic/greeting。该消息一旦被接收并解码,就会被发送到clientInboundChannel,然后路由到消息代理,由消息代理存储客户端的订阅。 -
客户端向
/app/greeting发送一个 SEND 帧。/app前缀用于将其路由到带注解的控制器。在去除/app前缀后,目标地址剩余的/greeting部分将被映射到@MessageMapping中的GreetingController方法。 -
从
GreetingController返回的值会被转换为一个 SpringMessage,其有效载荷(payload)基于返回值,并带有默认的目标地址头(destination header)/topic/greeting(该地址是通过将输入目标地址中的/app替换为/topic得到的)。生成的消息会被发送到brokerChannel,并由消息代理(message broker)进行处理。 -
消息代理会找到所有匹配的订阅者,并通过
clientOutboundChannel向每个订阅者发送一个 MESSAGE 帧,消息在此通道中被编码为 STOMP 帧,并通过 WebSocket 连接发送出去。
下一节将详细介绍带注解的方法,包括所支持的参数类型和返回值类型。