一旦STOMP的接口被公布,Spring应用程序就成为连接客户端的STOMP代理。本节描述服务端消息处理的流程。
spring-messaging模块包含消息类应用的基础功能,这些功能起源于Spring Integration项目。并且,后来被提取整合到Spring框架,以便在更多的Spring项目和应用场景中更广泛地使用。下面列出了模块里包含的消息抽象:
- Message: 消息的简单表示,包括头部和有效载荷。
- MessageHandler: 消息处理器。
- MessageChannel: 发送消息的渠道,实现生产者和消费者的解耦。
- SubscribableChannel: 带有
MessageHandler订阅者的MessageChannel。 - ExecutorSubscribableChannel: 使用
Executor线程池来发送消息的SubscribableChannel。
Java配置(即@EnableWebSocketMessageBroker)和XML命名空间配置(即<websocket:message-broker>)使用前面的组件来组装消息工作流。下面的图表显示了,在使用程序内置的消息代理时用到的组件:

上图展示了三个消息通道:
clientInboundChannel: 用于接收来自WebSocket客户端的消息。clientOutboundChannel: 用于将服务器的消息发送到WebSocket客户端。brokerChannel: 用于从服务器端应用程序向消息代理发送消息。
下图展示了配置外部代理(如RabbitMQ)用于管理订阅和广播消息时用到的组件:

前面两幅图的主要区别是,第二幅图使用了“broker relay”,通过TCP链接将消息发送到外部的STOMP代理,并将消息从代理发送到订阅的客户端。
当从WebSocket连接接收到消息时,它们被解码为STOMP帧,转换为Spring Message 对象表示,并发送到clientInboundChannel进行进一步处理。例如,目的地头部以/app开头的STOMP消息可能会被路由到控制器中带了@MessageMapping 注解的方法,而/topic和/queue 开头的消息可能会直接路由到消息代理。
带了@Controller 注解的程序,在处理客户端发的STOMP消息后,可以通过brokerChannel向消息代理发送消息,代理通过clientOutboundChannel将消息广播给匹配的订阅者。同一个controller也可以对HTTP请求做出相同的响应,因此客户端可以执行一个HTTP POST请求,处理请求的@PostMapping方法可以向消息代理发送消息,然后广播给订阅的客户端。
我们通过一个简单的例子来熟悉流程。下面是配置服务端的示例:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {@Overridepublic void registerStompEndpoints(StompEndpointRegistry registry) {registry.addEndpoint("/portfolio");}@Overridepublic void configureMessageBroker(MessageBrokerRegistry registry) {registry.setApplicationDestinationPrefixes("/app");registry.enableSimpleBroker("/topic");}
}@Controller
public class GreetingController {@MessageMapping("/greeting")public String handle(String greeting) {return "[" + getTimestamp() + ": " + greeting;}
}
前面的示例支持以下流程:
- 客户端连接到
http://localhost:8080/portfolio,一旦建立WebSocket连接,STOMP帧就开始在它上面传输。 - 客户端发送一个destination消息头值为
/topic/greeting的SUBSCRIBE帧。一旦接收并解码,消息被发送到clientInboundChannel,然后被路由到消息代理,代理存储了客户端订阅信息。 - 客户端向
/app/greeting发送一个SEND帧。/app前缀的消息会路由到带注解的控制器上。在删掉了/app前缀之后,destination值剩余的部分/greeting会映射到GreetingController中的@MessageMapping方法上。 - 从
GreetingController返回的值被转换成一个SpringMessage对象,方法的返回值放入消息的payload,消息的默认destination消息头是/topic/greeting(从输入的destination派生而来,规则是用/topic替换/app)。返回的消息被发送到brokerChannel并由消息代理处理。 - 消息代理找到所有匹配的订阅者,并通过
clientOutboundChannel向所有订阅者发送一个MESSAGE帧,发送前消息被编码为STOMP帧,并通过WebSocket连接发送。