@Cacheable中key的SPEL表达式实现

大家好,我是小义。Spring中的@Cacheable注解相信大家都有用过,其key属性是支持SPEL表达式的,像key="#root.args[0]"取到的就是方法第一个入参,这极大地简化了缓存key的配置。

上面提到的SPEL(Spring Expression language),是Spring3.0开始引入的Spring表达式语言,可以通过程序在运行期间执行的表达式将值装配到对象的属性或构造函数中。

小义之前有实现过带过期时间的自定义缓存注解@CacheableTtl,但是在实现key的动态设值功能是通过在方法入参里添加另外一个注解@CacheParam实现的。具体的可以看看之前的文章。虽然@CachePram也支持了SPEL表达式,但在实现过程和使用上还是没有像@Cacheable的可以那样简单快捷。

其实直接用SPEL就够了,只怪自己学艺不精,之前绕了一大圈,下面来看看具体代码实现。

在拦截器中获取拦截方法入参中的参数名称与参数值映射,然后通过解析spel表达式的key,获取真正存入缓存中的key值。

@Component
@Aspect
public class CacheableAspect {

@Pointcut("@annotation(com.invent.momo.annotation.CacheableTtl)")
public void pointcut() {
}

@Around(value = "pointcut()")
public Object around(final ProceedingJoinPoint pjp) throws Throwable {
    Object[] args = pjp.getArgs();//方法入参对象数组
    Method method = MethodSignature.class.cast(pjp.getSignature()).getMethod();//方法实体
    CacheableTtl cacheable = method.getAnnotation(CacheableTtl.class);//注解
    String[] parameterNames = new LocalVariableTableParameterNameDiscoverer().getParameterNames(method);//参数名称
    StandardEvaluationContext context = new StandardEvaluationContext();
    for (int i = 0; i < parameterNames.length; i++) {
        context.setVariable(parameterNames[i], args[i]);
    }
    //解析spel表达式的key,获取真正存入缓存中的key值
    String key = parseSpelKey(cacheable, context);
    //读取缓存
    Object value = getCache(cacheable, key);
    if (null == value) {
        value = pjp.proceed();//执行方法
        //设置缓存
        setCache(cacheable, key, value);
    }
    return value;
}

private String parseSpelKey(CacheableTtl cacheable, StandardEvaluationContext context) {
    String keySpel = cacheable.key();
    Expression expression = new SpelExpressionParser().parseExpression(keySpel);
    String key = expression.getValue(context, String.class);
    return key;
}

}
拦截器设置好后,在Controller层就可以像使用@Cacheable的key那样,给自定义注解的key灵活设置SPEL表达式了。

@RequestMapping(“/com”)
@RestController
public class ComController {

@CacheableTtl(key = "#demoUser.name + #demoUser.job", ttl = 5, ttlTimeUnit = TimeUnit.MINUTES)
@PostMapping("/summer")
public CustomVo summer(DemoUser demoUser) {
    CustomVo customVo = new CustomVo();
    customVo.setName(demoUser.getName() + demoUser.getJob());
    return customVo;
}

@CacheableTtl(key = "'spring::' + #demoUser.name", ttl = 5, ttlTimeUnit = TimeUnit.MINUTES)
@PostMapping("/spring")
public CustomVo spring(DemoUser demoUser) {
    CustomVo customVo = new CustomVo();
    customVo.setName("xx");
    return customVo;
}

@CacheableTtl(key = "#id + #name", ttl = 5, ttlTimeUnit = TimeUnit.MINUTES)
@PostMapping("/winter")
public CustomVo winter(@RequestParam("id") String id, @RequestParam("name") String name) {
    CustomVo customVo = new CustomVo();
    customVo.setAge("18");
    customVo.setName(name);
    return customVo;
}

}
上文提到的历史文章如下,感兴趣的同学可以读一读。欢迎关注小义公众号,一起学习新知识。

推荐阅读:

Spring Cache解析

实现Cacheable注解

  • 9
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值