java springboot websocket 不能注入( @Autowired ) service bean 报 null 错误

解决方法

spring 或 springboot 的 websocket 里面使用 @Autowired 注入 service 或 bean 时,报空指针异常,service 为 null(并不是不能被注入)。

** 解决方法:将要注入的 service 改成 static,就不会为null了。**
参考代码:

@Controller
@ServerEndpoint(value="/chatSocket")
public class ChatSocket {
    //  这里使用静态,让 service 属于类
    private static ChatService chatService;

    // 注入的时候,给类的 service 注入
    @Autowired
    public void setChatService(ChatService chatService) {
        ChatSocket.chatService = chatService;
    }
}

原因

本质原因:spring管理的都是单例(singleton)和 websocket (多对象)相冲突。
需要了解一个事实:websocket 是多对象的,每个用户的聊天客户端对应 java 后台的一个 websocket 对象,前后台一对一(多对多)实时连接,所以 websocket 不可能像 servlet 一样做成单例的,让所有聊天用户连接到一个 websocket对象,这样无法保存所有用户的实时连接信息。可能 spring 开发者考虑到这个问题,没有让 spring 创建管理 websocket ,而是由 java 原来的机制管理websocket ,所以用户聊天时创建的 websocket 连接对象不是 spring 创建的,spring 也不会为不是他创建的对象进行依赖注入,所以如果不用static关键字,每个 websocket 对象的 service 都是 null。

详细解释(按上面我写的代码,假设属性使用了 static):
初始化:项目启动时,spring 工厂会创建 websocket 的单例对象(此时注解合法,spring 就会为 ChatSocket 类的属性 ChatService 进行注入,并创建一个单例对象,spring 并不知道 websocket 的特殊意义,只是该类的注解合法,便会进行操作,与其他 controller 进行的操作一模一样),因此 chatService 不是 null。

聊天时:当新用户通过客户端聊天时,后台(不管是tomcat 还是java)会根据 ChatSocket 类创建一个新的 chatSocket 对象,保存与用户的连接。因为chatService 是属于类的,所以也不是 null。

总结:
这里 websocket 的多对象机制和 spring 的 controller 注解机制,同时进行,互相没有矛盾。spring 会在初始化时创建一个没有意义的 ChatSocket 的单例对象,该对象在运行期间一直不会被使用,同时为 ChatSocket 的类进行了静态属性的完善,这是 spring 的唯一作用。

当有用户连接聊天时,java 会根据 ChatSocket 类进行创建对象,每个对象保持与对应的用户连接,因为类的静态属性已在启动时被 spring 初始化了,所以每个对象都可以正常使用。

安全性:
安全性要高於单例模式。单例模式全程使用一个对象,而 websocket 使用了多个对象,每个对象互相独立,属性互相分开,唯一的静态属性chatService,只是调用了其方法而已。如果内心实在害怕,自己根据实际情况在 chatService 中使用同步,或者加锁。

发布了19 篇原创文章 · 获赞 1 · 访问量 2万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章