千家信息网

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

发表于:2024-09-24 作者:千家信息网编辑
千家信息网最后更新 2024年09月24日,redis@Cacheable注解以及过期时间设置方式是什么,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。原理解释友情链接 手写re
千家信息网最后更新 2024年09月24日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 List listLeaders(String leaderGroupId, String uuid, String yearDetailId) {                return sysIndexMapper.listLeaders(leaderGroupId, uuid, yearDetailId);        }

等同于

        @Override        public List 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) 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 RedisTemplate redisTemplate(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...集合                List 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 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 List listLeaders(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注解以及过期时间设置方式是什么问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注行业资讯频道了解更多相关知识。

0