使用自定义注解+AOP实现存放HASH类型的Redis缓存

使用自定义注解+AOP实现存放HASH类型的Redis缓存

1.自定义的Redis方法

	/**
     * @description 获取返回值
     * @param key - 键 不能为null
     * @param hashKey - 项 不能为null
     * @return Object  -
     * @author XinLau
     * @since 2020/3/24 12:40
     * @creed The only constant is change ! ! !
     */
    public Object hget(String key, String hashKey) {
        return redisTemplate.opsForHash().get(key, hashKey);
    }

    /**
     * @description 获取指定类型的返回值
     * @param key - 键 不能为null
     * @param hashKey - 项 不能为null
     * @param clazz - 返回值类型
     * @return <T> -
     * @author XinLau
     * @since 2020/3/24 15:44
     * @creed The only constant is change ! ! !
     */
    public <T> T hget(String key, String hashKey, Class<T> clazz) {
        Object hget = hget(key, hashKey);
        if (ConvertUtils.isEmpty(hget)){
            return null;
        }
        if (clazz.isInstance(hget)){
            return clazz.cast(hget);
        }
        return null;
    }

2.自定义注解

import java.lang.annotation.*;

/**
 * <p>
 * HashCache<br>
 *  以HASH形式存储的缓存注解
 * </p>
 *
 * @author XinLau
 * @version 1.0
 * @since 2020年03月24日 14:15
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface HashCache {
    /**
     * HASH标识
     * @return
     */
    String hashIdentification();
    /**
     * HASH内存放的Key
     * @return
     */
    String hashKey();
    /**
     * HASH过期时间
     * 0 - 立即过期
     * -1 - 不会被使用
     * -2 - 永不过期
     * @return
     */
    int expireTime() default -2;
}
import java.lang.annotation.*;

/**
 * <p>
 * HashCacheEvict<br>
 *  清除以HASH形式存储的缓存注解
 * </p>
 *
 * @author XinLau
 * @version 1.0
 * @since 2020年03月25日 09:15
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface HashCacheEvict {
    /**
     * HASH标识
     * @return
     */
    String hashIdentification();
    /**
     * HASH内存放的Key
     * @return
     */
    String hashKey();
}

import java.lang.annotation.*;

/**
 * <p>
 * HashCachePut<br>
 *  以HASH形式存储的缓存注解
 * </p>
 *
 * @author XinLau
 * @version 1.0
 * @since 2020年03月24日 14:15
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface HashCachePut {
    /**
     * HASH标识
     * @return
     */
    String hashIdentification();
    /**
     * HASH内存放的Key
     * @return
     */
    String hashKey();
    /**
     * HASH过期时间
     * 0 - 立即过期
     * -1 - 不会被使用
     * -2 - 永不过期
     * @return
     */
    int expireTime() default -2;
}

3.自定义Aspect


import com.zzdz.platform.base.annotation.HashCache;
import com.zzdz.platform.base.annotation.HashCacheEvict;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.lang.reflect.Method;

/**
 * <p>
 * HashCacheAspect<br>
 * 以HASH形式存储的缓存注解 切面处理类
 * </p>
 *
 * @author XinLau
 * @version 1.0
 * @since 2020年03月24日 14:37
 */
@Aspect
@Component
public class HashCacheAspect {
    /**
     * Redis 工具类
     */
    @Resource
    private com.zzdz.platform.base.util.RedisUtil redisUtil;

    /**
     * @description 获取被拦截方法对象
     *  MethodSignature.getMethod() 获取的是顶层接口或者父类的方法对象
     *  而缓存的注解在实现类的方法上
     *  所以应该使用反射获取当前对象的方法对象
     * @param proceedingJoinPoint - ProceedingJoinPoint
     * @return Method -
     * @author XinLau
     * @since 2020/3/24 14:58
     * @creed The only constant is change ! ! !
     */
    private Method getMethod(ProceedingJoinPoint proceedingJoinPoint) {
//        获取参数的类型
        Object[] args = proceedingJoinPoint.getArgs();
        Class[] argTypes = new Class[proceedingJoinPoint.getArgs().length];
        for (int i = 0; i < args.length; i++) {
            argTypes[i] = args[i].getClass();
        }
        Method method = null;
        try {
            method = proceedingJoinPoint.getTarget().getClass().getMethod(proceedingJoinPoint.getSignature().getName(), argTypes);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }
        return method;
    }

    /**
     * @description 获取缓存的hashKey
     * @param hashKey - hashKey
     * @param method -
     * @param args -方法参数
     * @return String -
     * @author XinLau
     * @since 2020/3/24 15:48
     * @creed The only constant is change ! ! !
     */
    private String parseKey(String hashKey, Method method, Object[] args) {
//        1.获取被拦截方法参数名列表(使用Spring支持类库)
        LocalVariableTableParameterNameDiscoverer localVariableTableParameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
        String[] paraNameArr = localVariableTableParameterNameDiscoverer.getParameterNames(method);
//        2.使用SPEL进行key的解析
        ExpressionParser parser = new SpelExpressionParser();
//        3.SPEL上下文
        StandardEvaluationContext context = new StandardEvaluationContext();
//        4.把方法参数放入SPEL上下文中
        for (int i = 0; i < paraNameArr.length; i++) {
            context.setVariable(paraNameArr[i], args[i]);
        }
        return parser.parseExpression(hashKey).getValue(context, String.class);
    }

