spring使用RedisCacheManager管理key的一些问题
spring可以很好地管理各种内存的快速缓存。
这些常见的内存缓存库实现方式有redis,Ehcache。
本文阐述的是redis,毕竟这个东西相当容易使用。
spring通过 org.springframework.cache.Cache 和org.springframework.cache.CacheManager两个接口来管理缓存
redis的cache实现类是 RedisCacheManager,它们的关系是这样的:
object
<-AbstractCacheManager=>(CacheManager, InitializingBean)
<-AbstractTransactionSupportingCacheManager
<-RedisCacheManager
可以看出RedisCacheManager实现了接口CacheManager接口。
一、如何自定义redis中key
如果使用默认的方式来注册RedisCacheManager,如下:
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofHours(this.cacheTimeOutHour))
假定注解是这样的:
@Cacheable(value="getUserPoJoById",key="#userId")
那么生成redis的key是形如这样的:
getUserPoJoById::103
其中双冒号(::)是分隔符。
这是因为RedisCacheConfiguration.defaultCacheConfig()的源码如下:
public static RedisCacheConfiguration defaultCacheConfig() { return defaultCacheConfig(null); } public static RedisCacheConfiguration defaultCacheConfig(@Nullable ClassLoader classLoader) { DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService(); registerDefaultConverters(conversionService); return new RedisCacheConfiguration(Duration.ZERO, true, true, CacheKeyPrefix.simple(), SerializationPair.fromSerializer(RedisSerializer.string()), SerializationPair.fromSerializer(RedisSerializer.java(classLoader)), conversionService); }
从上面代码可以看到使用的key前缀是CacheKeyPrefix.simple(),CacheKeyPrefix.simple()的实现如下:
@FunctionalInterface public interface CacheKeyPrefix { /** * Compute the prefix for the actual {@literal key} stored in Redis. * * @param cacheName will never be {@literal null}. * @return never {@literal null}. */ String compute(String cacheName); /** * Creates a default {@link CacheKeyPrefix} scheme that prefixes cache keys with {@code cacheName} followed by double * colons. A cache named {@code myCache} will prefix all cache keys with {@code myCache::}. * * @return the default {@link CacheKeyPrefix} scheme. */ static CacheKeyPrefix simple() { return name -> name + "::"; } }
simple实现的CacheKeyPrefix的compute方法等同于:
String compute(String cacheName){
return cacheName+"::";
}
所以默认的是使用双冒号进行分隔。
但很多情况下,我们并不希望redis的key就是这样的形式,我们可能想:
- 在整个key前加前缀
- 使用不同的分隔符号
怎么做了? 调用CacheKeyPrefix 的定制实现即可。
先来看看CacheKeyPrefix 的唯一接口方法(非静态):
String compute(String cacheName);
也就是说我们可以通过compute来指定需要的实现。
思路有了,那么以下就是实现方式:
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofHours(this.cacheTimeOutHour)).computePrefixWith(cacheName -> cacheName + this.keyPrefix); RedisCacheManager cm=RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(redisCacheConfiguration).build(); cm.setTransactionAware(true);
上文中的关键代码部分:computePrefixWith(cacheName -> cacheName + this.keyPrefix);
我们来看下RedisCacheConfiguration的computePrefixWith的实现代码:
public RedisCacheConfiguration computePrefixWith(CacheKeyPrefix cacheKeyPrefix) { Assert.notNull(cacheKeyPrefix, "Function for computing prefix must not be null!"); return new RedisCacheConfiguration(ttl, cacheNullValues, true, cacheKeyPrefix, keySerializationPair, valueSerializationPair, conversionService); }
所以代码:cacheName -> cacheName + this.keyPrefix 就是为了构建CacheKeyPrefix的compute方法
String compute(String cacheName){ return cacheName+this.keyPrefix; }
如果想加前缀,可以这样:
computePrefixWith(cacheName -> this.getCachePrefix+"->"+cacheName + this.keyPrefix)
这等同于compute方法变为: return this.getCachePrefix+"->"+cacheName + this.keyPrefix
spring 5.1.x后大量使用lambda,如果不熟悉,就无法阅读这个代码。
二、定义key所需要注意的其它方面
1.当多个应用共用一个redis实例的时候,需要注意使用前缀
2.如果有很多值,建议key短一些,并形成一个key的命名文档
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
· DeepSeek 解答了困扰我五年的技术问题
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· 易语言 —— 开山篇