前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >玩转Spring Cache --- 扩展缓存注解支持失效时间TTL【享学Spring】

玩转Spring Cache --- 扩展缓存注解支持失效时间TTL【享学Spring】

作者头像
YourBatman
发布2019-09-03 15:21:58
8.3K2
发布2019-09-03 15:21:58
举报
文章被收录于专栏:BAT的乌托邦BAT的乌托邦

前言

在上篇文章讲解整合分布式缓存Redis时埋下了一个伏笔:如何让我们的缓存注解支持自定义TTL失效时间呢?

这篇文章本可以不用写,因为其实基于RedisRedisCacheManager它本身天生就是能够针对不同的Cache配置不同的TTL的。但是我发现有的小伙伴觉得使用得还是不太方便,希望能在使用注解的时候直接控制失效时间,为了帮助解决小伙伴的这个困惑,这就是我书写本文的目的~

Spring Cache与失效时间TTL

首先此处我有必要再次强调一点:Spring Cache抽象本省是并不支持Expire失效时间的设定的,我粗暴的把它归为了Spring Cache抽象的一个设计上的bug,可参考文章:【小家Spring】玩转Spring Cache — @Cacheable/@CachePut/@CacheEvict注解的原理深度剖析和使用

若想在缓存注解上指定失效时间,必须具备如下两个基本条件:

  1. 缓存实现产品支持Expire失效时间(Ehcache、Redis等几乎所有第三方实现都支持)
  2. xxxCacheManager管理的xxxCache必须扩展了Expire的实现

因为缓存的k-v键值对具有自动失效的特性实在太重要和太实用了,所以虽然org.springframework.cache.Cache它没有实现Expire,但好在第三方产品对Spring缓存标准实现的时候,大都实现了这个重要的失效策略,比如典型例子:RedisCache

本文以最为常用的Redis缓存为例,介绍两种控制缓存失效时间的方式。

实现Cache失效时间的两种通用方式

接下来就以Redis Cache为例,介绍两种常用的、通用的管理缓存失效时间的方式。

方式一:使用源生的RedisCacheManager进行集中式控制

由于控制key的失效时间这一块非常的实用和重要,所以其实Spring Data Redis工程早就给与了支持(不管是1.x版本还是2.x版本)。因此话不多说,直接给个例子就非常清晰明了:

1、准备Cache配置:

使用示例:

运行单元测试

打印结果如下:

缓存生效。去Redis服务端查看对应的key情况:

眼睛尖的小伙伴可能发现了,只有最后一个key前面有caching前缀,其余两个木有,这是为何呢? 这是我故意留出来的一个小问题,留给小伙伴们自行思考~

由此可见,通过RedisCacheManager完成了对不同的Cache进行了失效时间的定制化配置,达到了我们的目的。

小细节

针对如上的配置,总结如下两点小细节使时需要注意:

  1. 即使禁用前缀disableKeyPrefix(),也是不会影响对应CacheName的TTL(因为TTL针对的是Cache,而不是key
  2. 每个CacheName都可以对应一个RedisCacheConfiguration(它里面有众多属性都可以个性化),若没配置的(比如动态生成的)都走默认配置

Spring提供的在RedisCacheManager来统一管理Cache的TTL,这种集中式的管理其实是我赞同的方式,若让他分散在各个缓存注解上,反而非常不利于后期的维护管理~~~因此这种方式我也是推荐的

方式二:自定义cacheNames方式

虽然我觉得方案一已经能够满足我们需求了,但是广大小伙伴还是觉得使用起来不太自由,毕竟大多数Cache都希望是通过在注解指定CacheNames让其自动生成就行(其实提前追备好有助于提升初次访问的性能)。但是为了便用性摆第一位的话,那就应广大小伙伴的要求,写出本例供以参考

其实最终我们期望的使用方式如下:

通过#分隔,后面部分表示此Cache的TTL(单位:秒)

为了实现这个效果,其实并不难,只需要对RedisCacheManager稍稍的改造一下即可达到目的:

使用我自定义的MyRedisCacheManager配置CacheConfig如下:

使用示例如下:

打印结果:

缓存生效。Redis Server里查到缓存结果如图(TTL都分别生效了):

说明:demoFsx没有指定TTL,所以走了默认值ttl=1天

小细节
  1. 同样的,禁用前缀并不影响它的TTL的生效与否
  2. 若在CacheManager已经配置了Cache对应的TTL配置,那就以CacheManager里配置的为准
  3. 多个方法里配置了同一个CacheNameTTL以第一个执行的生成Cache的方法配置的为准

总之一个原则:TTL是和Cache绑定的,且是在Cache在首次被初始化的时候就被指定好了

关于此方案,其实还可以扩展一下,比如可以扩展成可配置的如下:

方案提出来,实现此处我就不写了,因为还是比较容易实现的。

TTL能精确到key吗?

据我了解,这是很多小伙伴都想问的一个问题,但其实我一直不明白为何有非常多的小伙伴会有这种呼声呢?

很多小伙伴是希望把TTL写在key上,形如这样书写:

其实这么想的小伙伴,我觉得根本原因是不太能理解cacheNameRedis的key的关系导致的(本文以Redis为例~)

我此处不直接解答这个问题,但我对此额外抛出3个问题,相信答案就不攻自破了:

  1. 为何同一个Cache下管理的key你需要不同的TTL???(这种设计本身就不合理吧)
  2. 在不禁用前缀的情况下,cacheName默认都会反映到key上。因此即使你有这种特殊需求,你也可以通过定义特殊的CacheName来实现
  3. 若你真想控制到key这种细粒度,我只能说:实现成本太高了且会打破一定的封装性,后续扩展受限

综合来说,不管从场景上还是技术上,我都是极力不推荐这种行为的。

总结

本文主要介绍了让缓存注解支持TTL失效时间,提供的两种方式都可以用在生产环境中。合理的使用、控制失效时间,能让你的应用更加的高效,缓存利用得更合理。

另外关于Spring缓存其实还有一个重要知识点:**缓存即将过期时主动刷新缓存**:

因为缓存失效后,就会有一些请求会打到DB上,这段时间如果是高并发的话DB压力就很大(sync=true可以有一定的缓解作用),DB就很危险,容易造成雪崩。

因此我们是期望在缓存即将过期的某一时间点,后台主动去更新缓存以确保前端请求的缓存命中率。关于这部分的实现,只有在高并发系统下才有需求,有兴趣和有需要的小伙伴可往这方面考虑一把~

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019年07月10日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

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

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • Spring Cache与失效时间TTL
  • 实现Cache失效时间的两种通用方式
    • 方式一:使用源生的RedisCacheManager进行集中式控制
      • 方式二:自定义cacheNames方式
        • TTL能精确到key吗?
          • 总结
          相关产品与服务
          云数据库 Redis
          腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档