Springboot使用Websocket的时候调取IOC管理的Bean报空指针异常问题

 更新时间:2025年05月15日 10:03:02   作者:堕落年代  
这篇文章主要介绍了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,从而避免空指针异常。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 使用Mybatis如何实现多个控制条件查询

    使用Mybatis如何实现多个控制条件查询

    这篇文章主要介绍了使用Mybatis如何实现多个控制条件查询,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • 详解Java编程中对线程的中断处理

    详解Java编程中对线程的中断处理

    这篇文章主要介绍了Java编程中对线程的中断处理,特别讲解了中断的时机与中断状态的管理,需要的朋友可以参考下
    2015-11-11
  • SpringBoot分布式WebSocket的实现指南

    SpringBoot分布式WebSocket的实现指南

    在现代Web应用中,实时通信已成为基本需求,而WebSocket是实现这一功能的核心技术,本文将详细介绍如何在Spring Boot项目中实现分布式WebSocket,包括完整的技术方案、实现步骤和核心代码,需要的朋友可以参考下
    2025-10-10
  • 聊聊如何打印GC日志排查的问题

    聊聊如何打印GC日志排查的问题

    这篇文章主要介绍了聊聊如何打印GC日志排查的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • java中Map、Set、List的简单使用教程(快速入门)

    java中Map、Set、List的简单使用教程(快速入门)

    这篇文章主要给大家介绍了关于java中Map、Set、List简单使用教程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • Spring Data Jpa 中原生查询 REGEXP 的使用详解

    Spring Data Jpa 中原生查询 REGEXP 的使用详解

    这篇文章主要介绍了Spring Data Jpa 中原生查询 REGEXP 的使用详解,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12
  • 亲测解决,nacos下线失败问题

    亲测解决,nacos下线失败问题

    这篇文章主要介绍了亲测解决,nacos下线失败问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-07-07
  • maven打包加入本地jar包的实现

    maven打包加入本地jar包的实现

    在使用maven打包的过程中,有时候我们需要添加一些本地的jar包,本文主要介绍了maven打包加入本地jar包的实现,具有一定的参考价值,感兴趣的可以了解一下
    2024-08-08
  • Log4j关闭Spring和Hibernate日志打印方式

    Log4j关闭Spring和Hibernate日志打印方式

    这篇文章主要介绍了Log4j关闭Spring和Hibernate日志打印方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12
  • Java异常javax.net.ssl.SSLHandshakeException: SSL的解决方法

    Java异常javax.net.ssl.SSLHandshakeException: SSL的解决方法

    在Java开发过程中,SSL(Secure Sockets Layer)握手异常是一个常见的网络通信错误,特别是在使用HTTPS协议进行安全通信时,本文将详细分析javax.net.ssl.SSLHandshakeException: SSL这一异常的背景、可能的原因,并通过代码示例帮助您理解和解决这一问题
    2024-12-12

最新评论