经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Spring » 查看文章
Spring 缓存注解这样用,太香了!
来源:cnblogs  作者:waynaqua  时间:2023/11/10 10:07:58  对本文有异议

作者最近在开发公司项目时使用到 Redis 缓存,并在翻看前人代码时,看到了一种关于 @Cacheable 注解的自定义缓存有效期的解决方案,感觉比较实用,因此作者自己拓展完善了一番后分享给各位。

Spring 缓存常规配置

Spring Cache 框架给我们提供了 @Cacheable 注解用于缓存方法返回内容。但是 @Cacheable 注解不能定义缓存有效期。这样的话在一些需要自定义缓存有效期的场景就不太实用。

按照 Spring Cache 框架给我们提供的 RedisCacheManager 实现,只能在全局设置缓存有效期。这里给大家看一个常规的 CacheConfig 缓存配置类,代码如下,

  1. @EnableCaching
  2. @Configuration
  3. public class CacheConfig extends CachingConfigurerSupport {
  4. ...
  5. private RedisSerializer<String> keySerializer() {
  6. return new StringRedisSerializer();
  7. }
  8. private RedisSerializer<Object> valueSerializer() {
  9. return new GenericFastJsonRedisSerializer();
  10. }
  11. public static final String CACHE_PREFIX = "crowd:";
  12. @Bean
  13. public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
  14. // 配置序列化(解决乱码的问题)
  15. RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
  16. //设置key为String
  17. .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer()))
  18. //设置value为自动转Json的Object
  19. .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer()))
  20. .computePrefixWith(name -> CACHE_PREFIX + name + ":")
  21. .entryTtl(Duration.ofSeconds(600));
  22. RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(Objects.requireNonNull(redisConnectionFactory));
  23. return new RedisCacheManager(redisCacheWriter, config);
  24. }
  25. }

这里面简单对 RedisCacheConfiguration 缓存配置做一下说明:

  1. serializeKeysWith():设置 Redis 的 key 的序列化规则。
  2. erializeValuesWith():设置 Redis 的 value 的序列化规则。
  3. computePrefixWith():计算 Redis 的 key 前缀。
  4. entryTtl():全局设置 @Cacheable 注解缓存的有效期。

那么使用如上配置生成的 Redis 缓存 key 名称是什么样得嘞?这里用开源项目 crowd-adminConfigServiceImpl 类下 getValueByKey(String key) 方法举例,

  1. @Cacheable(value = "configCache", key = "#root.methodName + '_' + #root.args[0]")
  2. @Override
  3. public String getValueByKey(String key) {
  4. QueryWrapper<Config> wrapper = new QueryWrapper<>();
  5. wrapper.eq("configKey", key);
  6. Config config = getOne(wrapper);
  7. if (config == null) {
  8. return null;
  9. }
  10. return config.getConfigValue();
  11. }

执行此方法后,Redis 中缓存 key 名称如下,

crowd:configCache:getValueByKey_sys.name

image

ttl 过期时间是 287,跟我们全局设置的 300 秒基本是一致的。此时假如我们想把 getValueByKey 方法的缓存有效期单独设置为 600 秒,那我们该如何操作嘞?

@Cacheable 注解默认是没有提供有关缓存有效期设置的。想要单独修改 getValueByKey 方法的缓存有效期只能修改全局的缓存有效期。那么有没有别的方法能够为 getValueByKey 方法单独设置缓存有效期嘞?当然是有的,大家请往下看。

自定义 MyRedisCacheManager 缓存

其实我们可以通过自定义 MyRedisCacheManager 类继承 Spring Cache 提供的 RedisCacheManager 类后,重写 createRedisCache(String name, RedisCacheConfiguration cacheConfig) 方法来完成自定义缓存有效期的功能,代码如下,

  1. public class MyRedisCacheManager extends RedisCacheManager {
  2. public MyRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) {
  3. super(cacheWriter, defaultCacheConfiguration);
  4. }
  5. @Override
  6. protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) {
  7. String[] array = StringUtils.split(name, "#");
  8. name = array[0];
  9. // 解析 @Cacheable 注解的 value 属性用以单独设置有效期
  10. if (array.length > 1) {
  11. long ttl = Long.parseLong(array[1]);
  12. cacheConfig = cacheConfig.entryTtl(Duration.ofSeconds(ttl));
  13. }
  14. return super.createRedisCache(name, cacheConfig);
  15. }
  16. }

MyRedisCacheManager 类逻辑如下,

  1. 继承 Spring Cache 提供的 RedisCacheManager 类。
  2. 重写 createRedisCache(String name, RedisCacheConfiguration cacheConfig) 方法。
  3. 解析 name 参数,根据 # 字符串进行分割,获取缓存 key 名称以及缓存有效期。
  4. 重新设置缓存 key 名称以及缓存有效期。
  5. 调用父类的 createRedisCache(name, cacheConfig) 方法来完成缓存写入。

接着我们修改下 CacheConfig 类的 cacheManager 方法用以使用 MyRedisCacheManager 类。代码如下,

  1. @Bean
  2. public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
  3. return new MyRedisCacheManager(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory), defaultCacheConfig());
  4. }
  5. private RedisCacheConfiguration defaultCacheConfig() {
  6. return RedisCacheConfiguration.defaultCacheConfig()
  7. .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer()))
  8. .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer()))
  9. .computePrefixWith(name -> CACHE_PREFIX + name + ":")
  10. .entryTtl(Duration.ofSeconds(600));
  11. }

最后在使用 @Cacheable 注解时,在原有 value 属性的 configCache 值后添加 #600,单独标识缓存有效期。代码如下,

  1. @Cacheable(value = "configCache#600", key = "#root.methodName + '_' + #root.args[0]")
  2. @Override
  3. public String getValueByKey(String key) {
  4. ...
  5. }

看下 getValueByKey 方法生成的 Redis 缓存 key 有效期是多久。如下,

image

OK,看到是 590 秒有效期后,我们就大功告成了。到这里我们就完成了对 @Cacheable 注解的自定义缓存有效期功能开发。

关注公众号【waynblog】每周分享技术干货、开源项目、实战经验、国外优质文章翻译等,您的关注将是我的更新动力!

原文链接:https://www.cnblogs.com/waynaqua/p/17822170.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号