问题描述:
在controller层和在service层调用redis时都能正常进行数据的保存和读取,现在打算把已经连接到webSocket的用户id保存到redis中,结果报NullPointerException,如下: 在这里插入代码片
问题分析
在@ServerEndpoint注解类中使用@Resource或@Autowired注入失败。报出空指针异常。
原因是WebSocket是线程安全的,有用户连接时就会创建一个新的端点实例,一个端WebSocket是多对象的,使用的spring却是单例模式。这两者刚好冲突。 @Autowired注解注入对象是在启动的时候就把对象注入,而不是在使用A对象时才把A需要的B对象注入到A中。 而WebSocket在刚刚有说到,有连接时才实例化对象,而且有多个连接就有多个 对象。总结就是,WebSocket是多对象的。不管单独使用也好,结合spring也好,或者结合SpringBoot也罢,他都是多对象的。
解决办法
- 一、新建一个SpringUtil类,通过getBean的方法主动获取实例
根据上下文获取beanConfigurableListableBeanFactory.getBean(),可以有两种参数类型: 传入String格式的类名 传入类.Class的类 SpringUtils类中getBean代码如下:
/**
* 获取类型为requiredType的对象
*
* @param name
* @return
* @throws org.springframework.beans.BeansException
*
*/
public static <T> T getBean(Class<T> name) throws BeansException {
if(getBeanFactory()==null){
//zhengkai.blog.csdn.net
System.out.println("本地调试Main模式,没有BeanFactory,忽略错误");
return null;
}else{
T result = (T) getBeanFactory().getBean(name);
return result;
}
}
- 二、在webSocket中直接使用SpringUtils.getBean(StringRedisTemplate.class);调出对应的bean
@ServerEndpoint("/webSocketServer/{userId}")
@Component
public class WebSocketServer {
static Logger log = LoggerFactory.getLogger(WebSocketServer.class);
@Resource
private RedisUtil redisUtil = SpringUtils.getBean(RedisUtil.class);
//省略redis相关方法调用
springUtil完整代码如下:
package cn.yatinova.yz_service.utils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;
/**
* SpringUtils
*
* @author zhengkai.blog.csdn.net
*/
@Component
public final class SpringUtils implements BeanFactoryPostProcessor {
private static ConfigurableListableBeanFactory beanFactory;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
SpringUtils.beanFactory = beanFactory;
}
public static ConfigurableListableBeanFactory getBeanFactory() {
return beanFactory;
}
/**
* 获取对象
*
* @param name
* @return Object 一个以所给名字注册的bean的实例
* @throws org.springframework.beans.BeansException
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) throws BeansException {
if (getBeanFactory() == null) {
//zhengkai.blog.csdn.net
System.out.println("本地调试Main模式,没有BeanFactory,忽略错误");
return null;
} else {
T result = (T) getBeanFactory().getBean(name);
return result;
}
}
/**
* 获取类型为requiredType的对象
*
* @param name
* @return
* @throws org.springframework.beans.BeansException
*/
public static <T> T getBean(Class<T> name) throws BeansException {
if (getBeanFactory() == null) {
//zhengkai.blog.csdn.net
System.out.println("本地调试Main模式,没有BeanFactory,忽略错误");
return null;
} else {
T result = (T) getBeanFactory().getBean(name);
return result;
}
}
/**
* 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true
*
* @param name
* @return boolean
*/
public static boolean containsBean(String name) {
return getBeanFactory().containsBean(name);
}
/**
* 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)
*
* @param name
* @return boolean
* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
*/
public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
return getBeanFactory().isSingleton(name);
}
/**
* @param name
* @return Class 注册对象的类型
* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
*/
public static Class<?> getType(String name) throws NoSuchBeanDefinitionException {
return getBeanFactory().getType(name);
}
/**
* 如果给定的bean名字在bean定义中有别名,则返回这些别名
*
* @param name
* @return
* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
*/
public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {
return getBeanFactory().getAliases(name);
}
}
|