• 注解及AOP实现Redis缓存组件


    使用AOP以及注解实现缓存组件

    1. 为什么使用AOP和注解实现缓存?

      项目是一个报表系统,使用druid.io查询hue,每次查询巨大,可以达到每次30多M,而且后台也有很多运算,每次查询对服务器对压力很大,经常出现young gc,因此计划加入缓存提高查询效率,同时减少服务端的压力。

    2. 为什么这么设计?

      报表系统的一个基本逻辑:根据查询参数查询数据库,由于是离线的库,每天刷一遍数据,所以每次请求之间的区别仅仅是传递的参数,所以可以将缓存的位置直接放在controller层,根据传递的参数来缓存数据,这样使用注解来实现就比较好了。

    3. 注解

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD, ElementType.TYPE})
    public @interface Cache {
        int expire() default 60 * 60 * 12;
    
        String type() default "Object";
    
        Class returnClass() default Object.class;
    
        Class param() default Object.class;
    }

     

    其中expire是缓存的保存时间,type是返回的类型是Object还是List形式的对象,returnClass是返回的对象类型,param是参数的类型

    4. 设计切面类

    /**
     * @author 张驰
     * @since 26 九月 2018
     */
    @Aspect
    @Component
    public class CacheInterceptor {
        private static final String OBJECT = "Object";
    
        private static final String LIST = "List";
    
        private static final String PRE_KEY = "md_cache";
    
        @Autowired
        private JedisClient jedisClient;
    
        @SuppressWarnings("unchecked")
        @Around("@annotation(com.wormpex.data.warehouse.biz.utils.cache.Cache)")
        public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
            if (joinPoint == null) {
                return null;
            }
    
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            Cache myAnnotation = method.getAnnotation(Cache.class);
            String type = myAnnotation.type();
            Class returnClass = myAnnotation.returnClass();
    
            String key = "";
            try {
                key = getKey(joinPoint, method);
                //如果没有命中到缓存值。应该调用目标函数,通过目标函数计算实际值。
                String result = jedisClient.get(key);
                if (StringUtils.isNotBlank(result)) {
                    switch (type) {
                        case OBJECT:
                            if (returnClass.equals(JsonResult.class)) {
                                JsonResult jsonResult = JsonUtil.of(result, JsonResult.class);
                                if (!jsonResult.isSuccess()) {
                                    jedisClient.del(key);
                                    return joinPoint.proceed();
                                }
                            }
                            return JsonUtil.of(result, returnClass);
                        case LIST:
                            return JsonUtil.ofList(result, returnClass);
                        default:
                            jedisClient.del(key);
                            return joinPoint.proceed();
                    }
                }
            }
            catch (Throwable t) {
                jedisClient.del(key);
                return joinPoint.proceed();
            }
    
            Object o = joinPoint.proceed();
            jedisClient.set(key, JsonUtil.toJson(o));
            jedisClient.expire(key, myAnnotation.expire());
            return o;
        }
    
        /**
         * 根据参数生成cachekey
         * @param joinPoint
         * @param method
         * @return
         */
        @SuppressWarnings("unchecked")
        private String getKey(ProceedingJoinPoint joinPoint, Method method) {
            Class paramClass = method.getAnnotation(Cache.class).param();
            String methodName = method.getDeclaringClass().getPackage().toString() + method.getName() + paramClass.getName();
            return PRE_KEY + methodName + MD5Util.encode(String.valueOf(JsonUtil.toJson(get(paramClass, joinPoint.getArgs()[0]))));
        }
    
        private static <T> T get(Class<T> clz, Object o) {
            if (clz.isInstance(o)) {
                return clz.cast(o);
            }
            throw new IllegalArgumentException();
        }
    }

     

  • 相关阅读:
    商业分析07_15辅助产品设计
    商业分析07_14行为序列的分析方法
    商业分析07_13路径挖掘的分析方法
    商业分析07_12精准运营推送
    商业分析07_11归因查找
    商业分析07_10高质量拉新
    商业分析07_08功能/内容上线的评估
    商业分析07_07用户留存分析
    Ubuntu14.04安装CUDA8.0与Cudnn5.1
    Windows编译libcaffe时报cudnn.hpp(114): too few arguments in function call错误
  • 原文地址:https://www.cnblogs.com/zhangchiblog/p/9718952.html
Copyright © 2020-2023  润新知