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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章