spring可以很好地管理各种内存的快速缓存。
这些常见的内存缓存库实现方式有redis,Ehcache。
本文阐述的是redis,毕竟这个东西相当容易使用。
spring通过 org.springframework.cache.Cache 和org.springframework.cache.CacheManager两个接口来管理缓存
redis的cache实现类是 RedisCacheManager,它们的关系是这样的:
object
可以看出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 staticRedisCacheConfiguration defaultCacheConfig() {return defaultCacheConfig(null);
}public staticRedisCacheConfiguration defaultCacheConfig(@Nullable ClassLoader classLoader) {
DefaultFormattingConversionService conversionService= newDefaultFormattingConversionService();
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()的实现如下:
@FunctionalInterfacepublic interfaceCacheKeyPrefix {/*** Compute the prefix for the actual {@literalkey} stored in Redis.
*
*@paramcacheName will never be {@literalnull}.
*@returnnever {@literalnull}.*/String compute(String cacheName);/*** Creates a default {@linkCacheKeyPrefix} scheme that prefixes cache keys with {@codecacheName} followed by double
* colons. A cache named {@codemyCache} will prefix all cache keys with {@codemyCache::}.
*
*@returnthe default {@linkCacheKeyPrefix} scheme.*/
staticCacheKeyPrefix 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的实现代码:
publicRedisCacheConfiguration 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方法变为: returnthis.getCachePrefix+"->"+cacheName +this.keyPrefix
spring 5.1.x后大量使用lambda,如果不熟悉,就无法阅读这个代码。
二、定义key所需要注意的其它方面
1.当多个应用共用一个redis实例的时候,需要注意使用前缀
2.如果有很多值,建议key短一些,并形成一个key的命名文档