redis@Cacheable注解以及过期时间设置方式是什么
redis@Cacheable注解以及过期时间设置方式是什么,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。
原理解释
友情链接 手写redis @ Cacheable注解参数java对象作为键值
@Cacheable注解作用,将带有该注解方法的返回值存放到redis的的中;
使用方法在方法上使用@Cacheable(键="测试+#P0 + P1#...")
表示键值为测试+方法第一个参数+方法第二个参数,值为该方法的返回值。
以下源代码表示获取人员列表,Redis的中存放的关键值为'领袖'+ leaderGroupId + UUID + yearDetailId
@Override @Cacheable(key="'leader'+#p0+#p1+#p2",value="leader") public ListlistLeaders(String leaderGroupId, String uuid, String yearDetailId) { return sysIndexMapper.listLeaders(leaderGroupId, uuid, yearDetailId); }
等同于
@Override public ListlistLeaders(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 ) leadersList; } else { List 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@EnableCachingpublic 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 RedisTemplateredisTemplate(RedisConnectionFactory factory) { RedisTemplate template = new RedisTemplate (); 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@Aspectpublic 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...集合 ListkeyList = 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 getKeyParsList(String key) { List ListPar = new ArrayList (); 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 ListlistLeaders(String leaderGroupId, String uuid, String yearDetailId) { List 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注解以及过期时间设置方式是什么问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注行业资讯频道了解更多相关知识。