Spring-cache + redis 自定义注解

需求:
API 端需要调用我这儿的一个接口,接口的数据是Mysql 全表的数据(涉及很多张表的数据拼接), 于是引入了Spring -cache 和 redis 缓存,Service 层的代码如下:

@Override
    @Cacheable(value = "cache:apiPolicy")
    public List<PolicyMain> apiList(Map<String, Object> map) {
        List<PolicyBaseCommonBO> policyBaseCommonBOList = policyBaseCommonService.list(map);
        return setDate(policyBaseCommonBOList);
    }

这个map 里面是查询的条件,也就导致了无法按记录的id去缓存, 每当mysql 的数据发生更改时,于是这里需要自己定义@CachePut 和 @CacheAdd。

思路: 通过AOP 获取注解,拿到Cache ,然后转pojo,处理对应的cache 。

1.自定义注解

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyCacheAdd {
    @AliasFor("cacheNames")
    String[] value() default {};

    @AliasFor("value")
    String[] cacheNames() default {};

    String key() default "";

    String keyGenerator() default "";

    String cacheManager() default "";

    String cacheResolver() default "";

    String condition() default "";

    String unless() default "";

    boolean sync() default false;
}

2.使用

@Override
    @Transactional
    @MyCacheAdd(value = "cache:apiPolicy", key = "#policyMain")
    public boolean add(PolicyMain policyMain) {
        xxxx
    }

这里最重要的就是解析Key 的步骤了

3.SPEL 表达式解析key

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


    /**
     * SpEL表达式缓存Key生成器.
     * 注解中传入key参数,则使用此生成器生成缓存.
     *
     * @param spELString
     * @param joinPoint
     * @return
     */
    Object generateKeyBySpEL(String spELString, ProceedingJoinPoint joinPoint) {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        String[] paramNames = nameDiscoverer.getParameterNames(methodSignature.getMethod());
        Expression expression = parser.parseExpression(spELString);
        EvaluationContext context = new StandardEvaluationContext();
        Object[] args = joinPoint.getArgs();
        for (int i = 0; i < args.length; i++) {
            context.setVariable(paramNames[i], args[i]);
        }
        return expression.getValue(context);
    }
}

4.AOP 逻辑

@Aspect
@Component
public class MyCacheAddAspect {
    private static final Logger logger = LoggerFactory.getLogger("MyCacheAddAspect");

    @Resource(name = "cacheManager")
    private CacheManager cacheManager;

    /**
     * 定义切点
     * 1、通过扫包切入
     * 2、带有指定注解切入
     */
    @Pointcut("@annotation(com.annotation.MyCacheAdd)")
    public void checkPointcut() {
    }

    @ResponseBody
    @Around(value = "checkPointcut()")
    public Object aroundNotice(ProceedingJoinPoint pjp) throws Throwable {
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
        HttpServletRequest request = sra.getRequest();
        String ip = request.getLocalAddr();
        String requestURI = request.getRequestURI();
        logger.info("MyCacheAddAspect 拦截到了 ip:{} , 方法:{}...", ip, requestURI);
        Signature signature = pjp.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        //获取目标方法
        Method targetMethod = methodSignature.getMethod();
        if (targetMethod.isAnnotationPresent(MyCacheAdd.class)) {
            //获取目标方法的@MyCacheDelete注解
            MyCacheAdd myCacheAdd = targetMethod.getAnnotation(MyCacheAdd.class);
            String key = myCacheAdd.key();
            String[] valueArr = myCacheAdd.value();
            //使用注解中的key, 支持SpEL表达式
            GenerateCacheKey generate = new GenerateCacheKey();
            PolicyMain newCache = (PolicyMain) generate.generateKeyBySpEL(key, pjp);
            //新增缓存
            for (String value : valueArr) {
                Cache cache = cacheManager.getCache(value);
                /*  不设置key 默认 {} */
                Cache.ValueWrapper list = cache.get("{}");
                List policyMainList = new ArrayList<>();
                if (list != null) {
                    policyMainList = (List) list.get();
                }
                policyMainList.add(newCache);
                cache.put("{}", policyMainList);
                logger.info("Redis : value:{} ,新增的缓存数据为:{}", value, policyMainList);

            }
        }
        return pjp.proceed();
    }
}

你可能感兴趣的:(javaweb知识)