1.开发准备
假定读者已经有一定的Spring Boot 的基础
并且了解 RabbitMQ 中 Exchange Queue Topic Topic相关概念已经很了解,
可以借此文章更深入的了解如何使用 STOMP 以及 RabbitMQ 来作为消息代理来配置 STOMP集群。
安装 Chrome 插件 ```Apic``` 用来测试 STOMP请求
STOMP 简介
STOMP是一个用于C/S之间进行异步消息传输的简单文本协议, 全称是Simple Text Oriented Messaging Protocol。
RabbitMQ
** RabbitMQ 作为老牌的消息队列功能完善**
RabbitMQ 常用命令
./rabbitmq-server 开启本地rabbitmq 服务
./rabbitmqctl stop 停止本地rabbitmq 服务
./rabbitmqctl add_user {username} {password} 添加用户
./rabbitmqctl set_permissions [-p vhostpath] {user} {conf} {write} {read} 给用户添加权限
开发实战
RabbitMQ 添加 STOMP 插件
./rabbitmq-plugins enable rabbitmq_management rabbitmq_web_stomp rabbitmq_stomp 安装插件,看到下图中红框所示,标识插件安装成功

gradle 添加如下依赖
implementation 'org.springframework.boot:spring-boot-starter-websocket'
implementation 'org.springframework.boot:spring-boot-starter-amqp'
implementation 'org.springframework.boot:spring-boot-starter-reactor-netty'
implementation 'io.projectreactor:reactor-net:2.0.8.RELEASE'
implementation 'io.netty:netty-all:4.1.22.Final'
STOMP 配置
@EnableWebSocketMessageBroker
@EnableWebSocket
@Configuration
@Slf4j
public class StompConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
// 注册连接点 path
registry.addEndpoint("/ws-endpoint")
.setHandshakeHandler(new HandshakeHandler() {
@Override
public boolean doHandshake(ServerHttpRequest request, ServerHttpResponse response,
WebSocketHandler wsHandler, Map<String, Object> attributes)
throws HandshakeFailureException {
// 如果未登录用户在这里拦截
return true;
}
})
.setHandshakeHandler(new DefaultHandshakeHandler(){
@Override
protected Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler,
Map<String, Object> attributes) {
// return super.determineUser(request, wsHandler, attributes);
return new Principal() {
@Override
public String getName() {
// TODO 根据session 返回连接的用户米看那个成
return "default-user";
}
};
}
})
.setAllowedOrigins("*");
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
// 设置消息代理为RabbitMQ
registry.enableStompBrokerRelay("/topic")
.setVirtualHost("/")
.setClientLogin("guest")
.setClientPasscode("guest")
.setSystemLogin("guest")
.setSystemPasscode("guest")
.setSystemHeartbeatSendInterval(5000)
.setSystemHeartbeatReceiveInterval(5000)
.setRelayHost("127.0.0.1")// RabbitMQ 地址
.setRelayPort(61613) // STOMP 端口
// 设置用户信息注册
.setUserDestinationBroadcast("/topic/log-unresolved-user")
.setUserRegistryBroadcast("/topic/log-user-registry");
}
@Override
public void configureWebSocketTransport(WebSocketTransportRegistration registry) {
registry.addDecoratorFactory(new WebSocketHandlerDecoratorFactory() {
@Override
public WebSocketHandler decorate(WebSocketHandler handler) {
return new WebSocketHandlerDecorator(handler) {
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
super.afterConnectionEstablished(session);
log.info("连接建立 " + session);
// WS 连接建立前
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus)
throws Exception {
super.afterConnectionClosed(session, closeStatus);
// WS 连接建立后
log.info("连接断开 " + session);
}
};
}
});
}
}
说明
大概介绍一下
SimpUserRegistry这个类,默认情况下SimpUserRegistry的实现是DefaultSimpUserRegistry这个类型,它是用来管理本地用户的登录信息。
如果在设置消息代理的时候添加了如下代码
setUserDestinationBroadcast("/topic/log-unresolved-user")
.setUserRegistryBroadcast("/topic/log-user-registry");
那么它的实现类型将变成MultiServerUserRegistry,可以用来建立STOMP集群之间的用户信息联系。具体原理还需要分析。
给所有用户发送请求
public void sendAll(){
messagingTemplate.convertAndSend("/topic/follow", "Test Message");
}
此时需要监听的路径为 /topic/follow
给指定用户发送请求
messagingTemplate.convertAndSendToUser("user-demo", "/topic/follow", "Test Message");
此时需要监听的路径为 /user/topic/follow
说明下 destination 的路由以下构成 /{type}/{routingkey}
type 分为
- exchange
对于 SUBCRIBE frame,destination 一般为/exchange//[/pattern] 的形式。 该 destination 会创建一个唯一的、自动删除的随机queue, 并根据 pattern 将该 queue 绑定到所给的 exchange,实现对该队列的消息订阅。
对于 SEND frame,destination 一般为/exchange//[/routingKey] 的形式。 这种情况下消息就会被发送到定义的 exchange 中,并且指定了 routingKey。
- topic
对于 SUBCRIBE frame,destination 创建出自动删除的、非持久的 queue 并根据 routingkey 为 绑定到 amq.topic exchange 上,同时实现对该 queue 的订阅。
对于 SEND frame,消息会被发送到 amq.topic exchange 中,routingKey 为。
对于在页面发送消息的例子跟订阅类似,这里就不再演示。
- queue
- amp/queue