日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring Cache 实战:兼容所有缓存中间件!

發(fā)布時間:2025/3/11 javascript 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring Cache 实战:兼容所有缓存中间件! 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

作者 | 悟空聊架構(gòu)

來源 |?悟空聊架構(gòu)(ID:PassJava666)

本篇給大家介紹一種兼容所有緩存中間件的方案,不論我們是使用 Redis 還是 Ehcache,都不需要關心如何操作 Redis 或者 Ehcache,這套方案統(tǒng)統(tǒng)幫你搞定。

這套方案就是大名鼎鼎的?Spring Cache。什么?你沒有聽過,沒關系,本篇帶你一起探索。

一、揭開 Spring Cache 的面紗

1.1 現(xiàn)有緩存方案的痛點

試想一種場景

1.用戶 A 打開 APP,進入到了秒殺商品的詳情頁,那這個商品數(shù)據(jù)我們會先去數(shù)據(jù)庫查詢,然后返回給客戶端。

2.因為有大量用戶短時間內(nèi)進入到了詳情頁,所以可以把活動列表緩存起來,直接讀緩存就可以了。

3.那下次再查詢商品時,直接去緩存查詢就可以了。如果秒殺商品下架了,緩存的數(shù)據(jù)不會用到了,就把緩存刪掉就可以了。

4.上面幾步看起來也沒啥問題,但是放緩存,刪除緩存這兩步是需要我們?nèi)ナ謩訉懘a實現(xiàn)的。有沒有一種方式不用寫操作緩存的代碼?

5.假如現(xiàn)在用的緩存中間件是 Redis,領導說要換成 Ehcache,操作緩存的代碼是不是又得重新擼一遍?

總結(jié)下上面場景的痛點:

  • 需要手寫操作緩存代碼,如添加緩存、更新緩存、刪除緩存。

  • 切換緩存組件并不容易,或者說沒有對緩存層進行抽象封裝,依賴具體的緩存中間件。

哪有沒有一種方案可以幫助解決上面的兩個痛點呢?

這就是今天要介紹的 Spring Cache。

1.2 Spring Cache 介紹

Spring Cache 是 Spring 提供的一整套的緩存解決方案。雖然它本身并沒有提供緩存的實現(xiàn),但是它提供了一整套的接口和代碼規(guī)范、配置、注解等,這樣它就可以整合各種緩存方案了,比如 Redis、Ehcache,我們也就不用關心操作緩存的細節(jié)。

Spring 3.1 開始定義了 org.springframework.cache.Cache 和 org.springframework.cache.CacheManager 接口來統(tǒng)一不同的緩存技術,并支持使用注解來簡化我們開發(fā)。

Cache 接口它包含了緩存的各種操作方式,同時還提供了各種xxxCache緩存的實現(xiàn),比如 RedisCache 針對Redis,EhCacheCache 針對 EhCache,ConcurrentMapCache 針對 ConCurrentMap,具體有哪幾種,后面實戰(zhàn)中會介紹。

1.3 Spring Cache 有什么功效

每次調(diào)用某方法,而此方法又是帶有緩存功能時,Spring 框架就會檢查指定參數(shù)的那個方法是否已經(jīng)被調(diào)用過,如果之前調(diào)用過,就從緩存中取之前調(diào)用的結(jié)果;如果沒有調(diào)用過,則再調(diào)用一次這個方法,并緩存結(jié)果,然后再返回結(jié)果,那下次調(diào)用這個方法時,就可以直接從緩存中獲取結(jié)果了。

1.4 Spring Cache 的原理是什么?

Spring Cache 主要是作用在類上或者方法上,對類中的方法的返回結(jié)果進行緩存。那么如何對方法增強,來實現(xiàn)緩存的功能?

學過 Spring 的同學,肯定能一下子就反應過來,就是用 AOP(面向切面編程)。

面向切面編程可以簡單地理解為在類上或者方法前加一些說明,就是我們常說的注解。

Spring Cache 的注解會幫忙在方法上創(chuàng)建一個切面(aspect),并觸發(fā)緩存注解的切點(poinitcut),聽起來太繞了,簡單點說就是:Spring Cache 的注解會幫忙在調(diào)用方法之后,去緩存方法調(diào)用的最終結(jié)果,或者在方法調(diào)用之前拿緩存中的結(jié)果,或者刪除緩存中的結(jié)果,這些讀、寫、刪緩存的臟活都交給 Spring Cache 來做了,是不是很爽,再也不用自己去寫緩存操作的邏輯了。

1.5 緩存注解

