1. 改造之前的代码
之间的代码注入方法直接声明了公共的静态字段, 所以不满足封装原则, 因为我可以在任意的地方给 redisTemplate 字段重新赋值, 可能会导致程序出错
2. 改造之后的代码
改造思路是为了满足封装原则
1. RedisUtil 工具类, 里面提供静态方法, 需要在外部直接调用 RedisUtil.set() 方法或其他方法完成对 redis 的操作
2. redisTemplate 需要封装到 RedisUtil 内部, redisTemplate 必须是私有的, 不能通过外部传递, 阻止外部调用对 redisTemplate 重新赋值
3. redisTemplate 必须是静态的, 因为操作 redis 的方法是静态的, 需要用 RedisUtil 类名直接调用
4. RedisUtil 的构造器必须是私有的, 防止在外部创建对象, 如果需要创建对象, 这个对象必须是单例的
改造其实很简单, 依赖 @Autowired 注解
第一 : 私有化构造器, 防止在类的外部实例化, 当然你可以用反射, 但是即便用了反射创建了对象, 也没办法在外部调用私有静态字段和私有方法
第二 : redisTemplate 字段应该是私有的, 防止在外部重新赋值, 而且必须是静态的, 应为需要在静态的方法中使用
第三 : 由于 redisTemplate 字段是静态的, 没办法在字段上使用 @Autowired 注解, 所以需要提供一个方法, 在方法上使用 @Autowired 注解, 方法内部给静态字段赋值, 并且该方法需要是私有的, 也是为了防止在类的外部被调用
类中的 setRedisTemplate() 为什么会被调用不清楚的可以看下 @Autowired 的原理, 简单来说就是 :
Spring 在通过 byName 的自动填充属性时流程是 :
1. 找到所有set方法所对应的XXX部分的名字
2. 根据XXX部分的名字去获取bean
Spring 在通过 byType 的自动填充属性时流程是 :
1. 获取到set方法中的唯一参数的参数类型,并且根据该类型去容器中获取bean
2. 如果找到多个,会报错。
相关源码体现 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition
附上这个工具类的全代码
package com.kone.sp.common.redis2.utils;
import com.kone.sp.common.redis2.config.LettuceConnectionAutoConfiguration;
import com.kone.sp.common.redis2.config.RedisTemplateAutoConfiguration;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* @author yukun.yan
* @description RedisUtil redis缓存自动配置
* @date 2023/5/5 10:15
*/
@Slf4j
@AutoConfigureAfter({RedisTemplateAutoConfiguration.class, LettuceConnectionAutoConfiguration.class})
public class RedisUtil {
/**
* 构造器应该是私有的
*/
private RedisUtil() {
}
/**
* 静态注入字段, 必须私有化, 满足封装原则
*/
private static RedisTemplate redisTemplate;
/**
* 因为静态字段没办法直接使用 @Autowired 注入, 所以可以提供一个方法
* 而且方法应该是私有的, 只能在类的内部调用, 防止重新给 redisTemplate 赋值
*/
@Autowired
private void setRedisTemplate(RedisTemplate redisTemplate) {
RedisUtil.redisTemplate = redisTemplate;
}
/**
* @param key 需要获取目标数据的唯一标识key
* @return 返回key对应唯一的value
*/
public static Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
}
/**
* @param key 指定redis key
* @param time 设置过期时间 单位秒
* @return 设置成功状态
*/
public static Boolean expire(String key, long time) {
return expire(key, time, TimeUnit.SECONDS);
}
/**
* @param key 指定redis key
* @param time 设置过期时间
* @param timeUnit 时间单位
* @return 设置成功状态
*/
public static Boolean expire(String key, long time, TimeUnit timeUnit) {
return redisTemplate.expire(key, time, timeUnit);
}
/**
* @param key 指定redis key
* @return 当前key的过期时间 单位秒
*/
public static long getExpire(String key) {
return Optional.ofNullable(redisTemplate.getExpire(key, TimeUnit.SECONDS)).orElse(0L);
}
/**
* @param key 所存储的 key值
* @param value 所存储的 value值
*/
public static void set(String key, Object value) {
redisTemplate.opsForValue().set(key, value);
}
/**
* @param key 所存储的 key值
* @param value 所存储的 value值
* @param time 设置存储后过期时间 单位秒
*/
public static void zset(String key, Object value, long time) {
set(key, value, time, TimeUnit.SECONDS);
}
/**
* @param key 所存储的 key值
* @param value 所存储的 value值
* @param time 设置存储后过期时间
* @param timeUnit 时间单位
*/
public static void set(String key, Object value, long time, TimeUnit timeUnit) {
redisTemplate.opsForValue().set(key, value, time, timeUnit);
}
/**
* 检查如果当前key不为存在则新增 存在则不改变已经有的值
*
* @param key 所存储的 key值
* @param value 所存储的 value值
* @return 返回是否修改当前key对应的value的状态结果
*/
public static boolean setIfAbsent(String key, Object value) {
return Optional.ofNullable(redisTemplate.opsForValue().setIfAbsent(key, value)).orElse(false);
}
/**
* 检查如果当前key不为存在则新增 存在则不改变已经有的值
*
* @param key 所存储的 key值
* @param value 所存储的 value值
* @param time 设置存储后过期时间 单位秒
* @return 返回是否修改当前key对应的value的状态结果
*/
public static boolean setIfAbsent(String key, Object value, long time) {
return setIfAbsent(key, value, time, TimeUnit.SECONDS);
}
/**
* 检查如果当前key不为存在则新增 存在则不改变已经有的值
*
* @param key 所存储的 key值
* @param value 所存储的 value值
* @param time 设置存储后过期时间
* @param timeUnit 时间单位
* @return 返回是否修改当前key对应的value的状态结果
*/
public static boolean setIfAbsent(String key, Object value, long time, TimeUnit timeUnit) {
return Optional.ofNullable(redisTemplate.opsForValue().setIfAbsent(key, value, time, timeUnit)).orElse(false);
}
/**
* @param key 删除key
*/
public static void delete(String key) {
if (StringUtils.isEmpty(key)) {
return;
}
redisTemplate.delete(key);
}
/**
* 批量删除key
*
* @param keys 删除keys
*/
public static void delete(Collection keys) {
redisTemplate.delete(keys);
}
/**
* 模糊删除
*
* @param likeKey 模糊删除的key, 比如"zhangsan*", 这时就会删除所有以zhangsan开头的key所对应的value
*/
public static void deleteLike(String likeKey) {
Set keys = keys(likeKey);
if (keys != null && keys.size() > 0) {
redisTemplate.delete(keys);
}
}
/**
* 模糊查询key
*
* @param likeKey 模糊删除的key, 比如"zhangsan*", 这时就会删除所有以zhangsan开头的key所对应的value
*/
public static Set keys(String likeKey) {
return redisTemplate.keys(likeKey);
}
/**
* @param keys 批量获取 keys
* @return 返回缓存的对象数据
*/
public static List