spring-boot支持多種介質(zhì)來實現(xiàn)緩存功能兜蠕,我們最常用的可能是redis存儲的方式。目前spring-boot發(fā)布了2.0.0版本較之1.5.x版本存在一些細(xì)小的差異,接下來我們比較一下兩個版本下使用方式斧账。
一著蟹、本次案例
我們假設(shè)用戶信息(user)和產(chǎn)品信息(product)需要緩存,緩存數(shù)據(jù)都加上user和product作為key前綴中贝,采用用戶的id和產(chǎn)品的id作為key的后綴囤捻。用戶緩存時間為30分鐘,產(chǎn)品信息緩存時間為10分鐘邻寿。
二蝎土、redis客戶端配置
無論使用spring-boot的哪個版本,我們都需要先配置redis連接老厌,兩個版本的redis客戶端連接池使用有所不同瘟则。
spring-boot版本 | 默認(rèn)連接池類型 |
---|---|
1.5.x | jedis |
2.x | lettuce |
在1.5.x中,我們配置jedis連接池只需要配置 spring.redis.pool.* 開始的配置即可枝秤,如下配置
spring.redis.pool.max-active=8
spring.redis.pool.max-wait=-1
spring.redis.pool.min-idle=0
spring.redis.pool.max-idle=8
但在2.x版本中由于引入了不同的客戶端醋拧,需要指定配置哪種連接池,如下配置
#jedis客戶端
spring.redis.jedis.pool.max-active=8
spring.redis.jedis.pool.max-wait=-1ms
spring.redis.jedis.pool.min-idle=0
spring.redis.jedis.pool.max-idle=8
#lettuce客戶端
spring.redis.lettuce.pool.min-idle=0
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.max-wait=-1ms
spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.shutdown-timeout=100ms
除此之外還可以看到時間配置上還需要帶上對應(yīng)的單位淀弹。
三丹壕、直接配置cache參數(shù)
在1.5.x版本下提供的針對cache的配置非常少,我們能夠使用到的自動裝配redis緩存的配置如下
#緩存的名稱集合薇溃,多個采用逗號分割
spring.cache.cache-names=
#緩存的類型菌赖,官方提供了很多,這里我們填寫redis
spring.cache.type=
在2.x版本時沐序,官方增加了更多的配置
#緩存的名稱集合琉用,多個采用逗號分割
spring.cache.cache-names=
#緩存的類型,官方提供了很多策幼,這里我們填寫redis
spring.cache.type=
#是否緩存null數(shù)據(jù)邑时,默認(rèn)是false
spring.cache.redis.cache-null-values=
#redis中緩存超時的時間,默認(rèn)60000ms
spring.cache.redis.time-to-live=
#緩存數(shù)據(jù)key是否使用前綴特姐,默認(rèn)是true
spring.cache.redis.use-key-prefix=
#緩存數(shù)據(jù)key的前綴晶丘,在上面的配置為true時有效,
spring.cache.redis.key-prefix=
四、JavaConfig方式配置
通用配置方式只能滿足整個程序所有緩存都采用相同公共配置的方式浅浮,如果需要特殊處理沫浆,如我們的案列,則需要自己采用代碼的方式來配置滚秩。
采用代碼的方式专执,只要需要配置的是CacheMananger,采用Redis時具體實現(xiàn)我們需要使用其子類RedisCacheMananger來做配置
4.1叔遂、spring-boot 1.5.x版本
CacheManager配置
@Bean
public CacheManager cacheManager(RedisTemplate redisTemplate) {
RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate);
//默認(rèn)超時時間他炊,單位秒
redisCacheManager.setDefaultExpiration(60);
//緩存超時時間Map,key為cacheName已艰,value為超時,單位是秒
Map<String, Long> expiresMap = new HashMap<>();
//緩存用戶信息的cacheName和超時時間
expiresMap.put("user", 1800L);
//緩存產(chǎn)品信息的cacheName和超時時間
expiresMap.put("product", 600L);
redisCacheManager.setExpires(expiresMap);
return redisCacheManager;
}
cache調(diào)用代碼
@Cacheable(value = "user", key = "'user:'+#id", unless = "#result==null")
public String getUser(int id) {
//邏輯操作
}
@Cacheable(value = "product", key = "'product:'+#id", unless = "#result==null")
public String getProduct(int id) {
//邏輯操作
}
4.2痊末、spring-boot 2.x版本
CacheManager配置
2.x版本開始,代碼方式配置變化比較大哩掺,同時增加了更多配置參數(shù)
@Bean
CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
//user信息緩存配置
RedisCacheConfiguration userCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(30)).disableCachingNullValues().prefixKeysWith("user");
//product信息緩存配置
RedisCacheConfiguration productCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(10)).disableCachingNullValues().prefixKeysWith("product");
Map<String, RedisCacheConfiguration> redisCacheConfigurationMap = new HashMap<>();
redisCacheConfigurationMap.put("user", userCacheConfiguration);
redisCacheConfigurationMap.put("product", productCacheConfiguration);
//初始化一個RedisCacheWriter
RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory);
//設(shè)置CacheManager的值序列化方式為JdkSerializationRedisSerializer,但其實RedisCacheConfiguration默認(rèn)就是使用StringRedisSerializer序列化key凿叠,JdkSerializationRedisSerializer序列化value,所以以下注釋代碼為默認(rèn)實現(xiàn)
//ClassLoader loader = this.getClass().getClassLoader();
//JdkSerializationRedisSerializer jdkSerializer = new JdkSerializationRedisSerializer(loader);
//RedisSerializationContext.SerializationPair<Object> pair = RedisSerializationContext.SerializationPair.fromSerializer(jdkSerializer);
//RedisCacheConfiguration defaultCacheConfig=RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(pair);
RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig();
//設(shè)置默認(rèn)超過期時間是30秒
defaultCacheConfig.entryTtl(Duration.ofSeconds(30));
//初始化RedisCacheManager
RedisCacheManager cacheManager = new RedisCacheManager(redisCacheWriter, defaultCacheConfig, redisCacheConfigurationMap);
return cacheManager;
}
以上代碼中RedisCacheConfiguration類為2.x新增的配置類,增加了幾個配置項嚼吞。這里比較奇怪的是調(diào)用它的配置方法每一次都會重新生成一個配置對象盒件,而不是在原對象上直接修改參數(shù)值,這一點本人沒搞懂作者為何要選擇這種方式舱禽。
cache調(diào)用代碼
@Cacheable(value = "user", key = "#id", unless = "#result==null")
public String getUser(int id) {
//邏輯操作
}
@Cacheable(value = "product", key = "#id", unless = "#result==null")
public String getProduct(int id) {
//邏輯操作
}
這里兩點需要注意的地方
- 1炒刁、在Cacheable的key屬性中不在需要自己配置前綴,可以在RedisCacheConfiguration中配置誊稚。
- 2翔始、如果Cacheable中不配置 unless = "#result==null" 屬性,而RedisCacheConfiguration中調(diào)用disableCachingNullValues()配置了不緩存null結(jié)果在出現(xiàn)null結(jié)果時會報異常里伯,這一點與我一開始的理解也不太一樣城瞎,二者并非都生效的。個人理解unless配置#result==null可以決定null的值是否往cacheManager丟疾瓮,而RedisCacheConfiguration的disableCachingNullValues()只在存儲前起到了校驗作用脖镀,而不會因為設(shè)置了這個值而直接跳過null的保存。如果真是設(shè)計如此狼电,感覺有點雞肋蜒灰,不知道算不算一個bug。
小結(jié)
spring-boot剛剛發(fā)布了2.0.0的正式版肩碟,除了比較大的webflux之外卷员,許多組件可能都有細(xì)節(jié)變化,在做升級的時候需要注意更改腾务,建議先驗證常用的功能用法后,再做升級的計劃安排削饵。