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的命名文檔
