Spring boot 自定义Redis缓存注解实现对方法返回结果缓存指定时间

自定义注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.concurrent.TimeUnit;

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

    /**
     * 分组名称
     * @return
     */
    String group();

    /**
     * 键名spel表达式
     * 实际键名为 group值 + ':' + key表达式值
     * @return
     */
    String key() default "";

    /**
     *  缓存条件spel表达式
     *  满足条件时缓存,参数为方法入参,参数名默认为方法参数名,可以用@Param 来重命名
     *  unless表达式不为空时,当前表达为true且unless表达式不为true时才会缓存
     * @return
     */
    String condition() default "";

    /**
     * 不缓存条件spel表达式
     * 满足条件是不进行缓存,参数为方法返回结果,参数名为result
     * 当前表达为不为空时,当前表达为false且condition表达式为true时才会缓存
     * @return
     */
    String unless() default ""; // 满足条件不缓存

    /**
     * 缓存时间
     * @return
     */
    long time() default 30L;

    /**
     * 缓存时间单位
     * @return
     */
    TimeUnit unit() default TimeUnit.MINUTES;
}

AOP实现

import lombok.extern.java.Log;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.annotations.Param;
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.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

@Aspect
@Component
@Log
public class RedisAop {
    private SpelExpressionParser parserSpel = new SpelExpressionParser(); // 表达式解析器

    @Autowired
    private RedisTemplate redisTemplate;

    @Around(value = "@annotation(redisCache)")
    public Object cache(ProceedingJoinPoint joinPoint, RedisCache redisCache) throws Throwable {
        StringBuffer keyName = new StringBuffer(redisCache.group()); // 缓存key名称
        Boolean isCache = true; // 是否缓存 默认缓存
        // 判断是否存在 key 或者 condition 表达式
        if (!StringUtils.isEmpty(redisCache.key()) || !StringUtils.isEmpty(redisCache.condition())){
            StandardEvaluationContext context = new StandardEvaluationContext(); // 上下文对象
            MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
            Object[] args = joinPoint.getArgs(); // 获取传入参数
            String[] argNames = methodSignature.getParameterNames(); // 获取参数名称
            // 获取方法
            Method method = joinPoint.getTarget().getClass().getDeclaredMethod(methodSignature.getName(), methodSignature.getParameterTypes());
            // 获取方法参数上的注解
            Annotation[][] annotations = method.getParameterAnnotations();
            // 便利参数将参数和参数名添加到上下文中
            for (int i = 0; i < args.length; i++){
                // 获取参数上的注解
                Annotation[] annotationArr = annotations[i];
                String name = argNames[i]; // 参数名称
                for (Annotation annotation : annotationArr){ // 便利注解
                    if (annotation instanceof Param) { // 存在Param参数
                        Param param = (Param) annotation;
                        name = param.value(); // 将参数名称设为Param的value
                    }
                }
                context.setVariable(name, args[i]); // 添加到上下文
            }
            // 判断是否存在key的变动时
            if (!StringUtils.isEmpty(redisCache.key())){
                Expression expression = this.parserSpel.parseExpression(redisCache.key());  // 解析表达式
                String key = expression.getValue(context, String.class); // 获取 key
                keyName.append(":").append(key); // 缓存key后
            }
            // 判断是否存在condition的表达式
            if (!StringUtils.isEmpty(redisCache.condition())) {
                Expression expression = this.parserSpel.parseExpression(redisCache.condition());  // 解析表达式
                isCache = expression.getValue(context, Boolean.class); // 获取表达式结果
            }
        }
        // 尝试从redis中获取
        Object obj = this.redisTemplate.opsForValue().get(keyName.toString());
        // 对象存在则直接返回
        if (obj != null) {
            return obj;
        }
        // 不存在执行方法
        obj = joinPoint.proceed();
        // 判断是否需要缓存
        if (!isCache) {
            return obj;
        }
        // 判断是否存在unless的表达式
        if (!StringUtils.isEmpty(redisCache.unless())){
            Expression expression = this.parserSpel.parseExpression(redisCache.unless());  // 解析表达式
            StandardEvaluationContext context = new StandardEvaluationContext(); // 上下文对象
            context.setVariable("result", obj);
            // 表达式结果为true时直接返回
            if (expression.getValue(context, Boolean.class)) {
                return obj;
            }
        }
        // 将结果缓存到redis中
        this.redisTemplate.opsForValue().set(keyName.toString(), obj, redisCache.time(), redisCache.unit());
        return obj; // 返回结果
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值