• SpringBoot使用@ServerEndpoint无法@Autowired依赖注入问题解决


    SpringBoot使用@ServerEndpoint无法@Autowired依赖注入问题解决

    问题

    websocket里面使用@Autowired注入service或bean时,报空指针异常。

    @Component
    @ServerEndpoint("/groupChat/{groupNo}/{uuid}")
    public class GroupChatWebsocket {
    
        @Autowired
        private RedisTemplateUtil redisTemplateUtil;
    }
    

    原因

    spring管理的都是单例(singleton)和 websocket (多对象)相冲突。

    需要了解一个事实:websocket 是多对象的,每个用户的聊天客户端对应 java 后台的一个 websocket 对象,前后台一对一(多对多)实时连接,
    所以 websocket 不可能像 servlet 一样做成单例的,让所有聊天用户连接到一个 websocket对象,这样无法保存所有用户的实时连接信息。
    可能 spring 开发者考虑到这个问题,没有让 spring 创建管理 websocket ,而是由 java 原来的机制管理websocket ,所以用户聊天时创建的
    websocket 连接对象不是 spring 创建的,spring 也不会为不是他创建的对象进行依赖注入,所以如果不用static关键字,每个 websocket 对象的 service 都是 null。

    原文链接

    解决方案

    • 方法一 使用static静态对象
    private static RedisTemplateUtil redisUtil;
     
    @Autowired
    public static void setRedisTemplateUtil(RedisTemplateUtil redisUtil) {
    	WebSocketServer.redisUtil = redisUtil;
    }
    
    
    • 方法二 动态的从spring容器中取出RedisTemplateUtil 推荐方案
    package cn.pconline.framework.util;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    
    /**
     * 获取spring容器
     * 当一个类实现了这个接口ApplicationContextAware之后,这个类就可以方便获得ApplicationContext中的所有bean。
     * 换句话说,这个类可以直接获取spring配置文件中所有有引用到的bean对象
     * 前提条件需作为一个普通的bean在spring的配置文件中进行注册 
     */
    public class SpringCtxUtils implements ApplicationContextAware {
    
        private static ApplicationContext applicationContext;
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        	SpringCtxUtils.applicationContext = applicationContext;
        }
    
    
        public static <T> T getBean(Class<T> type) {
            try {
                return applicationContext.getBean(type);
            } catch (NoUniqueBeanDefinitionException e) {   //出现多个,选第一个
                String beanName = applicationContext.getBeanNamesForType(type)[0];
                return applicationContext.getBean(beanName, type);
            }
        }
    
        public static <T> T getBean(String beanName, Class<T> type) {
            return applicationContext.getBean(beanName, type);
        }
    }
    
    
    
  • 相关阅读:
    算法--将Excel列索引转换成默认标识
    Java参考资料-中文API
    java编程规范
    POI-根据Cell获取对应的String类型值
    将Excel中读取的科学计数法表示的Double数据转换为对应的字符串
    Android进程间通信之LocalSocket通信
    Android进程间通信之socket通信
    android用讯飞实现TTS语音合成 实现中文版
    Android Junit测试框架
    java interface的两个经典用法
  • 原文地址:https://www.cnblogs.com/cnsyear/p/12635372.html
Copyright © 2020-2023  润新知