仿spring cache实现注解存储缓存

24 篇文章 0 订阅

大致就是使用aop 及SpEL。本例基于jdk1.8,直接上代码。

@Target({ElementType.METHOD})
@Retention(value = RetentionPolicy.RUNTIME)
@Inherited
public @interface RedisCache {
    RedisKeyEnum redisKeyEnum();

    /**
     * SpEL 编写
     *
     * @return
     */
    String[] dynamicFields() default {};

    /**
     * 缓存的条件,可以为空,使用 SpEL 编写
     * 为空则默认执行缓存操作
     *
     * @return
     */
    String condition() default "";
}
@Getter
@AllArgsConstructor
public enum RedisKeyEnum {
    EVENT_MSG_LOG("msg_log:{0}", "事件消息日志", 60 * 60);
    private String key;
    private String desc;
    /**
     * 默认失效时间(秒)
     */
    private Integer failureTime;
    public String getCacheKey(String... param) {
        StringBuilder stringBuilder = new StringBuilder("event:");
        if (param == null || param.length == 0) {
            return stringBuilder.append(this.getKey()).toString();
        }
        stringBuilder.append(MessageFormat.format(this.getKey(), param)).toString();
        return stringBuilder.toString();
    }
}
@Aspect
@Component
@Slf4j
public class RedisAspect {
    @Autowired
    private JedisCluster jedisCluster;

    @Pointcut("execution(* com.xxx.event.service.impl..*.*(..))")
    public void cachePointcut() {
    }

    /**
     * put 缓存
     *
     * @param pj
     * @param putRedisCache
     * @throws Throwable
     */
    @AfterReturning(returning = "result", pointcut = "cachePointcut() && @annotation(putRedisCache)")
    public void doPut(JoinPoint pj, Object result, RedisCachePut putRedisCache) {
        if (putRedisCache.putCaches() == null || putRedisCache.putCaches().length == 0) {
            return;
        }
        if (result == null) {
            return;
        }
        StandardEvaluationContext standardEvaluationContext = null;
        ExpressionParser parser = null;
        for (RedisCache redisCache : putRedisCache.putCaches()) {
            if (!isEnableCacheAction(redisCache, pj, parser, standardEvaluationContext)) {
                continue;
            }
            String redisKey = buildRedisKey(redisCache,pj, parser, standardEvaluationContext);
            save2Redis(redisKey, redisCache, result);
        }
    }

    /**
     * 清理缓存
     *
     * @param pj
     * @param clearRedisCache
     */
    @After("cachePointcut() && @annotation(clearRedisCache)")
    public void doClear(JoinPoint pj, RedisCacheClear clearRedisCache) {
        if (clearRedisCache.clearCaches() == null || clearRedisCache.clearCaches().length == 0) {
            return;
        }
        StandardEvaluationContext standardEvaluationContext = null;
        ExpressionParser parser = null;
        for (RedisCache redisCache : clearRedisCache.clearCaches()) {
            if (!isEnableCacheAction(redisCache, pj, parser, standardEvaluationContext)) {
                continue;
            }
            String redisKey = buildRedisKey(redisCache,pj, parser, standardEvaluationContext);
            log.info("清理缓存key为:{}", redisKey);
            jedisCluster.del(redisKey);
        }
    }

    @Around("cachePointcut() && @annotation(redisCache)")
    public Object doCache(ProceedingJoinPoint pj, RedisCache redisCache) throws Throwable {
        StandardEvaluationContext standardEvaluationContext = null;
        ExpressionParser parser = null;
        if (!isEnableCacheAction(redisCache, pj, parser, standardEvaluationContext)) {
            return pj.proceed();
        }
        String redisKey = buildRedisKey(redisCache,pj, parser, standardEvaluationContext);
        String str = jedisCluster.get(redisKey);
        if (!StringUtils.isBlank(str)) {
            MethodSignature methodSignature = (MethodSignature) pj.getSignature();
            log.info("方法:{}命中缓存key:{}", methodSignature.getMethod(), redisKey);
            return JSON.parseObject(str, methodSignature.getMethod().getReturnType());
        }
        Object result = pj.proceed();
        return save2Redis(redisKey, redisCache, result);
    }

    private Object save2Redis(String redisKey, RedisCache redisCache, Object result) {
        if (result == null) {
            return result;
        }
        String str = JSON.toJSONString(result);
        if (redisCache.redisKeyEnum().getFailureTime() != null) {
            jedisCluster.setex(redisKey, redisCache.redisKeyEnum().getFailureTime(), str);
        } else {
            jedisCluster.set(redisKey, str);
        }
        return result;
    }

    /**
     * 构建缓存key
     *
     * @param redisCache
     * @param parser
     * @param standardEvaluationContext
     * @return
     */
    private String buildRedisKey(RedisCache redisCache,JoinPoint pj, ExpressionParser parser, StandardEvaluationContext standardEvaluationContext) {
        String[] dynamicFields = redisCache.dynamicFields();
        if (dynamicFields == null || dynamicFields.length == 0) {
            return redisCache.redisKeyEnum().getCacheKey();
        }
        if (parser == null) {
            parser = new SpelExpressionParser();
        }
        if (standardEvaluationContext == null) {
            standardEvaluationContext = initContextVariables(pj);
        }
        String[] replaceFieldVal = new String[dynamicFields.length];
        for (int i = 0; i < dynamicFields.length; i++) {
            replaceFieldVal[i] = parser.parseExpression(dynamicFields[i]).getValue(standardEvaluationContext, Object.class).toString();
        }
        return redisCache.redisKeyEnum().getCacheKey(replaceFieldVal);
    }

    private boolean isEnableCacheAction(RedisCache redisCache, JoinPoint pj, ExpressionParser parser, StandardEvaluationContext standardEvaluationContext) {
        if (StringUtils.isBlank(redisCache.condition())) {
            return Boolean.TRUE;
        }
        if (parser == null) {
            parser = new SpelExpressionParser();
        }
        if (standardEvaluationContext == null) {
            standardEvaluationContext = initContextVariables(pj);
        }

        return parser.parseExpression(redisCache.condition()).getValue(standardEvaluationContext, Boolean.class);
    }

    private StandardEvaluationContext initContextVariables(JoinPoint joinPoint) {
        StandardEvaluationContext standardEvaluationContext = new StandardEvaluationContext();
        Object[] args = joinPoint.getArgs();
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        String[] parametersName = methodSignature.getParameterNames();
        if (args == null || args.length <= 0) {
            return standardEvaluationContext;
        }
        for (int i = 0; i < args.length; i++) {
            standardEvaluationContext.setVariable(parametersName[i], args[i]);
        }
        return standardEvaluationContext;
    }
}

使用
@RedisCache(redisKeyEnum = RedisKeyEnum.EVENT_MSG_LOG, dynamicFields = {"#msgId"})
    public EventMsgLog selectByMsgId(String msgId) {
        log.info("查询消息日志记录");
        return eventMsgLogMapper.selectByMsgId(msgId);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值