spring-boot+redis實現(xiàn)緩存功能

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é)變化,在做升級的時候需要注意更改腾务,建議先驗證常用的功能用法后,再做升級的計劃安排削饵。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末岩瘦,一起剝皮案震驚了整個濱河市未巫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌启昧,老刑警劉巖叙凡,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異密末,居然都是意外死亡握爷,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門严里,熙熙樓的掌柜王于貴愁眉苦臉地迎上來新啼,“玉大人,你說我怎么就攤上這事刹碾≡镒玻” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵迷帜,是天一觀的道長物舒。 經(jīng)常有香客問我,道長戏锹,這世上最難降的妖魔是什么冠胯? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮锦针,結(jié)果婚禮上荠察,老公的妹妹穿的比我還像新娘。我一直安慰自己伞插,他們只是感情好割粮,可當(dāng)我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著媚污,像睡著了一般舀瓢。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上耗美,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天京髓,我揣著相機與錄音,去河邊找鬼商架。 笑死堰怨,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蛇摸。 我是一名探鬼主播备图,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了揽涮?” 一聲冷哼從身側(cè)響起抠藕,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蒋困,沒想到半個月后盾似,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡雪标,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年零院,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片村刨。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡告抄,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出烹困,到底是詐尸還是另有隱情玄妈,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布髓梅,位于F島的核電站拟蜻,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏枯饿。R本人自食惡果不足惜酝锅,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望奢方。 院中可真熱鬧搔扁,春花似錦、人聲如沸蟋字。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鹊奖。三九已至苛聘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間忠聚,已是汗流浹背设哗。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留两蟀,地道東北人网梢。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像赂毯,于是被迫代替她去往敵國和親战虏。 傳聞我的和親對象是個殘疾皇子拣宰,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容