Spring 提供了四個注解來聲明緩存規(guī)則。@Cacheable,@CachePut,@CacheEvict,@Caching。

大家先有個概念,后面我們再來看怎么使用這些緩存注解。

二、使用緩存

2.1 引入 Spring Cache 依賴

在 pom 文件中引入 spring cache 依賴,如下所示:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId> </dependency>

2.2 配置使用哪種緩存

Spring Cache 支持很多緩存中間件作為框架中的緩存,總共有 9 種選擇:

  • caffeine:Caffeine 是一種高性能的緩存庫,基于 Google Guava。

  • couchbase:CouchBase是一款非關系型JSON文檔數(shù)據(jù)庫。

  • generic:由泛型機制和 static 組合實現(xiàn)的泛型緩存機制。

  • hazelcast:一個高度可擴展的數(shù)據(jù)分發(fā)和集群平臺,可用于實現(xiàn)分布式數(shù)據(jù)存儲、數(shù)據(jù)緩存。

  • infinispan:分布式的集群緩存系統(tǒng)。

  • jcache:JCache 作為緩存。它是 JSR107 規(guī)范中提到的緩存規(guī)范。

  • none:沒有緩存。

  • redis:用 Redis 作為緩存

  • simple:用內(nèi)存作為緩存。

mark

我們還是用最熟悉的 Redis 作為緩存吧。配置 Redis 作為緩存也很簡單,在配置文件 application.properties 中設置緩存的類型為 Redis 就可以了, 如下所示:

當然,別忘了還要在 pom 文件中 引入 Redis 的依賴,不然用不了 Redis。

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId> </dependency>

2.3 測試緩存

那基礎的配置已經(jīng)做好了,現(xiàn)在就是看怎么使用 Spring Cache 了。

(1)啟動類上添加 @EnableCaching注解。本文案例就是在 啟動類 PassjavaQuestionApplication 添加 @EnableCaching注解。

(2)指定某方法開啟緩存功能。在方法上添加 @Cacheable 緩存注解就可以了。

@Cacheable 注解中,可以添加四種參數(shù):value,key,condition,unless。首先我們來看下 value 參數(shù)。

下面的代碼出于演示作用,用了最簡單的邏輯,test 方法直接返回一個數(shù)字,連數(shù)據(jù)庫查詢都沒有做。不過沒關系,我們主要驗證 Spring Cache 是否對方法的結(jié)果進行了緩存。

@RequestMapping("/test") @Cacheable({"hot"}) public?int?test()?{return?222; }

大家注意,@Cacheable 注解中小括號里面還含有大括號,大括號里面還有 “hot” 字符串,這個 hot 字符串你可以把它當作一個緩存的名字,然后將 test 方法返回的結(jié)果存到 hot 緩存中。我們也可以用 value="hot" 的方式。

第一次調(diào)用 test 方法前,既沒有 hot 緩存,更沒有 test 的結(jié)果緩存。

調(diào)用 test 方法后,Redis 中就創(chuàng)建出了 hot 緩存了,然后緩存了一個 key,如下圖所示:

第二次調(diào)用 test 方法時,就從緩存 hot 中將 test 方法緩存的結(jié)果 222 取出來了,為了驗證沒有執(zhí)行 test 中的方法,大家可以在 test 方法中打下 log 或者斷點。最后的驗證結(jié)果肯定是沒有走 test 方法的,而是直接從緩存中獲取的。

那我們再來測試一個方法,方法名改為 test2,且請求路徑也改為 test2 了。

@RequestMapping("/test2") @Cacheable({"hot"}) public?int?test2()?{return?456; }

大家覺得這兩個方法的結(jié)果都會緩存嗎?還是只會緩存第一個被調(diào)用的方法?

經(jīng)過測試,執(zhí)行第一個 test 方法后,再執(zhí)行 test2 方法,緩存結(jié)果一直是 222 不會變。因為他們的 key 都是 默認的 SimpleKey[],所以兩個方法對應的緩存的 key 都叫這個,所以得到的緩存值是一樣的。

(3)加上數(shù)據(jù)庫查詢的測試。

有的同學可能覺得上面的測試太簡單了,test 方法里面啥都沒做,還緩存啥呢,完全沒必要啊。沒關系,大家的顧慮是對的,我們來加上數(shù)據(jù)庫查詢,安排~

先說下場景:前端需要查詢某個題目的詳情,正常邏輯是查詢數(shù)據(jù)庫后返回結(jié)果。假定這個查詢操作非常頻繁,我們需要將題目詳情進行緩存。我們先看看常規(guī) Redis 緩存方案:

