温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

redis@Cacheable注解以及过期时间设置方式是什么

发布时间:2022-01-04 00:26:20 来源:亿速云 阅读:829 作者:柒染 栏目:开发技术

redis@Cacheable注解以及过期时间设置方式是什么,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。


原理解释 

友情链接  手写redis @ Cacheable注解参数java对象作为键值 

@Cacheable注解作用,将带有该注解方法的返回值存放到redis的的中;

使用方法在方法上使用@Cacheable(键=“测试+#P0 + P1#...”)

表示键值为测试+方法第一个参数+方法第二个参数,值为该方法的返回值。

以下源代码表示获取人员列表,Redis的中存放的关键值为'领袖'+ leaderGroupId + UUID + yearDetailId

        @Override	@Cacheable(key="'leader'+#p0+#p1+#p2",value="leader")	public List<Leader> listLeaders(String leaderGroupId, String uuid, String yearDetailId) {	return sysIndexMapper.listLeaders(leaderGroupId, uuid, yearDetailId);	}

等同于

        @Override	public List<Leader> listLeaders(String leaderGroupId, String uuid, String yearDetailId) {	String key = "leader" + leaderGroupId + uuid + yearDetailId;	// 判断缓存是否存在redis中	boolean hasKey = redisUtil.hasKey(key);	if (hasKey) {                         //如果存在 返还redis中的值	Object leadersList = redisUtil.get(key);	return (List<Leader>) leadersList;	} else {	List<Leader> leadersQuotaDetailList = sysIndexMapper.listLeaders(leaderGroupId, uuid, yearDetailId);                         //将查询结果存放在redis中	redisUtil.set(key, leadersQuotaDetailList);	return leadersQuotaDetailList;	}	}

说白了就是在原方法的前面判断的关键值是否存在的Redis的中,如果存在就取内存中的值,如果不存在就查询数据库,将查询结果存放在Redis的的中。

实现方法

  • 使用代理模式,在方法执行前和执行后可以添加其他处理程序,本文采用springAOP +注解方式。

  • 集成redis,封装Redis工具类

  • 原版本不支持 过期时间 设置,本文将实现

源代码

缓存配置类RedisConfig

package com.huajie.config;  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.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper;   /**  * Redis缓存配置类  */ @Configuration @EnableCaching public class RedisConfig extends CachingConfigurerSupport {  	@Value("${spring.redis.host}")	private String host;	@Value("${spring.redis.port}")	private int port;	@Value("${spring.redis.timeout}")	private int timeout;  	// 自定义缓存key生成策略	@Bean	public KeyGenerator keyGenerator() {	return new KeyGenerator() {	@Override	public Object generate(Object target, java.lang.reflect.Method method, Object... params) {	StringBuffer sb = new StringBuffer();	sb.append(target.getClass().getName());	sb.append(method.getName());	for (Object obj : params) {	sb.append(obj.toString());	}	return sb.toString();	}	};	}  	// 缓存管理器	@Bean	public CacheManager cacheManager(@SuppressWarnings("rawtypes") RedisTemplate redisTemplate) {	RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);	// 设置缓存过期时间	cacheManager.setDefaultExpiration(10000);	return cacheManager;	}  	@Bean	public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {	RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();	template.setConnectionFactory(factory);	Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);	ObjectMapper om = new ObjectMapper();	om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);	om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);	jackson2JsonRedisSerializer.setObjectMapper(om);	StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();	// key采用String的序列化方式	template.setKeySerializer(stringRedisSerializer);	// hash的key也采用String的序列化方式	template.setHashKeySerializer(stringRedisSerializer);	// value序列化方式采用jackson	template.setValueSerializer(jackson2JsonRedisSerializer);	// hash的value序列化方式采用jackson	template.setHashValueSerializer(jackson2JsonRedisSerializer);	template.afterPropertiesSet();	return template;	}  	private void setSerializer(StringRedisTemplate template) {	@SuppressWarnings({ "rawtypes", "unchecked" })	Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);	ObjectMapper om = new ObjectMapper();	om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);	om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);	jackson2JsonRedisSerializer.setObjectMapper(om);	template.setValueSerializer(jackson2JsonRedisSerializer);	} }

Redis的依赖引入,配置文件,工具类RedisUtil,网上几个版本都类似,本文参考以下版本传送门

https://www.yisu.com/article/233562.htm

准备工作做好之后开始正式编写注解@Cacheable nextkey()用做二级缓存本文中不会用到

nextKey用法详情> 设计模式(实战) - 责任链模式 <

创建的Java的注解@ExtCacheable  

package com.huajie.annotation;  import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;   @Target({ ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) public @interface ExtCacheable {	String key() default "";	String nextKey() default ""; 	int expireTime() default 1800;//30分钟 }
 

SpringAop切面CacheableAspect

package com.huajie.aspect;  import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.huajie.annotation.ExtCacheable; import com.huajie.utils.RedisUtil;   /**  * redis缓存处理  * 不适用与内部方法调用(this.)或者private  */ @Component @Aspect public class CacheableAspect {	@Autowired	private RedisUtil redisUtil;  	@Pointcut("@annotation(com.huajie.annotation.ExtCacheable)")	public void annotationPointcut() {	}  	@Around("annotationPointcut()")	public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {	// 获得当前访问的class	Class<?> className = joinPoint.getTarget().getClass();	// 获得访问的方法名	String methodName = joinPoint.getSignature().getName();	// 得到方法的参数的类型	Class<?>[] argClass = ((MethodSignature) joinPoint.getSignature()).getParameterTypes();	Object[] args = joinPoint.getArgs();	String key = "";	int expireTime = 1800;	try {	// 得到访问的方法对象	Method method = className.getMethod(methodName, argClass);	method.setAccessible(true);	// 判断是否存在@ExtCacheable注解	if (method.isAnnotationPresent(ExtCacheable.class)) {	ExtCacheable annotation = method.getAnnotation(ExtCacheable.class);	key = getRedisKey(args,annotation);	expireTime = getExpireTime(annotation);	}	} catch (Exception e) {	throw new RuntimeException("redis缓存注解参数异常", e);	}	// 获取缓存是否存在	boolean hasKey = redisUtil.hasKey(key);	if (hasKey) {	return redisUtil.get(key);	} else {                          //执行原方法(java反射执行method获取结果)	Object res = joinPoint.proceed();                          //设置缓存	redisUtil.set(key, res);                          //设置过期时间	redisUtil.expire(key, expireTime);	return res;	}	}	private int getExpireTime(ExtCacheable annotation) {	return annotation.expireTime();	}  	private String getRedisKey(Object[] args,ExtCacheable annotation) {	String primalKey = annotation.key();	//获取#p0...集合	List<String> keyList = getKeyParsList(primalKey);	for (String keyName : keyList) {	int keyIndex = Integer.parseInt(keyName.toLowerCase().replace("#p", ""));	Object parValue = args[keyIndex];	primalKey = primalKey.replace(keyName, String.valueOf(parValue));	}	return primalKey.replace("+","").replace("'","");	}  	// 获取key中#p0中的参数名称	private static List<String> getKeyParsList(String key) {	List<String> ListPar = new ArrayList<String>();	if (key.indexOf("#") >= 0) {	int plusIndex = key.substring(key.indexOf("#")).indexOf("+");	int indexNext = 0;	String parName = "";	int indexPre = key.indexOf("#");	if(plusIndex>0){	indexNext = key.indexOf("#") + key.substring(key.indexOf("#")).indexOf("+");	parName = key.substring(indexPre, indexNext);	}else{	parName = key.substring(indexPre);	}	ListPar.add(parName.trim());	key = key.substring(indexNext + 1);	if (key.indexOf("#") >= 0) {	ListPar.addAll(getKeyParsList(key));	}	}	return ListPar;	} }

业务模块使用方法

@Override	@ExtCacheable(key = "Leaders+#p0+#p1+#p2")	// 手机端获取领导人员列表	public List<Leader> listLeaders(String leaderGroupId, String uuid, String yearDetailId) {	List<Leader> leadersQuotaDetailList = sysIndexMapper.listLeaders(leaderGroupId, uuid, yearDetailId);	return leadersQuotaDetailList;	}

业务模块过期时间使用方法,5分钟过期

@Override	@ExtCacheable(key = "mobileCacheFlag", expireTime = 60 * 5)	public int cacheFlag() {	int mobileCacheFlag = 1;	mobileCacheFlag = sysIndexMapper.cacheFlag();	return mobileCacheFlag;	}

Redis的的截图

redis@Cacheable注解以及过期时间设置方式是什么

关于redis@Cacheable注解以及过期时间设置方式是什么问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注亿速云行业资讯频道了解更多相关知识。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI