👉 这是一个或许对你有用的社群
🐱 一对一交流/面试小册/简历优化/求职解惑,欢迎加入芋道快速开发平台知识星球。下面是星球提供的部分资料:
👉这是一个或许对你有用的开源项目
国产 Star 破 10w+ 的开源项目,前端包括管理后台 + 微信小程序,后端支持单体和微服务架构。
功能涵盖 RBAC 权限、SaaS 多租户、数据权限、商城、支付、工作流、大屏报表、微信公众号等等功能:
  • Boot 地址:https://gitee.com/zhijiantianya/ruoyi-vue-pro
  • Cloud 地址:https://gitee.com/zhijiantianya/yudao-cloud
  • 视频教程:https://doc.iocoder.cn

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

Spring 缓存常规配置

Spring Cache 框架给我们提供了 @Cacheable 注解用于缓存方法返回内容。但是 @Cacheable 注解不能定义缓存有效期。这样的话在一些需要自定义缓存有效期的场景就不太实用。
按照 Spring Cache 框架给我们提供的 RedisCacheManager 实现,只能在全局设置缓存有效期。这里给大家看一个常规的 CacheConfig 缓存配置类,代码如下,
@EnableCaching
@Configuration
publicclassCacheConfigextendsCachingConfigurerSupport
{

    ...


private RedisSerializer<String> keySerializer()
{

returnnew
 StringRedisSerializer();

    }


private RedisSerializer<Object> valueSerializer()
{

returnnew
 GenericFastJsonRedisSerializer();

    }


publicstaticfinal
 String CACHE_PREFIX = 
"crowd:"
;


@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory)
{

// 配置序列化(解决乱码的问题)
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()

//设置key为String
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer()))

//设置value为自动转Json的Object
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer()))

                .computePrefixWith(name -> CACHE_PREFIX + name  + 
":"
)

                .entryTtl(Duration.ofSeconds(
600
));

        RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(Objects.requireNonNull(redisConnectionFactory));

returnnew
 RedisCacheManager(redisCacheWriter, config);

    }

}

这里面简单对 RedisCacheConfiguration 缓存配置做一下说明:
  1. serializeKeysWith():设置 Redis 的 key 的序列化规则。
  2. erializeValuesWith():设置 Redis 的 value 的序列化规则。
  3. computePrefixWith():计算 Redis 的 key 前缀。
  4. entryTtl():全局设置 @Cacheable 注解缓存的有效期。
那么使用如上配置生成的 Redis 缓存 key 名称是什么样得嘞?这里用开源项目 crowd-adminConfigServiceImpl 类下 getValueByKey(String key) 方法举例,
@Cacheable
(value = 
"configCache"
, key = 
"#root.methodName + '_' + #root.args[0]"
)

@Override
public String getValueByKey(String key)
{

    QueryWrapper<Config> wrapper = 
new
 QueryWrapper<>();

    wrapper.eq(
"configKey"
, key);

    Config config = getOne(wrapper);

if
 (config == 
null
) {

returnnull
;

    }

return
 config.getConfigValue();

}

执行此方法后,Redis 中缓存 key 名称如下,
crowd:configCache:getValueByKey_sys.name
TTL 过期时间是 287,跟我们全局设置的 300 秒基本是一致的。此时假如我们想把 getValueByKey 方法的缓存有效期单独设置为 600 秒,那我们该如何操作嘞?
@Cacheable 注解默认是没有提供有关缓存有效期设置的。想要单独修改 getValueByKey 方法的缓存有效期只能修改全局的缓存有效期。那么有没有别的方法能够为 getValueByKey 方法单独设置缓存有效期嘞?当然是有的,大家请往下看。
基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
  • 项目地址:https://github.com/YunaiV/ruoyi-vue-pro
  • 视频教程:https://doc.iocoder.cn/video/

自定义 MyRedisCacheManager 缓存

其实我们可以通过自定义 MyRedisCacheManager 类继承 Spring Cache 提供的 RedisCacheManager 类后,重写 createRedisCache(String name, RedisCacheConfiguration cacheConfig) 方法,代码如下,
publicclassMyRedisCacheManagerextendsRedisCacheManager
{

publicMyRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration)
{

super
(cacheWriter, defaultCacheConfiguration);

    }


@Override
protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig)
{

        String[] array = StringUtils.split(name, 
"#"
);

        name = array[
0
];

// 解析 @Cacheable 注解的 value 属性用以单独设置有效期
if
 (array.length > 
1
) {

long
 ttl = Long.parseLong(array[
1
]);

            cacheConfig = cacheConfig.entryTtl(Duration.ofSeconds(ttl));

        }

returnsuper
.createRedisCache(name, cacheConfig);

    }

}

MyRedisCacheManager 类逻辑如下,
  1. 继承 Spring Cache 提供的 RedisCacheManager 类。
  2. 重写 createRedisCache(String name, RedisCacheConfiguration cacheConfig) 方法。
  3. 解析 name 参数,根据 # 字符串进行分割,获取缓存 key 名称以及缓存有效期。
接着我们修改下 CacheConfig 类的 cacheManager 方法用以使用 MyRedisCacheManager 类。代码如下,
@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory)
{

returnnew
 MyRedisCacheManager(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory), defaultCacheConfig());

}


private RedisCacheConfiguration defaultCacheConfig()
{

return
 RedisCacheConfiguration.defaultCacheConfig()

            .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer()))

            .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer()))

            .computePrefixWith(name -> CACHE_PREFIX + name  + 
":"
)

            .entryTtl(Duration.ofSeconds(
600
));

}

最后我们修改下 @Cacheable 注解使用方式,在原有 value 属性的 configCache 值后添加 #600,单独标识缓存有效期。代码如下,
@Cacheable
(value = 
"configCache#600"
, key = 
"#root.methodName + '_' + #root.args[0]"
)

@Override
public String getValueByKey(String key)
{

   ...

}

看下 getValueByKey 方法生成的 Redis 缓存 key 有效期是多久。如下,
OK,看到是 590 秒有效期后,我们就大功告成了,希望本文能对大家有所帮助。

欢迎加入我的知识星球,全面提升技术能力。
👉 加入方式,长按”或“扫描”下方二维码噢
星球的内容包括:项目实战、面试招聘、源码解析、学习路线。
文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)
继续阅读
阅读原文