Springboot使用Websocket的時候調(diào)取IOC管理的Bean報空指針異常問題
問題
這個問題主要是因為Websocket的工作方式導(dǎo)致的,下面是詳細解決方案
解決
WebSocket 端點類通常不受 Spring IOC 管理的原因在于它們是由 WebSocket 容器(例如,Tomcat、Jetty 等)而不是 Spring 容器管理的。
WebSocket 規(guī)范(JSR 356)定義了 WebSocket 端點的生命周期和管理方式,這通常與 Spring 的生命周期和依賴注入機制不同。
以下是一些具體原因和解決方法:
原因
不同的生命周期管理:
- WebSocket 端點的創(chuàng)建和管理是由 Web 容器(如 Tomcat、Jetty 等)負責(zé)的,而不是由 Spring 容器負責(zé)。
- 這意味著 WebSocket 端點類的實例化和生命周期管理不在 Spring 的控制范圍內(nèi)。
注入機制不同:
- Spring 的依賴注入機制依賴于 Spring 容器管理的 Bean,但 WebSocket 端點類實例化時,Web 容器并不知道如何進行依賴注入。
解決方法
方法一:使用 Spring Boot 和 @Configuration 配置
在 Spring Boot 項目中,可以通過配置類和自定義 WebSocket 處理器來管理 WebSocket 連接,這樣可以使用 Spring 容器管理的 Bean。
創(chuàng)建 WebSocket 配置類:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
private final MyWebSocketHandler myWebSocketHandler;
public WebSocketConfig(MyWebSocketHandler myWebSocketHandler) {
this.myWebSocketHandler = myWebSocketHandler;
}
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(myWebSocketHandler, "/websocket").setAllowedOrigins("*");
}
}創(chuàng)建 WebSocket 處理器類:
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import org.springframework.stereotype.Component;
@Component
public class MyWebSocketHandler extends TextWebSocketHandler {
private final SomeService someService;
public MyWebSocketHandler(SomeService someService) {
this.someService = someService;
}
@Override
public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
String payload = message.getPayload();
System.out.println("消息為:" + payload);
someService.doSomething(); // 使用 Spring Bean
session.sendMessage(new TextMessage("servet 發(fā)送:" + payload));
}
}方法二:使用自定義 SpringConfigurator
創(chuàng)建自定義的 SpringConfigurator:
import javax.websocket.server.ServerEndpointConfig;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.WebApplicationContext;
public class SpringConfigurator extends ServerEndpointConfig.Configurator {
@Override
public <T> T getEndpointInstance(Class<T> clazz) throws InstantiationException {
WebApplicationContext context = ContextLoader.getCurrentWebApplicationContext();
if (context == null) {
throw new InstantiationException("Unable to get Spring context.");
}
return context.getAutowireCapableBeanFactory().createBean(clazz);
}
}在 @ServerEndpoint 注解中指定 configurator:
import javax.websocket.OnMessage;
import javax.websocket.server.ServerEndpoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@ServerEndpoint(value = "/websocket", configurator = SpringConfigurator.class)
@Component
public class MyWebSocket {
@Autowired
private SomeService someService; // 由 Spring 管理的 Bean
@OnMessage
public String onMsg(String text) throws IOException {
System.out.println("消息為:" + text);
someService.doSomething(); // 使用 Spring Bean
return "servet 發(fā)送:" + text;
}
}方法三:手動獲取 Spring Bean
創(chuàng)建 ApplicationContextProvider 類:
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
context = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return context;
}
}在 WebSocket 類中使用 ApplicationContextProvider 獲取 Bean:
import javax.websocket.OnMessage;
import javax.websocket.server.ServerEndpoint;
import org.springframework.stereotype.Component;
@ServerEndpoint(value = "/websocket")
@Component
public class MyWebSocket {
private SomeService someService;
public MyWebSocket() {
this.someService = ApplicationContextProvider.getApplicationContext().getBean(SomeService.class);
}
@OnMessage
public String onMsg(String text) throws IOException {
System.out.println("消息為:" + text);
someService.doSomething(); // 使用 Spring Bean
return "servet 發(fā)送:" + text;
}
}通過這些方法,你可以確保 WebSocket 端點類能夠正確地訪問由 Spring IOC 管理的 Bean,從而避免空指針異常。
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
- SpringBoot分布式WebSocket的實現(xiàn)指南
- SpringBoot實現(xiàn)WebSocket通信過程解讀
- 深入淺出SpringBoot WebSocket構(gòu)建實時應(yīng)用全面指南
- 利用SpringBoot與WebSocket實現(xiàn)實時雙向通信功能
- Springboot整合WebSocket 實現(xiàn)聊天室功能
- vue+springboot+webtrc+websocket實現(xiàn)雙人音視頻通話會議(最新推薦)
- Java?springBoot初步使用websocket的代碼示例
- SpringBoot3整合WebSocket詳細指南
- SpringBoot實現(xiàn)WebSocket的示例代碼
- Spring Boot集成WebSocket項目實戰(zhàn)的示例代碼
相關(guān)文章
springboot用thymeleaf模板的paginate分頁完整代碼
本文根據(jù)一個簡單的user表為例,展示 springboot集成mybatis,再到前端分頁完整代碼,需要的朋友可以參考下2017-07-07
springboot啟動后卡住無日志的幾種情況小結(jié)
這篇文章主要介紹了springboot啟動后卡住無日志的幾種情況小結(jié),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12