    /**
     * @description 缓存逻辑
     * @param proceedingJoinPoint - ProceedingJoinPoint
     * @return Object - 返回值
     * @author XinLau
     * @since 2020/3/24 15:35
     * @creed The only constant is change ! ! !
     */
    @Around("@annotation(com.zzdz.platform.base.annotation.HashCache)")
    public Object hashCache(ProceedingJoinPoint proceedingJoinPoint) {
//        1.获取被拦截方法对象
        Method method = getMethod(proceedingJoinPoint);
//        2.获取 Annotation
        HashCache hashCache = method.getAnnotation(HashCache.class);
//        3.获取HASH的HASH标识
        String hashIdentification = hashCache.hashIdentification();
//        存放的Key
        String hashKey = parseKey(hashCache.hashKey(), method, proceedingJoinPoint.getArgs());
//        过期时间
        int expireTime = hashCache.expireTime();
//        4.获取方法的返回类型,让缓存可以返回正确的类型
        Class returnType = ((MethodSignature) proceedingJoinPoint.getSignature()).getReturnType();
//        5.使用 Redis 的 HASH 进行存取,易于管理
        Object result = redisUtil.hget(hashIdentification, hashKey, returnType);
        if (result == null){
//            缓存为空
            try {
//                6.获取使用注解的方法的返回值
                result = proceedingJoinPoint.proceed();
                Assert.notNull(hashKey, "HASH内存放的Key");
//                7.缓存存放
                if (expireTime >= 0){
//                    带过期时间(包括0 - 立即过期)
                    redisUtil.hset(hashIdentification, hashKey, result, expireTime);
                }else {
//                    不带过期时间
                    redisUtil.hset(hashIdentification, hashKey, result);
                }
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
        }
        return result;
    }

    /**
     * @description 缓存清除
     * @param proceedingJoinPoint - ProceedingJoinPoint
     * @return Object - 返回值
     * @author XinLau
     * @since 2020/3/25 09:35
     * @creed The only constant is change ! ! !
     */
    @Around("@annotation(com.zzdz.platform.base.annotation.HashCacheEvict)")
    public void hashCacheEvict(ProceedingJoinPoint proceedingJoinPoint) {
//        1.获取被拦截方法对象
        Method method = getMethod(proceedingJoinPoint);
//        2.获取 Annotation
        HashCacheEvict hashCacheEvict = method.getAnnotation(HashCacheEvict.class);
//        3.获取HASH的HASH标识
        String hashIdentification = hashCacheEvict.hashIdentification();
//        过期时间
        String hashKey = hashCacheEvict.hashKey();
//        4.获取方法的返回类型,让缓存可以返回正确的类型
        Class returnType = ((MethodSignature) proceedingJoinPoint.getSignature()).getReturnType();
//        5.使用 Redis 的 HASH 进行存取,易于管理
        Object result = redisUtil.hget(hashIdentification, hashKey);
        if (result == null){
            return;
        }
        redisUtil.del(hashIdentification, hashKey);
    }

    /**
     * @description 缓存修改
     * @param proceedingJoinPoint - ProceedingJoinPoint
     * @return Object - 返回值
     * @author XinLau
     * @since 2020/3/24 15:35
     * @creed The only constant is change ! ! !
     */
    @Around("@annotation(com.zzdz.platform.base.annotation.HashCachePut)")
    public Object hashCachePut(ProceedingJoinPoint proceedingJoinPoint) {
//        1.获取被拦截方法对象
        Method method = getMethod(proceedingJoinPoint);
//        2.获取 Annotation
        HashCache hashCache = method.getAnnotation(HashCache.class);
//        3.获取HASH的HASH标识
        String hashIdentification = hashCache.hashIdentification();
//        存放的Key
        String hashKey = parseKey(hashCache.hashKey(), method, proceedingJoinPoint.getArgs());
//        过期时间
        int expireTime = hashCache.expireTime();
        Object result = null;
        try {
//            4.获取使用注解的方法的返回值
            result = proceedingJoinPoint.proceed();
            Assert.notNull(hashKey, "HASH内存放的Key");
//            5.缓存存放
            if (expireTime >= 0){
//                    带过期时间(包括0 - 立即过期)
                redisUtil.hset(hashIdentification, hashKey, result, expireTime);
            }else {
//                    不带过期时间
                redisUtil.hset(hashIdentification, hashKey, result);
            }
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return result;
    }

}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叁金Coder

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值