在spring或者springboot 中websocket 不能注入service bean 报空指针异常的,三种有效解决方案!!!

我们在spring 或 springboot 的 websocket 里面使用 @Autowired 注入 service 或 bean 时,会报空指针异常,获取的service 为 null,并不是service 不能被注入。
本质原因:spring管理的都是单例(singleton),和 websocket (多对象)相冲突。
详细解释:项目启动时初始化,会初始化 websocket (非用户连接的),spring 同时会为其注入 service,该对象的 service 不是 null,被成功注入。但是,由于 spring 默认管理的是单例,所以只会注入一次 service。当新用户进入聊天时,系统又会创建一个新的 websocket 对象,这时矛盾出现了:spring 管理的都是单例,不会给第二个 websocket 对象注入 service,所以导致只要是用户连接创建的 websocket 对象,都不能再注入了。像 controller 里面有 service, service 里面有 dao。因为 controller,service ,dao 都有是单例,所以注入时不会报 null。但是 websocket 不是单例,所以使用spring注入一次后,后面的对象就不会再注入了,会报null。

下面我们可以通过三种方式来解决无法注入的问题

一、 使用applicationContext获取

@Component
@ServerEndpoint(value = "/loggings")
//注意这里要实现ApplicationContextAware的接口,才能使applicationContext生效,要不到时候获取不到
public class LoggingWebConfig implements ApplicationContextAware{
    
    
    //此处是解决无法注入的关键
    private static ApplicationContext applicationContext;
    //引入自己的接口类
    private MobileUserService mobileUserService;
    //applicationContext的set方法
    public  void setApplicationContext(ApplicationContext applicationContext) {
    
    
        LoggingWebConfig.applicationContext = applicationContext;
    }
    //然后通过applicationContext.getBean()的方法即可获取到对应的接口类了
    applicationContext.getBean(MobileUserService.class)
    }

二、使用@Autowired set方法注入,这种方法无需实现ApplicationContextAware接口

@Component
@ServerEndpoint(value = "/loggings")
public class LoggingWebConfig{
    
    

    //引入自己的接口类,注意要加上static 静态修饰
    private static MobileUserService mobileUserService;
    
    //mobileUserService的set方法
    @Autowired 
    public  void setApplicationContext(MobileUserService mobileUserService) {
    
    
        LoggingWebConfig.mobileUserService= mobileUserService;
    }
    //然后就可以直接用引入的mobileUserService接口,例如mobileUserService.list()即可获取到相应的数据
    }

三、使用配置文件,通过BeanFactory.getBean()来获取

1.新建配置文件MyEndpointConfig

public class MyEndpointConfig extends ServerEndpointConfig.Configurator implements ApplicationContextAware {
    
    
	 //此处是解决无法注入的关键
    private static volatile BeanFactory context;

    @Override
    public <T> T getEndpointInstance(Class<T> clazz){
    
    
        return context.getBean(clazz);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    
    
        MyEndpointConfig.context = applicationContext;
    }

}

2.引入配置文件

@Component
//使用configurator = MyEndpointConfig.class的方式引入配置文件
@ServerEndpoint(value = "/loggings",configurator = MyEndpointConfig.class)
public class LoggingWebConfig{
    
    
	//此方式可以用@Autowired将接口类直接注入进去
 	@Autowired
    MobileUserService mobileUserService;
    //然后就可以直接用引入的mobileUserService接口,例如mobileUserService.list()即可获取到相应的数据
}

四、新建WebSocketConfig配置文件

在WebSocketConfig配置文件中注入配置文件MyEndpointConfig的bean,要不MyEndpointConfig配置文件无法生效,不用MyEndpointConfig配置方式的解决问题的可以不用配置这个bean,只要有ServerEndpointExporter注解扫描就可以了

@Configuration
public class WebSocketConfig {
    
    
    /**
     * 用途:扫描并注册所有携带@ServerEndpoint注解的实例。 @ServerEndpoint("/loggings")
     * 如果使用外部容器 则无需提供ServerEndpointExporter。
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
    
    
        return new ServerEndpointExporter();
    }

    /**
     * 支持注入其他接口类
     */
    @Bean
    public MyEndpointConfig  newMyEndpointConfigure (){
    
    
        return new MyEndpointConfig ();
    }
}

猜你喜欢

转载自blog.csdn.net/qq_40136782/article/details/109078750