这里做一个Reids的封装,可能相对有些复杂,但是很好用,全是静态方法直接调用,不需要每次都注入。
下面我的会详细的把过程列举出来,如果还是有问题可以联系我。
1、项目截图
2、代码
2-1:RedisConfig
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;
import java.lang.reflect.Method;
import java.time.Duration;
//继承CachingConfigurerSupport,为了自定义生成KEY的策略。可以不继承。
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
@Value("${spring.redis.jedis.pool.max-idle}")
private Integer maxidle;
@Value("${spring.redis.jedis.pool.min-idle}")
private Integer minidle;
@Value("${spring.redis.jedis.pool.max-active}")
private Integer maxActive;
@Value("${spring.redis.jedis.pool.min-idle}")
private Integer maxWait;
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private Integer port;
@Value("${spring.redis.database}")
private Integer database;
@Value("${spring.redis.password}")
private String password;
@Value("${spring.redis.timeout}")
private Integer timeout;
/**
* 缓存管理器.
*
* @param redisTemplate
* @return
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
RedisCacheManager manager = RedisCacheManager.create(connectionFactory);
return manager;
}
/**
* JedisPoolConfig 连接池
*
* @return
*/
@Bean
public JedisPoolConfig jedisPoolConfig() {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
Integer maxidle = this.maxidle;
Integer minidle = this.minidle;
Integer maxActive = this.maxActive;
Integer maxWait = this.maxWait;
// 最大空闲数
jedisPoolConfig.setMaxIdle(maxidle);
jedisPoolConfig.setMinIdle(minidle);
// 连接池的最大数据库连接数
jedisPoolConfig.setMaxTotal(maxActive);
// 最大建立连接等待时间
jedisPoolConfig.setMaxWaitMillis(maxWait);
// Idle时进行连接扫描
jedisPoolConfig.setTestWhileIdle(true);
// 表示idle object evitor两次扫描之间要sleep的毫秒数
jedisPoolConfig.setTimeBetweenEvictionRunsMillis(30000);
// 表示idle object evitor每次扫描的最多的对象数
jedisPoolConfig.setNumTestsPerEvictionRun(10);
// 表示一个对象至少停留在idle状态的最短时间,然后才能被idle object
// evitor扫描并驱逐;这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义
jedisPoolConfig.setMinEvictableIdleTimeMillis(60000);
// 在borrow一个jedis实例时,是否提前进行alidate操作
jedisPoolConfig.setTestOnBorrow(true);
// 在return给pool时,是否提前进行validate操作
jedisPoolConfig.setTestOnReturn(true);
return jedisPoolConfig;
}
@Bean
public JedisConnectionFactory connectionFactory(JedisPoolConfig jedisPoolConfig) {
String host = this.host;
Integer port = this.port;
Integer database = this.database;
String password = this.password;
Integer timeout = this.timeout;
RedisStandaloneConfiguration rf = new RedisStandaloneConfiguration();
rf.setHostName(host);
rf.setPort(port);
rf.setDatabase(database);
rf.setPassword(RedisPassword.of(password));
JedisClientConfiguration.JedisClientConfigurationBuilder jedisClientConfiguration = JedisClientConfiguration
.builder();
JedisClientConfiguration.JedisPoolingClientConfigurationBuilder jpb = jedisClientConfiguration
.usePooling();
jedisClientConfiguration.connectTimeout(Duration.ofMillis(timeout));// connection timeout
// 连接池
jpb.poolConfig(jedisPoolConfig);
JedisConnectionFactory factory = new JedisConnectionFactory(rf,
jedisClientConfiguration.build());
return factory;
}
/**
* 注解@Cache key生成规则
*/
@Bean
@Override
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
}
};
}
// 设置数据存入 redis 的序列化方式
@SuppressWarnings({ "rawtypes", "unchecked" })
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory) {
// 创建一个模板类
RedisTemplate<Object, Object> template = new RedisTemplate<>();
// 将redis连接工厂设置到模板类中
template.setConnectionFactory(factory);
// 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
serializer.setObjectMapper(mapper);
// 开启事务
// template.setEnableTransactionSupport(true);
template.setValueSerializer(serializer);
// 使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}
}
2-2:CacheContext
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.concurrent.TimeUnit;
/**
* 缓存管理工具
* @author 小道仙
* @date 2020年2月26日
*/
public class CacheContext<T extends CacheManager> {
static CacheManager cache;
/**
* 初始化方法
*
* @author 小道仙
* @date 2020年2月26日
* @version 1.0
*/
@SuppressWarnings("unchecked")
public void init() {
Type type = this.getClass().getGenericSuperclass();
if (type instanceof ParameterizedType) {
Class<T> entityClass;
Type[] parameterizedType = ((ParameterizedType) type).getActualTypeArguments();
entityClass = (Class<T>) parameterizedType[0];
try {
cache = entityClass.newInstance();
cache.init();
} catch (InstantiationException | IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* 批量删除对应的value
*
* @param keys
*/
public static void remove(final String... keys) {
cache.remove(keys);
}
/**
* 删除对应的value
*
* @param key
*/
public static boolean remove(final String key) {
return cache.remove(key);
}
/**
* 判断缓存中是否有对应的value
*
* @param key
* @return
*/
public static boolean exists(final String key) {
return cache.exists(key);
}
/**
* 读取缓存
*
* @param key
* @return
*/
public static Object get(final String key) {
return cache.get(key);
}
/**
* 写入缓存
*
* @param key
* @param value
* @return
*/
public static boolean set(final String key, Object value) {
return cache.set(key, value);
}
/**
* 写入缓存(可以配置过期时间-单位分钟)
*
* @param key
* @param value
* @return
*/
public static boolean set(final String key, Object value, long expireTime) {
return cache.set(key, value, expireTime);
}
/**
* 设置缓存时间,默认单位分钟
* @param key
* @param timeout
* @return
* @author 小道仙
* @date 2020年2月26日
* @version 1.0
*/
public static Boolean expire(String key, final long timeout) {
return cache.expire(key, timeout);
}
/**
* 设置缓存时间
* @param key
* @param timeout
* @return
* @author 小道仙
* @date 2020年2月26日
* @version 1.0
*/
public static Boolean expire(String key, final long timeout, final TimeUnit unit) {
return cache.expire(key, timeout,unit);
}
/**
* 获取key有效期
*
* @param key
* @return
* @author 小道仙
* @date 2020年2月26日
* @version 1.0
*/
public static Long getExpire(String key) {
return cache.getExpire(key);
}
}
2-3:CacheManager
import java.util.concurrent.TimeUnit;
public interface CacheManager {
/**
* 默认过期时间,单位分钟
*/
Long defaultExpirationTime = 30L;
/**
* 初始化方法
*
* @author 小道仙
* @date 2020年2月26日
* @version 1.0
*/
void init();
/**
* 批量删除对应的value
*
* @param keys
*/
void remove(final String... keys);
/**
* 删除对应的value
*
* @param key
*/
boolean remove(final String key);
/**
* 判断缓存中是否有对应的value
*
* @param key
* @return
*/
boolean exists(final String key);
/**
* 读取缓存
*
* @param key
* @return
*/
Object get(final String key);
/**
* 写入缓存
*
* @param key
* @param value
* @return
*/
boolean set(final String key, Object value);
/**
* 写入缓存(可以配置过期时间-单位分钟)
*
* @param key
* @param value
* @return
*/
boolean set(final String key, Object value, long expireTime);
/**
* 设置缓存时间,默认单位分钟
*
* @param key
* @param timeout
* @return
* @author 小道仙
* @date 2020年2月26日
* @version 1.0
*/
Boolean expire(String key, final long timeout);
/**
* 设置缓存时间
*
* @param key
* @param timeout
* @return
* @author 小道仙
* @date 2020年2月26日
* @version 1.0
*/
Boolean expire(String key, final long timeout, final TimeUnit unit);
/**
* 获取key有效期
*
* @param key
* @return
* @author 小道仙
* @date 2020年2月26日
* @version 1.0
*/
Long getExpire(String key);
}
2-4:RedisManager
import com.xdx97.framework.utils.SpringContextUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.io.Serializable;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@Component
public class RedisManager implements CacheManager {
private final Logger logger = LoggerFactory.getLogger(RedisManager.class);
@Resource
protected RedisTemplate<Serializable, Object> redisTemplate;
@Override
public void init() {
@SuppressWarnings("unchecked")
RedisTemplate<Serializable, Object> redisTemplate = (RedisTemplate<Serializable, Object>) SpringContextUtils
.getBean("redisTemplate");
if (redisTemplate != null && this.redisTemplate == null) {
this.redisTemplate = redisTemplate;
}
}
/**
* 批量删除对应的value
*
* @param keys
*/
@Override
public void remove(final String... keys) {
for (String key : keys) {
remove(key);
}
}
/**
* 批量删除key(通配符)
*
* @param pattern
*/
public void removePattern(final String pattern) {
Set<Serializable> keys = redisTemplate.keys(pattern);
if (keys.size() > 0){
redisTemplate.delete(keys);
}
}
/**
* 删除对应的value
*
* @param key
*/
@Override
public boolean remove(final String key) {
if (exists(key)) {
return redisTemplate.delete(key);
}
return true;
}
/**
* 判断缓存中是否有对应的value
*
* @param key
* @return
*/
@Override
public boolean exists(final String key) {
return redisTemplate.hasKey(key);
}
/**
* 读取缓存
*
* @param key
* @return
*/
@Override
public Object get(final String key) {
if (!exists(key)) {
return null;
}
Object result = null;
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
result = operations.get(key);
return result;
}
/**
* 写入缓存
*
* @param key
* @param value
* @return
*/
@Override
public boolean set(final String key, Object value) {
Integer expire = defaultExpirationTime.intValue() ;
return set(key, value, expire);
}
/**
* 写入缓存(可以配置过期时间-单位分钟)
*
* @param key
* @param value
* @return
*/
@Override
public boolean set(final String key, Object value, long expireTime) {
boolean result = false;
try {
if (expireTime <= 0) {
logger.warn("设置缓存时间不能小于0,key:{},value:{}", key, value);
return result;
}
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
operations.set(key, value);
expire(key, expireTime);
result = true;
} catch (Exception e) {
logger.warn("缓存设置失败,key:{},value:{}", key, value);
}
return result;
}
@Override
public Boolean expire(String key, final long timeout) {
return redisTemplate.expire(key, timeout, TimeUnit.MINUTES);
}
@Override
public Boolean expire(String key, final long timeout, final TimeUnit unit) {
return redisTemplate.expire(key, timeout, unit);
}
/**
* 获取key有效期
*
* @param key
* @return
* @author 小道仙
* @date 2020年2月26日
* @version 1.0
*/
@Override
public Long getExpire(String key) {
return redisTemplate.getExpire(key) == null ? 0 : redisTemplate.getExpire(key);
}
public void setRedisTemplate(RedisTemplate<Serializable, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
public RedisTemplate<Serializable, Object> getRedisTemplate() {
return redisTemplate;
}
}
2-5:RedisUtils
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;
/**
* RedisUtils
*
* @DependsOn(value = "springContextUtils")
* 作用是在这之前加载springContextUtils bean
*
* @author 小道仙
* @date 2020年2月26日
*/
@Component
@DependsOn(value = "springContextUtils")
public class RedisUtils extends CacheContext<RedisManager>{
public RedisUtils() {
super.init();
}
}
2-6:SpringContextUtils
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* Spring Context 工具类
*
* @author 小道仙
* @date 2020年2月26日
*/
@Component
public class SpringContextUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContextUtils.applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext() {
assertApplicationContext();
return applicationContext;
}
@SuppressWarnings("unchecked")
public static <T> T getBean(String beanName) {
assertApplicationContext();
return (T) applicationContext.getBean(beanName);
}
public static <T> T getBean(Class<T> requiredType) {
assertApplicationContext();
return applicationContext.getBean(requiredType);
}
private static void assertApplicationContext() {
if (SpringContextUtils.applicationContext == null) {
throw new RuntimeException("applicaitonContext属性为null,请检查是否注入了SpringContextHolder!");
}
}
}
2-7: yml
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-edpwGNM3-1582699118287)(https://www.xdx97.com:8185/api/preview?url=uploads/ARTICLE/root/article/2020-02-26/xdx_qXYi7XsGUzAdNIKx.png)]
# redis配置
redis:
database: 0
host: 47.100.60.252
port: 8379
password: fdE#84K$EW~
timeout: 3000
jedis:
pool:
max-active: 8
max-idle: 8
max-wait: -1
min-idle: 0
3、使用
封装的时候有点麻烦,所以使用的时候超级简单了。
关注我吧,和我一起进步: