异常信息:
2020-09-22 09:42:56.581 263170 [http-nio-5556-exec-1] ERROR o.s.w.s.m.StompSubProtocolHandler - Failed to send client message to application via MessageChannel in session uddpnpiw. Sending STOMP ERROR to client.
org.springframework.messaging.MessageDeliveryException: Failed to send message to ExecutorSubscribableChannel[clientInboundChannel]; nested exception is java.lang.NullPointerException
at org.springframework.messaging.support.AbstractMessageChannel.send(AbstractMessageChannel.java:129)
at org.springframework.messaging.support.AbstractMessageChannel.send(AbstractMessageChannel.java:105)
大致说的是在早期版本中有个bug,提供解决方案的大佬Gary Russell解决这个bug后还顺便给spring-framework提了个bug;
如果ChannelInterceptor 为null就会报错!!!
下面是我的主要代码
@Slf4j
@Component
public class MyChannelInterceptor implements ChannelInterceptor {
@Autowired
private WebSocketRegistry webSocketRegistry;
@Autowired
private SimpMessagingTemplate messagingTemplate;
@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
if(StompCommand.CONNECT.equals(accessor.getCommand())){
String name = accessor.getUser().getName();
String sessionId = accessor.getSessionId();
System.out.println("CONNECT sessionId = " + sessionId);
//统计用户在线数,可通过redis来实现更好
if (webSocketRegistry.isExist(name)){
JSONObject jsObj = new JSONObject();
jsObj.put("sessionId",sessionId);
messagingTemplate.convertAndSendToUser(name,"/topic/disconnect",jsObj);
}
webSocketRegistry.registerOnlineUser(name,sessionId);
}else if (StompCommand.DISCONNECT.equals(accessor.getCommand())){
Principal principal = accessor.getUser();
//判断是否是客户端手动触发断开,根据header参数判断
String manual = accessor.getFirstNativeHeader("manual");
if (StringUtils.isBlank(manual)){
if (null != principal && StringUtils.isNotBlank(principal.getName())){
String sessionId = accessor.getFirstNativeHeader("sessionId");
if (accessor.getSessionId().equals(sessionId)){
webSocketRegistry.unregisterOnlineUser(principal.getName(),sessionId);
}
}
}else {
webSocketRegistry.unregisterOnlineUser(principal.getName(),accessor.getSessionId());
}
}
return message;
}
解释
:在利用websocket做一个实时聊天的基础上,我想拓展一下附加功能,配合redis实现在线人数统计,然后考虑到同一个用户发起多个连接如何处理???最后采取方案是直接建立新连接,但是与此同时通知前一个客户端断开连接;所以加了一个messagingTemplate.convertAndSendToUser的方法通知客户端,重点来了,
将messagingTemplate放入ChannelInterceptor 的preSend()方法中会导致
Caused by: java.lang.NullPointerException: null
at org.springframework.messaging.support.AbstractMessageChannel$ChannelInterceptorChain.applyPreSend(AbstractMessageChannel.java:161)
at org.springframework.messaging.support.AbstractMessageChannel.send(AbstractMessageChannel.java:115)
进而引起本文最开始提到的异常
那么如何解决呢???
我仔细思考了一下,考虑可能是注入SimpMessagingTemplate 的时机不成熟,那么能不能晚点再注入,调用的时候再注入呢??能不能用懒加载的方式呢???
@Lazy <---------------------
@Autowired
private SimpMessagingTemplate messagingTemplate;
经过反复对比测试,发现加上@Lazy注解后效果确实起到了
在初始化的时候懒加载不注入,调用的时候注入,问题解决了!!!!