1.不能注入原因
项目启动时初始化,会初始化 websocket (非用户连接的),spring 同时会为其注入 service,该对象的 service 不是 null,被成功注入。但是,由于 spring 默认管理的是单例,所以只会注入一次 service。当新用户进入聊天时,系统又会创建一个新的 websocket 对象,这时矛盾出现了:spring 管理的都是单例,不会给第二个 websocket 对象注入 service,所以导致只要是用户连接创建的 websocket 对象,都不能再注入了。
2.解决办法
像 controller 里面有 service, service 里面有 dao。因为 controller,service ,dao 都有是单例,所以注入时不会报 null。但是 websocket 不是单例,所以使用spring注入一次后,后面的对象就不会再注入了,会报null。
3.例如
package com.tl.coral.deskmsg.service;
import com.alibaba.fastjson.JSON;
import net.sf.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.web.socket.*;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* @Author: lc
* @Date: 2019/9/20 14:44
*/
@Service
@Component
public class MyHandler extends TextWebSocketHandler /*implements WebSocketHandler*/ {
//@Autowired
private static StringRedisTemplate stringRedisTemplate;
/**
* 项目启动时初始化,会初始化 websocket (非用户连接的),
* spring 同时会为其注入 service,该对象的 service 不是 null,被成功注入。
* 但是,由于 spring 默认管理的是单例,所以只会注入一次 service。
* 当新用户进入聊天时,系统又会创建一个新的 websocket 对象,
* 这时矛盾出现了:spring 管理的都是单例,不会给第二个 websocket 对象注入 service,
* 所以导致只要是用户连接创建的 websocket 对象,都不能再注入了。
* <p>
* <p>
* controller 里面有 service, service 里面有 dao。
* 因为 controller,service ,dao 都有是单例,
* 所以注入时不会报 null。但是 websocket 不是单例,
* 所以使用spring注入一次后,后面的对象就不会再注入了,会报null。
*
* @param stringRedisTemplate
*/
@Autowired
public void setStringRedisTemplate(StringRedisTemplate stringRedisTemplate) {
MyHandler.stringRedisTemplate = stringRedisTemplate;
}
//在线用户列表
private static final Map<String, WebSocketSession> users;
static {
users = new HashMap<>();
}
//新增socket
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
System.out.println("成功建立连接");
String ID = session.getUri().toString().split("ID=")[1];
System.out.println(ID);
if (ID != null) {
//users.put(ID, session);
Map<String, WebSocketSession> hashMap = new HashMap<>();
hashMap.put(ID, session);
stringRedisTemplate.convertAndSend("index", hashMap.toString());
session.sendMessage(new TextMessage("成功建立socket连接"));
}
System.out.println("当前在线人数:" + users.size());
}
public void receiveMessage(String message) {
System.out.println(message);
Map<String, WebSocketSession> hashMap = JSON.parseObject(message, HashMap.class);
users.putAll(hashMap);
System.out.println("添加登陆信息:" + message);
//这里是收到通道的消息之后执行的方法
}
//接收socket信息
@Override
public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage<?> webSocketMessage) throws Exception {
try {
JSONObject jsonobject = JSONObject.fromObject(webSocketMessage.getPayload());
System.out.println(jsonobject.get("id"));
System.out.println(jsonobject.get("message") + ":来自" + (String) webSocketSession.getAttributes().get("WEBSOCKET_USERID") + "的消息");
sendMessageToUser(jsonobject.get("id") + "", new TextMessage("服务器收到了,hello!"));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 发送信息给指定用户
*
* @param clientId
* @param message
* @return
*/
public boolean sendMessageToUser(String clientId, TextMessage message) {
if (users.get(clientId) == null) return false;
WebSocketSession session = users.get(clientId);
System.out.println("sendMessage:" + session);
if (!session.isOpen()) return false;
try {
session.sendMessage(message);
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 广播信息
*
* @param message
* @return
*/
public boolean sendMessageToAllUsers(TextMessage message) {
boolean allSendSuccess = true;
Set<String> clientIds = users.keySet();
WebSocketSession session = null;
for (String clientId : clientIds) {
try {
session = users.get(clientId);
if (session.isOpen()) {
session.sendMessage(message);
}
} catch (IOException e) {
e.printStackTrace();
allSendSuccess = false;
}
}
return allSendSuccess;
}
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
if (session.isOpen()) {
session.close();
}
System.out.println("连接出错");
users.remove(getClientId(session));
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
System.out.println("连接已关闭:" + status);
users.remove(getClientId(session));
}
@Override
public boolean supportsPartialMessages() {
return false;
}
/**
* 获取用户标识
*
* @param session
* @return
*/
private Integer getClientId(WebSocketSession session) {
try {
Integer clientId = (Integer) session.getAttributes().get("WEBSOCKET_USERID");
return clientId;
} catch (Exception e) {
return null;
}
}
}