今天在写redission 的一个工具类的时候,随手写出下面的代码
package com.wt.redission.wtredission.utils;
import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component
public class RedissionUtilserror {
@Autowired
private static RedissonClient redissonClient;
public static RLock getRLock(String objectName) {
RLock rLock =redissonClient.getLock(objectName);
return rLock;
}
//根据名字获取map
public static <K, V> RMap<K, V> getRMap(String objectName) {
RMap<K, V> map = redissonClient.getMap(objectName);
return map;
}
//根据名字和值设置map
public static void setMap(String objectName,Object key,Object value){
RMap<Object, Object> map =redissonClient.getMap(objectName);
map.put(key,value);
}
//根据名字获取set
public static <V> RSet<V> getSet(String objectName) {
RSet<V> set = redissonClient.getSet(objectName);
return set;
}
//根据名字和值设置set
public static void setSet(String objectName,Object value){
RSet<Object> set = redissonClient.getSet(objectName);
set.add(value);
}
//根据名字获取list
public static <V> RList<V> getRList(String objectName) {
RList<V> rList = redissonClient.getList(objectName);
return rList;
}
//根据名字和值设置list
public static void setList(String objectName, int index,Object element ){
RList<Object> objectRList = redissonClient.getList(objectName);
objectRList.set(index,element);
}
//根据名字获取bucket
public static <T> RBucket<T> getRBucket(String objectName) {
RBucket<T> bucket = redissonClient.getBucket(objectName);
return bucket;
}
//根据名字和值 设置对应的bucket
public static <T> T setBucket(String objectName,String value){
RBucket<Object> bucket = redissonClient.getBucket(objectName);
bucket.set(value);
T t= (T) bucket.get(); //值类型由返回值确定
return t;
}
}
乍一看好像没问题 我写一个静态方法 然后在方法中使用静态变量redissonClient ,哇....,一切看得如此正常
当我开始测试时,NPE.............,我去这是怎么回事,自己在想这不科学啊,怎么会空指针,于是我开始找原因
最后发现是基础不牢啊............,对jvm的类加载机制几乎就没考虑,简要说要错误的原因
jvm在进行类加载的时候,首先会加载类变量,类方法,也就是我这里被static修饰的方法,然后当我调用静态方法进行使用的时候,会使用到redissionClient,注意这个redissionClient是通过autowired进来的,关键问题就在这里,autowired的底层是通过构造器和set方法注入bean的
redissionClient被static修饰 并且还是一个接口 在被调用的时候肯定没有实例化
下面提供三种方式正确使用
方式一
package com.wt.redission.wtredission.utils;
import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class RedissionUtils {
private static RedissonClient redissonClient;
@Autowired
public RedissionUtils(RedissonClient redissonClient){
RedissionUtils.redissonClient=redissonClient;
}
public static RLock getRLock(String objectName) {
RLock rLock = redissonClient.getLock(objectName);
return rLock;
}
//根据名字获取map
public static <K, V> RMap<K, V> getRMap(String objectName) {
RMap<K, V> map = redissonClient.getMap(objectName);
return map;
}
//根据名字和值设置map
public static void setMap(String objectName,Object key,Object value){
RMap<Object, Object> map =redissonClient.getMap(objectName);
map.put(key,value);
}
//根据名字获取set
public static <V> RSet<V> getSet(String objectName) {
RSet<V> set = redissonClient.getSet(objectName);
return set;
}
//根据名字和值设置set
public static void setSet(String objectName,Object value){
RSet<Object> set = redissonClient.getSet(objectName);
set.add(value);
}
//根据名字获取list
public static <V> RList<V> getRList(String objectName) {
RList<V> rList = redissonClient.getList(objectName);
return rList;
}
//根据名字和值设置list
public static void setList(String objectName, int index,Object element ){
RList<Object> objectRList = redissonClient.getList(objectName);
objectRList.set(index,element);
}
//根据名字获取bucket
public static <T> RBucket<T> getRBucket(String objectName) {
RBucket<T> bucket = redissonClient.getBucket(objectName);
return bucket;
}
//根据名字和值 设置对应的bucket
public static <T> T setBucket(String objectName,String value){
RBucket<Object> bucket = redissonClient.getBucket(objectName);
bucket.set(value);
T t= (T) bucket.get(); //值类型由返回值确定
return t;
}
}
方式二
package com.wt.redission.wtredission.utils;
import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component
public class RedissionUtils2 {
@Autowired
RedissonClient redissonClient;
public static RedissionUtils2 redissionUtils;
@PostConstruct
public void init(){
redissionUtils=this;
redissionUtils.redissonClient=this.redissonClient;
}
public static RLock getRLock(String objectName) {
RLock rLock = redissionUtils.redissonClient.getLock(objectName);
return rLock;
}
//根据名字获取map
public static <K, V> RMap<K, V> getRMap(String objectName) {
RMap<K, V> map = redissionUtils.redissonClient.getMap(objectName);
return map;
}
//根据名字和值设置map
public static void setMap(String objectName,Object key,Object value){
RMap<Object, Object> map =redissionUtils.redissonClient.getMap(objectName);
map.put(key,value);
}
//根据名字获取set
public static <V> RSet<V> getSet(String objectName) {
RSet<V> set = redissionUtils.redissonClient.getSet(objectName);
return set;
}
//根据名字和值设置set
public static void setSet(String objectName,Object value){
RSet<Object> set = redissionUtils.redissonClient.getSet(objectName);
set.add(value);
}
//根据名字获取list
public static <V> RList<V> getRList(String objectName) {
RList<V> rList = redissionUtils.redissonClient.getList(objectName);
return rList;
}
//根据名字和值设置list
public static void setList(String objectName, int index,Object element ){
RList<Object> objectRList = redissionUtils.redissonClient.getList(objectName);
objectRList.set(index,element);
}
//根据名字获取bucket
public static <T> RBucket<T> getRBucket(String objectName) {
RBucket<T> bucket = redissionUtils.redissonClient.getBucket(objectName);
return bucket;
}
//根据名字和值 设置对应的bucket
public static <T> T setBucket(String objectName,String value){
RBucket<Object> bucket = redissionUtils.redissonClient.getBucket(objectName);
bucket.set(value);
T t= (T) bucket.get(); //值类型由返回值确定
return t;
}
}
方式三 通过spring上下文获取
package com.wt.redission.wtredission.utils;
import io.micrometer.core.instrument.util.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
/**
* Spring Context工具类.
*
* @author:Hohn
*/
@Component
@Scope("singleton")
public class SpringUtil implements ApplicationContextAware {
/**
* Spring应用上下文环境.
*/
private static ApplicationContext applicationContext;
/**
* 实现ApplicationContextAware接口的回调方法,设置上下文环境
*
* <br>🌹param: applicationContext
* @throws BeansException
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringUtil.applicationContext = applicationContext;
}
/**
* 获取ApplicationContext.
*
* <br>🌹return: ApplicationContext
*/
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
/**
* 获取对象.
*
* <br>🌹param: name
* <br>🌹return: Object 一个以所给名字注册的bean的实例
* @throws BeansException
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) throws BeansException {
return (T) applicationContext.getBean(name);
}
/**
* 获取类型为requiredType的对象.
*
* <br>🌹param: clz
* <br>🌹return:
* @throws BeansException
*/
public static <T> T getBean(Class<T> clz) throws BeansException {
return (T)applicationContext.getBean(clz);
}
/**
* 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true
*
* <br>🌹param: name
* <br>🌹return: boolean
*/
public static boolean containsBean(String name) {
return applicationContext.containsBean(name);
}
/**
* 判断以给定名字注册的bean定义是一个singleton还是一个prototype。
* 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)
* <br>🌹param: name
* <br>🌹return: boolean
* @throws NoSuchBeanDefinitionException
*/
public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
return applicationContext.isSingleton(name);
}
/**
* <br>🌹param: name
* <br>🌹return: Class 注册对象的类型
* @throws NoSuchBeanDefinitionException
*/
public static Class<?> getType(String name) throws NoSuchBeanDefinitionException {
return applicationContext.getType(name);
}
/**
* 如果给定的bean名字在bean定义中有别名,则返回这些别名
*
* <br>🌹param: name
* <br>🌹return:
* @throws NoSuchBeanDefinitionException
*/
public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {
return applicationContext.getAliases(name);
}
/**
* 请求头获取请求token
* @param servletRequest
* @return
*/
public static String getJwtToken(HttpServletRequest servletRequest, String tokenId) {
String token = servletRequest.getHeader(tokenId);
if (StringUtils.isBlank(token)) {
token = servletRequest.getParameter(tokenId);
}
return token;
}
}