先從 Redis 緩存中查看緩存中是否有該題目,如果緩存中有,則返回緩存中的題目;如果沒有,就從數(shù)據(jù)庫中查。查詢出題目后,就用 Redis 存起來,然后返回。這里就要寫操作 Redis 的代碼了:查詢 Redis 緩存、更新 Redis 緩存。

//?查詢緩存,假定該題目詳情緩存的?key=question1 redisTemplate.opsForValue().get("question1");? //?更新緩存 redisTemplate.opsForValue().set("question1",?questionEntity);

那如果用 Spring Cache 注解的話,上面兩行代碼可以直接干掉了。如下所示,加一個 @Cacheable 注解搞定。

@Cacheable({"question",?"hot"}) public?QuestionEntity?info(Long?id)?{return?getById(id);?//?查詢數(shù)據(jù)庫操作 }

其中 question 和 hot 是緩存的名字,我們可以將結(jié)果放到不同的緩存中。

結(jié)論:

  • 如果沒有指定請求參數(shù),則緩存生成的 key name,是默認自動生成的,叫做 SimpleKey[]。

  • 如果指定了請求參數(shù),則緩存的 key ?name 就是請求參數(shù),比如上面 info 方法,key 等于我傳入的 id = 1。

  • 緩存中 key 對應的 value 默認使用 JDK 序列化后的數(shù)據(jù)。

  • value 的過期時間為 -1,表示永不過期。

2.4 自定義配置類

上面保存的緩存數(shù)據(jù)都是默認設置,我們也可以自己定義配置,如下所示,在配置文件 application.properties 添加如下配置:

#?使用?Redis?作為緩存組件 spring.cache.type=redis #?緩存過期時間為?3600s spring.cache.redis.time-to-live=3600000 #?緩存的鍵的名字前綴 spring.cache.redis.key-prefix=passjava_ #?是否使用緩存前綴 spring.cache.redis.use-key-prefix=true #?是否緩存控制,防止緩存穿透 spring.cache.redis.cache-null-values=true

然后需要加一個配置類:MyCacheConfig。可以在我的開源項目 passjava 獲取完整源碼。

RedisCacheConfiguration?redisCacheConfiguration(CacheProperties?cacheProperties)?{ }

2.5 自定義 key

然后我們可以指定 key 的值,可以在 @Cacheable 注解里面加上 key 的值 #root.method.name。這是一種特有的表達式,稱作 SpEL 表達式,這里代表用方法名作為緩存 key 的名字。

@Cacheable(value?=?{"hot"},?key?=?"#root.method.name")

接下來就是見證奇跡的時刻,調(diào)用 test 方法和 test2 方法,發(fā)現(xiàn)有兩個不同的 key,一個是 passjava_test1,另外一個 passjava_test2,它們的 key 就是前綴 passjava_ + 方法名 組成。

SpEL 表達式還有很多其它規(guī)則,如下所示:

可以根據(jù)項目需要選擇合適的表達式來自定義 key。

2.6 自定義條件

除了設置緩存條目的 key,我們還可以自定義條件來決定是否將緩存功能關閉。這里就要用到@Cacheable 另外兩個屬性:condition 和 unless,它倆的格式還是用 SpEL 表達式。對應的四個屬性總結(jié)如下:

代碼示例如下:

@Cacheable(value?=?"hot",?unless?=?"#result.message.containss('NoCache')")

當放回的結(jié)果 message 字段包含有 NoCache 就不會進行緩存。

2.7 更新注解

@CachePut 也是用來更新緩存,和 @Cacheable 非常相似,不同點是 @CachePut 注解的方法始終都會執(zhí)行,返回值也會也會放到緩存中。通常用在保存的方法上。

保存成功后,可以將 key 設置保存實例的 id。這個怎么做呢?

之前我們說過 key 可以通過 SpEL 表達式來指定,這里就可以搭配 #result.id 來實現(xiàn)。

這里還是用個例子來說明用法:創(chuàng)建題目的方法,返回題目實例,其中包含有題目 id。

@RequestMapping("/create") @CachePut(value?=?"hot",?key?=?"#result.id") public?QuestionEntity?create(@Valid?@RequestBody?QuestionEntity?question){return?IQuestionService.createQuestion(question); }

保存的 id 是自增的,值為 123,所以緩存中的 key = passjava_123。

2.8 刪除緩存注解

@CacheEvict 注解的方法在調(diào)用時不會在緩存中添加任何東西,但是會從從緩存中移除之前的緩存結(jié)果。

示例代碼如下:

@RequestMapping("/remove/{id}") @CacheEvict(value?=?"hot") public?R?remove(@PathVariable("id")?Long?id){IQuestionService.removeById(id);return?R.ok(); }

刪除條目的 key 與傳遞進來的 id 相同。我測試的時候傳的 id = 123,經(jīng)過前綴passjava_組裝后就是 passjava_123,所以將之前緩存的 passjava_123 刪除了。重復執(zhí)行也不會報錯。

注意:@CacheEvict 和 @Cacheable、@CachePut 不同,它能夠應用在返回值為 void 的方法上。

@CacheEvict 還有些屬性可供使用,總結(jié)如下:

三、 總結(jié)

本文通過傳統(tǒng)使用緩存的方式的痛點引出 Spring 框架中的 Cache 組件。然后詳細介紹了 Spring Cache 組件的用法:

  • 五大注解。@Cacheable、@CachePut、@CacheEvict、@Caching,、@CacheConfig。

  • 如何自定義緩存條目的 key。

  • 如何自定義 Cache 配置。

  • 如何自定義緩存的條件。

當然 Spring Cache 并不是萬能的,緩存一致性問題依舊存在,下一篇,我們再細聊緩存的一致性問題。

往期推薦

@Autowired報錯的4種解決方案和原因分析!


厲害了,Spring中bean的12種定義方法!


SpringBoot 中的 3 種條件裝配!



總結(jié)

以上是生活随笔為你收集整理的Spring Cache 实战:兼容所有缓存中间件!的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 久久久久久久久久久av | av在线播放网站 | 日本新japanese乱熟 | 女同互舔视频 | 国产av人人夜夜澡人人爽麻豆 | 瑟瑟在线观看 | 美国免费高清电影在线观看 | 国产网友自拍 | 在线观看亚洲 | 亚洲人午夜射精精品日韩 | 69视频免费 | 91美女精品| 一区二区三区欧美日韩 | 欧美a级成人淫片免费看 | 日韩电影在线一区 | 亚洲综合激情小说 | 好看的中文字幕电影 | 国产一区不卡在线观看 | 欧美久久久久久久久中文字幕 | 国产精品丝袜视频 | 国产稀缺精品盗摄盗拍 | 大伊人网 | av综合色| 波多野结衣爱爱 | 少妇一区二区三区四区 | 一区二区国产精品视频 | 成人黄色在线视频 | 成人三级做爰av | 精品国产va久久久久久久 | 可以看的av网址 | 97精品国产97久久久久久免费 | 无码一区二区三区在线 | 最新福利视频 | 久久香蕉网站 | 久久精品视频在线观看 | 日韩高清片 | 一区二区三区视频播放 | 国产精品嫩草影院桃色 | 红桃一区二区三区 | 亚洲偷偷 | 日日拍夜夜拍 | 色综合久久久久无码专区 | av网站在线观看不卡 | a级黄毛片 | 中文在线字幕免费观看 | 777精品| 日韩欧美亚洲成人 | 一本一道久久综合 | 亚洲综合欧美综合 | a级片黄色| 国产亚洲欧美视频 | 男女视频在线 | 国产成人精品综合久久久久99 | 高潮一区二区三区乱码 | 久久亚洲综合国产精品99麻豆精品福利 | 色综合天天网 | 日本在线一本 | 91成人亚洲| 久久久性视频 | 亚洲无码一区二区三区 | 欧美黑人一区二区三区 | 日本xxxxxⅹxxxx69 | 性xxxx狂欢老少配o | 女人下面喷水视频 | 国产精品视频一区二区三区, | 色多多在线观看 | 国产999精品视频 | 影音先锋在线看 | 亚洲天堂精品在线观看 | 免费看v片 | 国产嘿咻视频 | 白嫩情侣偷拍呻吟刺激 | 软萌小仙自慰喷白浆 | 中文字幕视频一区二区 | 国产极品一区 | 午夜视频福利网站 | 色婷婷精品视频 | 欧美大片黄 | 成人av软件| 成人精品在线视频 | 亚洲精品在线观看网站 | 男生把女生困困的视频 | 亚洲成a人在线观看 | 绿帽视频 | 国产乱码久久久久 | 欧美13p | 欧美日韩一区二区在线视频 | 欧美日性视频 | 黄色一节片 | 午夜之声l性8电台lx8电台 | 男女男精品视频站 | 亚洲国产精品视频 | 3d动漫啪啪精品一区二区中文字幕 | 久久久久国产视频 | 最新天堂中文在线 | 一级片在线免费播放 | 韩国黄色片网站 | 欧美激情影音先锋 | 亚洲视频一二三四 |