概述
目录
一、Maven依赖
二、Redis配置类
三、使用@Cacheable注解进行数据缓存
四、自定义Redis工具类及使用
4.1 序列化工具类
4.2 redis客户端工具类
4.3 redis客户端工具类使用Demo
在日常的开发中,使用Redis作为缓存中间件来提高查询性能已经很常见。通常为了简化开发,提高开发效率,我们在实际开发中会封装一些工具类来满足我们的诉求。
本文以Java工程为例,介绍基于JedisPool的Redis工具类的使用。
一、Maven依赖
<!-- jedis依赖-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.3</version>
</dependency>
二、Redis配置类
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import redis.clients.jedis.JedisPoolConfig;
import java.time.Duration;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* Redis配置类,Redis集群为主从模式。
*/
@Configuration
@Slf4j
@EnableCaching
public class RedisConfig {
/**
* 30分钟缓存
*/
public final static Integer SECOND_1800 = 30*60;
/**
* Redis Host
*/
@Value("${spring.redis.host}")
private String redisHost;
/**
* Redis Port
*/
@Value("${spring.redis.port}")
private Integer redisPort;
/**
* Redis Password
*/
@Value("${spring.redis.password}")
private String redisPassWord;
/**
* jedis pool config
* 配置连接池线程数(减少线程的频繁创建带来的开销)、超时时间(提高服务可用性)等参数。
* @return
*/
@Bean
public JedisPoolConfig jedisPoolConfig() {
JedisPoolConfig config = new JedisPoolConfig();
// 连接池中最小空闲连接
config.setMinIdle(1);
// 连接池中最大空闲连接
config.setMaxIdle(8);
// 连接池最大连接数
config.setMaxTotal(8);
// 连接池最大堵塞等待时间,2000ms
config.setMaxWaitMillis(2000L);
// 获取连接时校验有效性
config.setTestOnBorrow(true);
// 连接空闲时定时校验有效性
config.setTestWhileIdle(true);
// 连接空闲时定时校验有效性间隔时间,1分钟
config.setTimeBetweenEvictionRunsMillis(1000L*60);
return config;
}
/**
* 创建JedisClient
* @return
*/
@Bean
public JedisClientConfiguration jedisClientConfiguration(JedisPoolConfig jedisPoolConfig) {
JedisClientConfiguration.JedisClientConfigurationBuilder builder = JedisClientConfiguration.builder();
return builder.usePooling()
.poolConfig(jedisPoolConfig)
.build();
}
/**
* 配置Redis连接。
* Reids一共提供了RedisStandaloneConfiguration(单节点)、RedisSentinelConfiguration(哨兵)、RedisClusterConfiguration(集群)
* @return
*/
@Bean
RedisStandaloneConfiguration redisStandaloneConfiguration() {
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setHostName(redisHost);
redisStandaloneConfiguration.setPort(redisPort);
redisStandaloneConfiguration.setPassword(redisPassWord);
return redisStandaloneConfiguration;
}
/**
* 创建jedis客户端
* @param redisStandaloneConfiguration redis连接
* @param jedisClientConfiguration redis客户端配置
* @return
*/
@Bean
public JedisConnectionFactory jedisConnectionFactory(RedisStandaloneConfiguration redisStandaloneConfiguration,
JedisClientConfiguration jedisClientConfiguration) {
log.info("ConnectTimeOut {}",jedisClientConfiguration.getConnectTimeout());
log.info("ReadTimeOut {}",jedisClientConfiguration.getReadTimeout());
JedisConnectionFactory factory = new JedisConnectionFactory(redisStandaloneConfiguration,jedisClientConfiguration);
return factory;
}
// 为方便使用Spring @Cacheable等注解进行的配置 ----------------------Start
public final static String CACHE_5MINUTES = "cache:5m";
public final static String CACHE_10MINUTES = "cache:10m";
public final static String CACHE_30MINUTES = "cache:30m";
public final static String CACHE_60MINUTES = "cache:60m";
/**
* 自定义缓存管理器
*/
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory factory) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
// 生成
Set cacheNames = new HashSet<>();
cacheNames.add(CACHE_5MINUTES);
cacheNames.add(CACHE_10MINUTES);
cacheNames.add(CACHE_30MINUTES);
cacheNames.add(CACHE_60MINUTES);
ConcurrentHashMap configMap = new ConcurrentHashMap<>();
// 自定义缓存时间
// 5分钟缓存
configMap.put(CACHE_5MINUTES, config.entryTtl(Duration.ofMinutes(5L)));
// 10分钟缓存
configMap.put(CACHE_10MINUTES, config.entryTtl(Duration.ofMinutes(10L)));
// 30分钟缓存
configMap.put(CACHE_30MINUTES, config.entryTtl(Duration.ofMinutes(30L)));
// 60分钟缓存
configMap.put(CACHE_60MINUTES, config.entryTtl(Duration.ofMinutes(60L)));
//
//永久 key1 的有效期是永久的
//
configMap.put("distributor", config);
// 需要先初始化缓存名称,再初始化其它的配置。
RedisCacheManager cacheManager = RedisCacheManager.builder(factory).initialCacheNames(cacheNames).withInitialCacheConfigurations(configMap).build();
return cacheManager;
}
// 以下内容为方便使用Spring @Cacheable等注解进行的配置 ----------------------End
}
三、使用@Cacheable注解进行数据缓存
@Cacheable(value= RedisConfig.CACHE_5MINUTES,key="'hasPermission' + #userId + #uri")
public Boolean hasPermission(String uri, Long userId) {
}
@Cacheable是Spring提供的注解,对于只读的场景使用很方便。但需要注意,如果是在同一个Class中调用这类方法,@Cacheable的切面会失效(即缓存不生效)。@Cacheable注解比较适合在基础的Service层使用。
@Cacheable中,缓存的key也可以自定义生成,下面是一个自定生成器及使用案例,可参考。
/**
* 通过类名+方法名+参数值生成key值
*/
@Component
public class UserKeyGenerator extends CachingConfigurerSupport {
@Bean
public KeyGenerator cacheKeyGenerator() {
return (target,method,params) -> {
StringBuffer key = new StringBuffer();
String strParams = "";
if(params!=null && params.length>0){
strParams = Arrays.asList(params).stream().map(String::valueOf).collect(Collectors.joining(","));
}
key.append(target.getClass().getName() + method.getName() + strParams);
return key.toString();
};
}
}
/**
* 在@Cacheable中使用cacheKeyGenerator作为缓存key生成器
*/
@Cacheable(value= RedisConfig.CACHE_5MINUTES,key="cacheKeyGenerator")
public Boolean hasPermission(String uri, Long userId) {
}
另外@Cacheable方式的加入的缓存如果要进行手动删除,可通过如下方式。
@CacheEvict(cacheNames={RedisConfig.CACHE_5MINUTES,RedisConfig.CACHE_10MINUTES,RedisConfig.CACHE_30MINUTES,RedisConfig.CACHE_60MINUTES},key = "#key")
public String cacheDelete(@RequestParam(value = "key") String key){
return "缓存删除成功";
}
四、自定义Redis工具类及使用
在实际的开发场景中,在进行Redis操作时,往往会涉及到一些业务逻辑,这个时候使用类似@Cacheable的注解就显得有些不够灵活。此时可以通过工具类的方式,提高开发的效率。
4.1 序列化工具类
import lombok.extern.slf4j.Slf4j;
import java.io.*;
/**
* 序列化工具
* @author zhouhanfei 2021.12.2
*/
@Slf4j
public class SerializeUtil {
public static byte[] serialize(Object o) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
ObjectOutputStream outo = new ObjectOutputStream(out);
outo.writeObject(o);
} catch (IOException e) {
log.error("serialize exception",e);
}
return out.toByteArray();
}
public static Object unSerialize(byte[] b) {
ObjectInputStream oin;
try {
oin = new ObjectInputStream(new ByteArrayInputStream(b));
try {
return oin.readObject();
} catch (ClassNotFoundException e) {
log.error("unSerialize readObject exception",e);
return null;
}
} catch (IOException e) {
log.error("unSerialize exception",e);
return null;
}
}
}
4.2 redis客户端工具类
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* 基于RedisTemplate的Redis工具类
*/
@Component
@Slf4j
public class RedisUtil {
@Resource
private RedisTemplate redisTemplate;
/**
* 插入(覆盖)某个缓存
* @param key
* @param value
* @param timeToLive 过期时间,单位秒
* */
public boolean put(String key, Object value, int timeToLive) {
if (key == null || value == null) {
return false;
}
if(redisTemplate==null){
log.debug("redisTemplate is null");
return false;
}
try {
if (timeToLive > 0) {
redisTemplate.opsForValue().set(key, value, timeToLive, TimeUnit.SECONDS);
}else{
redisTemplate.opsForValue().set(key,value);
}
return true;
} catch (Exception e) {
log.error("redis util string key put exception", e);
}
return false;
}
/**
* 插入(覆盖)某个缓存
* @param key
* @param value
* @param timeToLive 过期时间,单位秒
* */
public boolean put(byte[] key, Object value, int timeToLive) {
if (key == null || value == null){
return false;
}
if(redisTemplate==null){
log.debug("redisTemplate is null");
return false;
}
try {
if (timeToLive > 0) {
redisTemplate.opsForValue().set(key, value, timeToLive, TimeUnit.SECONDS);
}else{
redisTemplate.opsForValue().set(key,value);
}
return true;
} catch (Exception e) {
log.error("redis util byte key put exception", e);
}
return false;
}
/**
* 根据key获取缓存
* @param key
* */
public Object get(String key) {
if (key == null) {
return null;
}
if(redisTemplate==null){
log.debug("redisTemplate is null");
return null;
}
try {
return redisTemplate.opsForValue().get(key);
} catch (Exception e) {
log.error("redis util get exception", e);
return null;
}
}
/**
* 根据key获取缓存
* @param key
* */
public byte[] getByte(byte[] key) {
if (key == null) {
return null;
}
if(redisTemplate==null){
log.debug("redisTemplate is null");
return null;
}
try {
return SerializeUtil.serialize(redisTemplate.opsForValue().get(key));
} catch (Exception e) {
log.error("redis util getByte exception", e);
return null;
}
}
/**
* 根据key获取缓存
* @param key
* */
public Object get(byte[] key) {
if (key == null) {
return null;
}
if(redisTemplate==null){
log.debug("redisTemplate is null");
return null;
}
try {
return redisTemplate.opsForValue().get(key);
} catch (Exception e) {
log.error("redis util getObject exception", e);
return null;
}
}
/**
* 递增某个数据(这个数据没有被序列化,不能用get查询)
* @param key
* @param delta
* @param timeToLive 超时时间,单位秒
* @return
*/
public long incr(String key, long delta, int timeToLive) {
if (key == null){
return -1;
}
if(redisTemplate==null){
log.debug("redisTemplate is null");
return -1;
}
try {
long result = redisTemplate.opsForValue().increment(key,delta);
if (timeToLive > 0) {
redisTemplate.expire(key, timeToLive, TimeUnit.SECONDS);
}
return result;
} catch (Exception e) {
log.error("redis util incr exception", e);
return -1;
}
}
/**
* 删除某个缓存
* @param key
* */
public boolean delete(String key) {
if (key == null) {
return false;
}
if(redisTemplate==null){
log.debug("redisTemplate is null");
return false;
}
try {
redisTemplate.delete(key);
return true;
} catch (Exception e) {
log.error("redis util delete exception", e);
return false;
}
}
/**
* 插原子缓存,同名key已存在返回false
* @param key
* @param value
* @param timeToLive 超时时间,单位秒
* */
public boolean setAtomCache(String key, Object value, int timeToLive) {
if (key == null || value == null) {
return false;
}
if(redisTemplate==null){
log.debug("redisTemplate is null");
return false;
}
boolean success = false;
try {
// 不存在则添加缓存
success = redisTemplate.opsForValue().setIfAbsent(key, value);
} catch (Exception e) {
log.error("redis util setAtomCache-setIfAbsent exception", e);
}
// 如果存活时间大于0,则设置存活时间
if (timeToLive > 0){
try {
redisTemplate.expire(key, timeToLive,TimeUnit.SECONDS);
} catch (Exception e) {
log.error("redis util setAtomCache-expire exception", e);
}
}
return success;
}
/**
* 判断key是否存在
* @param key
* @return
*/
public boolean exists(Object key){
return redisTemplate.hasKey(key);
}
/**
* 根据关键值模糊匹配
* @param keyPer
* @return
*/
public Set<String> keys(String keyPer){
return redisTemplate.keys(keyPer);
}
4.3 redis客户端工具类使用Demo
@Resource
private RedisUtil redisUtil;
public String useDemo(Long cloudUId) {
String key = "xxx";
if(redisUtil.exists(key)){
return redisUtil.get(key);
}
String result = db.findById(1);
redisUtil.put(key,result,RedisConfig.SECOND_1800);
return str;
}
最后
以上就是粗心火为你收集整理的Java开发中的工具类——基于JedisPool的Redis工具类一、Maven依赖二、Redis配置类三、使用@Cacheable注解进行数据缓存四、自定义Redis工具类及使用的全部内容,希望文章能够帮你解决Java开发中的工具类——基于JedisPool的Redis工具类一、Maven依赖二、Redis配置类三、使用@Cacheable注解进行数据缓存四、自定义Redis工具类及使用所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复