java springboot采用自定义注解形式封装Redis缓存

目前系统主要负责读取数据库对外提供数据接口,为了防止高并发集成了Redis和相应Redis工具类,避免缓存造轮子,封装了个注解@RedisGeneralAnnotation用以实现对该方法所有缓存读写操作。

集成Redis和封装操作Util类步骤跳过,网上一大堆就不详述了;
为了篇幅所有类中的import也省略;

1.编写Redis自定义注解@RedisGeneralAnnotation


/**
 * @Description:Redis注解
 * @Author: lifay
 * @datetime:2019/5/28 16:32
 *
 */

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RedisGeneralAnnotation {

    /**
     * 缓存数据类型
     */
    CacheType type();

    /**
     * 缓存key
     */
    CacheKeys key();

    /**
     * 失效时间
     */
    long expired() default 3600L;

    /**
     * 预留字段
     */
    boolean read() default true;

}

Target -- 指定注解在方法上
Retention -- 指定RUNTIME运行都启用
CacheType、CacheKeys -- 很好理解,前者是缓存数据类型,也就是具体方法的返回数据类型,后者是Redis的Key,不过两者都采用枚举形式,避免重复,并且必填
expired -- 失效时间 默认3600s

2.CacheType

/**
 * @Description:
 * @Author: lifay
 * @Return:
 * @datetime:2019/5/29 15:29
 *
 */
public enum CacheType {

    STRING,

    ENTITY,

    LIST,

    MAP
}

3.CacheKeys

/**
 * @Description:Redis缓存Keys容器
 * @Author: lifay
 * @Return:
 * @datetime:2019/5/29 17:04
 *
 */
public enum CacheKeys {

    /*获取所有用户信息*/
    QUE_ALLUSER,
    /*根据姓名获取用户信息*/
    QUE_USER_BY_NAME

}

4.自定义注解写好了,可是光注解没用,怎么去对缓存进行实现呢,笔者选择在serviceImpl实现类进行缓存操作,所以采用AOP切面拦截serviceImpl进行缓存操作的封装,那么就新建一个用于对impl实现Redis操作的切面类(如果没有AOPjar包请先引入)


/**
 * @Description:Redis切面
 * @Author: lifay
 * @datetime:2019/5/28 10:54
 *
 */
@Aspect
@Component
public class RedisGeneralAspect {

    private final Logger logger = LoggerFactory.getLogger(*.*.*.*.RedisGeneralAspect.class);//自己修改serviceImpl包路径

    @Autowired
    private RedisUtil redisUtil;

    /**
     * 定义切入点,使用了 @redisServicePoint 的方法
     */
    @Pointcut("@annotation(RedisGeneralAnnotation)")
    public void redisServicePoint(){

    }
    @Around("redisServicePoint()")
    public Object redisPoint(ProceedingJoinPoint pdj){
        try {
            Class classTarget = pdj.getTarget().getClass();
            Class[] pts = ((MethodSignature)pdj.getSignature()).getParameterTypes();
            Method objMethod = classTarget.getDeclaredMethod(pdj.getSignature().getName(),pts);
            Class returnType = objMethod.getReturnType();
            RedisGeneralAnnotation redisGeneralAnnotation = pdj.getTarget().getClass().getDeclaredMethod(pdj.getSignature().getName(),pts).getAnnotation(RedisGeneralAnnotation.class);
            if(redisGeneralAnnotation != null && redisGeneralAnnotation.read()){
               //先组装完整KEY 缓存注解的前缀key + 传参串
                StringBuilder sb = new StringBuilder();
                String anno_key = redisGeneralAnnotation.key().toString();
                String key = "";

                sb.append(anno_key);
                sb.append("-");
                if (pdj.getArgs() != null && pdj.getArgs().length > 0){
                    for(int i =0; i< pdj.getArgs().length;i++){
                        String arg_str = pdj.getArgs()[i].toString();
                        sb.append(arg_str.replace(",","^").toString());
                    }
                }
                key = sb.toString();
                //进入缓存判断                Object obj = null;
                if(!redisUtil.hasKey(key)){
                    // Redis 中不存在,则从数据库中查找,并保存到 Redis
                    logger.info("<====== Redis 中不存在该记录,从数据库查找 ======>");
                    obj = pdj.proceed();
                    if(obj != null) {
                        //查询有数据存入缓存
                        logger.info("-----存入redis-------");
                        if (redisGeneralAnnotation.type().equals(CacheType.LIST)) {
                            redisUtil.lSet(key,obj,redisGeneralAnnotation.expired());
                        } else if (redisGeneralAnnotation.type().equals(CacheType.ENTITY)) {
                            redisUtil.set(key,JSON.toJSONString(obj),redisGeneralAnnotation.expired());
                        } else if (redisGeneralAnnotation.type().equals(CacheType.MAP)) {
                            redisUtil.hmset(key, (Map) obj,redisGeneralAnnotation.expired());
                        } else {
                            redisUtil.set(key,obj,redisGeneralAnnotation.expired());
                        }
                    }
                }else {
                    //从Redis中获取
                    logger.info("-----redis中获取-------");
                    //查询有数据存入缓存
                    if (redisGeneralAnnotation.type().equals(CacheType.LIST)) {
                        obj = redisUtil.lGet(key,0,-1);
                        return ((ArrayList) obj).get(0);
                    } else if (redisGeneralAnnotation.type().equals(CacheType.ENTITY)) {
                        obj = JSON.parseObject((String)redisUtil.get(key),returnType);
                    } else if (redisGeneralAnnotation.type().equals(CacheType.MAP)) {
                        obj = redisUtil.hmget(key);
                    } else {
                        obj = redisUtil.get(key);
                    }
                }
                return obj;
            }else{
                //方法没加缓存注解直接返回原查询方法
                return pdj.proceed();
            }

        } catch (Throwable e){
            logger.error(e.getMessage());
        }
        return null;
    }
}

5.最后就是在impl实现类中的需要使用注解了,这个注解的原理是不管该方法的具体实现,只关注它的返回(如果没存入redis,执行原方法从DB获取到数据,再放入redis)和帮助它提前返回(从redis中直接获取数据返回)

    @Override
    @RedisGeneralAnnotation(type = CacheType.LIST,key = CacheKeys.QUE_ALLUSER,expired = 2)
    public List getAllUser() {
        List userList= userMapper.getAllUser();
        return userList;
    }

你可能感兴趣的:(java springboot采用自定义注解形式封装Redis缓存)