天天看点

手动实现一个缓存抽象手写一个 redis 缓存抽象

手写一个 redis 缓存抽象

下面是实现 SPEL表达式的代码, spring-cache 的 缓存抽象没法自定义时间,所以自己实现了一下普通的缓存注解

/**
     * 用于SpEL表达式解析.
     */
    private static SpelExpressionParser parser = new SpelExpressionParser();
    /**
     * 用于获取方法参数定义名字.
     */
    private static DefaultParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer();

    public static String generateKeyBySpEL(String spELString, ProceedingJoinPoint joinPoint) {
        // 通过joinPoint获取被注解方法
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        // 使用spring的DefaultParameterNameDiscoverer获取方法形参名数组
        String[] paramNames = nameDiscoverer.getParameterNames(method);
        // 解析过后的Spring表达式对象
        Expression expression = parser.parseExpression(spELString);
        // spring的表达式上下文对象
        EvaluationContext context = new StandardEvaluationContext();
        // 通过joinPoint获取被注解方法的形参
        Object[] args = joinPoint.getArgs();
        // 给上下文赋值
        for(int i = 0 ; i < args.length ; i++) {
            context.setVariable(paramNames[i], args[i]);
        }
        // 表达式从上下文中计算出实际参数值
        /*如:
            @annotation(key="#student.name")
             method(Student student)
             那么就可以解析出方法形参的某属性值,return “xiaoming”;
          */
        return expression.getValue(context).toString();
    }

           

WebUtil 类的静态方法

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface CacheResult {
    Unit unit() default Unit.SECOND;
    int duration() default 3*60;//缓存3分钟
    String spel();



}
           

自定义缓存注解

public enum Unit {
    /**
     * second
     */
    SECOND,
    /**
     * 小时
     */
    HOUR,
    /**
     * 分钟
     */
    MINUTE,
    /**
     * 一天
     */
    Day,
}
           
@Aspect
@Component
// @Order(-20)
@Slf4j
public class RedisCacheAspect {
    @Pointcut("@annotation(CacheResult)")
    public void aop() {
        // log.info("args-> {}", Arrays.toString(pjp.getArgs()));
    }
    @Pointcut("@annotation(UpdateCache)")
    public void aopForUpdate() {
        // log.info("args-> {}", Arrays.toString(pjp.getArgs()));
    }

    @Around("aop()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        CacheResult cacheResult = ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotation(CacheResult.class);
        String key = WebUtil.generateKeyBySpEL(cacheResult.spel(), joinPoint);
        log.info("cache Key {}",key);
        Object cache = redisTemplate.opsForValue().get(key);
        if (cache != null) {
            //如果缓存有,就返回
            return cache;
        }
        //没有缓存,运行,然后缓存入 redis中
        Object obj = joinPoint.proceed(joinPoint.getArgs());
        long ttl = cacheResult.duration();
        Duration duration = null;
        switch (cacheResult.unit()) {
            case SECOND: {
                duration = Duration.ofSeconds(ttl);
                break;
            }

            case MINUTE: {
                duration = Duration.ofMinutes(ttl);
                break;
            }
            case HOUR: {
                duration = Duration.ofHours(ttl);
                break;
            }
            default: {
                //一天时间
                duration = Duration.ofDays(ttl);
                break;
            }
        }
        redisTemplate.opsForValue().set(key, obj, duration);
        return obj;
    }

    @Around("aopForUpdate()")
    public Object delCache(ProceedingJoinPoint joinPoint) throws Throwable {
        UpdateCache updateCache = ((MethodSignature)joinPoint.getSignature()).getMethod().getAnnotation(UpdateCache.class);
        String key = WebUtil.generateKeyBySpEL(updateCache.spel(),joinPoint);
        expireCache(updateCache,key);
        return joinPoint.proceed(joinPoint.getArgs());
    }

    @Async
    public void expireCache(UpdateCache updateCache, String key) {




        long ttl = updateCache.duration();
        Duration duration = null;
        switch (updateCache.unit()) {
            case SECOND: {
                duration = Duration.ofSeconds(ttl);
                break;
            }

            case MINUTE: {
                duration = Duration.ofMinutes(ttl);
                break;
            }
            case HOUR: {
                duration = Duration.ofHours(ttl);
                break;
            }
            default: {
                //一天时间
                duration = Duration.ofDays(ttl);
                break;
            }
        }
        redisTemplate.expire(key,duration);
    }





    @Resource
    private RedisTemplate<String, Object> redisTemplate;
}