springwebsocket集问题的简单记录⽬录
前⾔
最近公司⾥遇到⼀个问题,在集中⼀些websocket的消息丢失了。
产⽣问题的原理很简单,发送消息的服务和接收者连接的服务不是同⼀个服务。
解决⽅案
⽤中间件(mq, redis etc.)来在服务之间进⾏通信。
不直接发送websocket消息,⽽是将消息放在mq或者redis的list中。
并在redis中维护连接信息,服务根据连接信息来判断⾃⼰是否需要处理消息,或者将消息发给接收者连接的服务。代码⽰例
我们的项⽬中使⽤的是Spring WebSocket,并且使⽤了STOMP协议,可以去查看⽂档。
代码⽰例只做维护连接信息的代码⽰例,其他部分就不放上来了。
维护连接信息的代码⽰例
想要在维护STOMP协议的连接信息,可以查看⽂档的这⼀部分
这⾥的连接信息只要是能够标识出不同的服务就OK。
⼀下是监听了订阅事件的Listener的部分代码:
package cn.fjhdtp.websocket.interceptor;
import java.util.Map;
import org.apachemons.lang.StringUtils;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;
public class LoginInfoInterceptor extends HttpSessionHandshakeInterceptor {
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response,
WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
//握⼿前,往attributes中增加所需信息
Object loginBean = ...;//获取登录的⽤户信息(或其他信息)
attributes.put(WebSocketConstant.WEBSOKET_LOGINBEAN,loginBean);
return super.beforeHandshake(request, response, wsHandler, attributes);
}
}
package cn.fjhdtp.listener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import t.ApplicationListener;
import org.urrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.ssaging.SessionSubscribeEvent;
import java.util.Map;
@Component
public class SessionSubscribeEventListener implements ApplicationListener<SessionSubscribeEvent> {
@Autowired
@Qualifier("serversideMessageTaskExecutor")
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
@Autowired
private IMessageHandler messageHandler;
@Override
public void onApplicationEvent(SessionSubscribeEvent event) {
//获取订阅的destination
String destination = (String) Message().getHeaders().get("simpDestination");
//获取登录信息
Object loginBean = ((Map) Message().getHeaders().get("simpSessionAttributes")).get(WebSocketConstant.WEBSOKET_LOGINBEAN); //TODO 向redis中增加连接信息
}
}
package ssage.listener;
import t.ApplicationListener;
import org.springframework.stereotype.Component;
import org.springframework.ssaging.SessionDisconnectEvent;
websocket和socketimport java.util.Map;
@Component
public class SessionDisconnectEventListener implements ApplicationListener<SessionDisconnectEvent> {
@Override
public void onApplicationEvent(SessionDisconnectEvent event) {
// stomp连接断开,清除连接信息
//从attributes中获取登录信息(或其他信息)
Object loginBean = ((Map) Message().getHeaders().get("simpSessionAttributes")).get(WebSocketConstant.WEBSOKET_LOGINBEAN); //从redis中移除连接信息
}
}
当然,有些情况下可能不会正常的触发断开连接的事件(在was下就不会有这个事件),因此还会需要HeartBeat。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论