Springboot使用Websocket的时候调取IOC管理的Bean报空指针异常问题
作者:堕落年代
这篇文章主要介绍了Springboot使用Websocket的时候调取IOC管理的Bean报空指针异常问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
问题
这个问题主要是因为Websocket的工作方式导致的,下面是详细解决方案
解决
WebSocket 端点类通常不受 Spring IOC 管理的原因在于它们是由 WebSocket 容器(例如,Tomcat、Jetty 等)而不是 Spring 容器管理的。
WebSocket 规范(JSR 356)定义了 WebSocket 端点的生命周期和管理方式,这通常与 Spring 的生命周期和依赖注入机制不同。
以下是一些具体原因和解决方法:
原因
不同的生命周期管理:
- WebSocket 端点的创建和管理是由 Web 容器(如 Tomcat、Jetty 等)负责的,而不是由 Spring 容器负责。
- 这意味着 WebSocket 端点类的实例化和生命周期管理不在 Spring 的控制范围内。
注入机制不同:
- Spring 的依赖注入机制依赖于 Spring 容器管理的 Bean,但 WebSocket 端点类实例化时,Web 容器并不知道如何进行依赖注入。
解决方法
方法一:使用 Spring Boot 和 @Configuration 配置
在 Spring Boot 项目中,可以通过配置类和自定义 WebSocket 处理器来管理 WebSocket 连接,这样可以使用 Spring 容器管理的 Bean。
创建 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("*");
}
}创建 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 发送:" + payload));
}
}方法二:使用自定义 SpringConfigurator
创建自定义的 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 发送:" + text;
}
}方法三:手动获取 Spring Bean
创建 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 发送:" + text;
}
}通过这些方法,你可以确保 WebSocket 端点类能够正确地访问由 Spring IOC 管理的 Bean,从而避免空指针异常。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
您可能感兴趣的文章:
- SpringBoot分布式WebSocket的实现指南
- SpringBoot实现WebSocket通信过程解读
- 深入浅出SpringBoot WebSocket构建实时应用全面指南
- 利用SpringBoot与WebSocket实现实时双向通信功能
- Springboot整合WebSocket 实现聊天室功能
- vue+springboot+webtrc+websocket实现双人音视频通话会议(最新推荐)
- Java springBoot初步使用websocket的代码示例
- SpringBoot3整合WebSocket详细指南
- SpringBoot实现WebSocket的示例代码
- Spring Boot集成WebSocket项目实战的示例代码
