AOP及自定义注解实现Redis缓存

2020/10/21 posted in  Java

背景

现在程序中是直接查询数据库数据的,Redis只是用来生成一些不重复id用的,现在要把Redis利用起来,缓存一些配置信息,提高程序运行及响应时间。

设计

  • 在Dao层查询数据库之前,先查一下是否在Redis缓存中,如果存在的话直接取Redis中的数据,如果不存在,在去查询数据库,然后将本次查询结果根据查询条件放到缓存中。
  • Redis在系统启动的时候先去清空配置信息。
  • 提供刷新缓存、删除缓存的方法

实现之前

在Dao层中每个查询配置信息的方法中,增加查询缓存及设置缓存的方法。
但是Dao层中的方法太多了。。。一个个加比较枯燥、主要是显得比较low,然后要想个方案实现。

方案

很自然就想到了AOP,环绕通知,
在目标方法执行之前先查询缓存,如果有就返回了,如果没有再去执行目标方法,
在执行目标方法之后将查询条件及内容放到Redis中。
自定义一个注解,被这个注解修饰的方法需要实现AOP。

实现

定义一个缓存注解,被这个注解修饰的方法,会执行切面中的方法。

/**
 * redis缓存注解
 * @author hitol
 * @version $Id: RedisCache.java, v 0.1 2020年3月19日 下午8:26:48 hitol Exp $
 */
@Documented
@Target({java.lang.annotation.ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RedisCache {
	String redisKey() default "";

	String cacheInfo() default "";

	Class<?> className() default String.class;
}


定义缓存切面,使用环绕通知.

/**
 * 缓存切面
 * @author hitol
 * @version $Id: CacheAop.java, v 0.1 2020年3月20日 下午6:49:10 hitol Exp $
 */
@Aspect
@Component
public class CacheAop {

    private static final Logger LOGGER = LoggerFactory.getLogger(CacheAop.class);

    @Pointcut("@annotation(com.acc.ac.core.util.redis.RedisCache)")
    public void getCacheInfo() {
        LOGGER.info("切入点");
    }

    @Around("getCacheInfo()")
    public Object doBefore(ProceedingJoinPoint joinPoint) throws Throwable {

        // 接口的参数
        Object[] args = joinPoint.getArgs();
        String arg = "";
        if (args.length > 0){
            arg = (String) args[0];
        }

        // 得到被代理的方法
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();

        // 得到被代理的方法上的注解
        RedisCache annotation = method.getAnnotation(RedisCache.class);

        Class<?> className = annotation.className();
        String redisKey = annotation.redisKey() + arg;
        Class returnType = method.getReturnType();

        LOGGER.info("key = {},查询Redis缓存", redisKey);
        String cacheInfo = RedisUtils.getString(redisKey);

        if (StringUtils.isNotBlank(cacheInfo)) {
            LOGGER.info("key = {},在Redis缓存中.", redisKey);

            if ("java.util.List".equals(returnType.getName())){
                return JSONObject.parseArray(cacheInfo,className);
            }

            return JSONObject.parseObject(cacheInfo, returnType);
        }
        LOGGER.info("key = {},没有在Redis缓存中查询到.", redisKey);
        Object result = joinPoint.proceed(args);
        cacheInfo = JSONObject.toJSONString(result);

        if (StringUtils.isNotBlank(cacheInfo)) {
            RedisUtils.setString(redisKey, cacheInfo);
        }

        return JSONObject.parseObject(cacheInfo, returnType);

    }
}

完成。