spring 或 springboot 的 websocket 裏面使用 @Autowired 注入 service 或 bean 時,報java.lang.NullPointerException異常,service爲null(實際上並非不能被注入)java
將要注入的 service 改爲 static,而後添加一個set方法(重要的事情說三遍:這個set方法必定不能是static的,這個set方法必定不能是static的,這個set方法必定不能是static的)就不會爲null了。通過測試,接口和實現類都是能夠成功注入的。web
參考代碼:spring
@Controller @ServerEndpoint("chatSocket") public class ImSer { // 這裏使用靜態,讓 service 屬於類 private static ChatService chatService; // 注入的時候,給類的 service 注入,注意:這個set方法必定不能是靜態的 @Autowired public void setChatService(ChatService chatService) { ImSer.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 中使用同步,或者加鎖。tomcat
轉載自:https://blog.csdn.net/m0_37202351/article/details/86255132,感謝原做者的無私奉獻安全