zoukankan      html  css  js  c++  java
  • 基于Redis的Service缓存实现

    项目中有使用到缓存,每次需要将缓存代码和业务代码杂糅在一起,以及分散各处的key,严重影响代码的可读性。以下是使用AOP对其简单尝试。直接上代码:

    1、定义缓存注解:

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Cache {
        long timeOut() default 0;
    
        TimeUnit timeUnit() default TimeUnit.HOURS;
    }

    2、定义参数唯一键注解,使用此注解标记此输入参数参与构成唯一键:

    @Target({ElementType.PARAMETER})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface CacheUniqueKey {
    }

    3、CacheAspect

    @Component
    @Slf4j
    @Aspect
    @Data
    public class CacheAspect {
        private final CacheCenter<String> cacheCenter;
       // 缓存开关配置
        @Value("${service.cache}")
        private boolean cacheEnable = false;
    
        @Around(value = "@annotation(com.yingying.survey.component.cache.Cache)&&@annotation(cache)")
        public Object around(ProceedingJoinPoint joinPoint, Cache cache) throws Throwable {
            if (!cacheEnable) {
                return joinPoint.proceed();
            }
    
            long timeOut = cache.timeOut();
            TimeUnit timeUnit = cache.timeUnit();
            if (timeOut == 0) {
                return joinPoint.proceed();
            }
    
            Class<?> clazz = joinPoint.getTarget().getClass();
            String clazzSimpleName = clazz.getSimpleName();
            String methodName = joinPoint.getSignature().getName();
    
            Signature signature = joinPoint.getSignature();
            Class declaringType = ((MethodSignature) signature).getReturnType();
    
            String uniqueParam = methodParamsResolve(joinPoint);
            String cacheKey = clazzSimpleName + ":" + methodName + ":" + uniqueParam;
            if (cacheCenter.isExistCache(cacheKey)) {
                String loadCache = cacheCenter.loadCache(cacheKey);
                log.info("data from cache:{}", loadCache);
                if (declaringType.isArray()) {
                    return JSONArray.parseArray(loadCache, declaringType);
                } else {
                    return JSON.parse(loadCache, declaringType);
                }
            }
    
            Object proceedResult = joinPoint.proceed();
            // 为了从缓存中取值时不出现空指针的情况,现不对返回值为空的结果缓存。
            if (proceedResult != null) {
                String cacheData = JSON.json(proceedResult);
                CacheUnit cacheUnit = new CacheUnit().setTimeUnit(timeUnit).setCacheOutTime(timeOut).setCacheKey(cacheKey);
                cacheCenter.insertCache(cacheUnit, cacheData);
            }
    
            return proceedResult;
        }
    
        private String methodParamsResolve(ProceedingJoinPoint joinPoint) {
            Signature signature = joinPoint.getSignature();
            Method method = ((MethodSignature) signature).getMethod();
            Annotation[][] parameterAnnotations = method.getParameterAnnotations();
    
            String uniqueParam = "";
            int idx = 0;
            for (Annotation[] annotations : parameterAnnotations) {
                for (Annotation annotation : annotations) {
                    if (annotation instanceof CacheUniqueKey) {
                        Object[] args = joinPoint.getArgs();
                        uniqueParam = (String) args[idx];
                        return uniqueParam;
                    }
                }
                idx++;
            }
            return uniqueParam;
        }
    }

    4、缓存配置单元:

    @Data
    @Accessors(chain = true)
    public class CacheUnit {
        @NotBlank
        @NotNull
        private String cacheKey;
    
        private long cacheOutTime = 0;
    
        @NotNull
        private TimeUnit timeUnit;
    }

    5、缓存中心实现接口:

    public interface CacheCenter<T> {
        boolean isExistCache(@NotNull @NotBlank String cacheKey);
    
        T loadCache(@NotNull @NotBlank String cacheKey);
    
        boolean insertCache(@NotNull CacheUnit cacheUnit, @NotNull T cacheData);
    }

    6、基于Redis的缓存中心实现:

    @Service("cacheCenter")
    @Data
    public class RedisCacheCenter implements CacheCenter<String> {
        private final RedisService redisService;
    
        @Override
        public boolean isExistCache(@NotNull @NotBlank String cacheKey) {
            return redisService.exists(cacheKey);
        }
    
        @Override
        public String loadCache(@NotNull @NotBlank String cacheKey) {
            return redisService.get(cacheKey);
        }
    
        @Override
        public boolean insertCache(@NotNull CacheUnit cacheUnit, @NotNull String cacheData) {
            long cacheOutTime = TimeUnit.SECONDS.convert(cacheUnit.getCacheOutTime(), cacheUnit.getTimeUnit());
            redisService.set(cacheUnit.getCacheKey().getBytes(), cacheData.getBytes(), cacheOutTime);
            return true;
        }
    }

    7、应用案例:

  • 相关阅读:
    计算机知识
    试题:论需求分析方法及应用
    试题:论信息系统开发方法及应用
    爬虫数据存储——安装docker和ElasticSearch(基于Centos7)
    go并发版爬虫
    go单任务版爬虫
    可变类型与不可变类型
    基本数据类型内置方法
    @submit.native.prevent作用
    获取当月第一天,今天的日期的方法
  • 原文地址:https://www.cnblogs.com/watson-ljf/p/10336995.html
Copyright © 2011-2022 走看看