前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >@Cacheable中key的SPEL表达式实现

@Cacheable中key的SPEL表达式实现

原创
作者头像
程序员小义
发布2024-06-26 00:29:27
1150
发布2024-06-26 00:29:27
举报
文章被收录于专栏:小义思小义思

​大家好,我是小义。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值。

代码语言:javascript
复制
@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表达式了。

代码语言:javascript
复制
@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注解

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档