SpringBoot使用Caffeine實現(xiàn)緩存的示例代碼_第1頁
SpringBoot使用Caffeine實現(xiàn)緩存的示例代碼_第2頁
SpringBoot使用Caffeine實現(xiàn)緩存的示例代碼_第3頁
SpringBoot使用Caffeine實現(xiàn)緩存的示例代碼_第4頁
SpringBoot使用Caffeine實現(xiàn)緩存的示例代碼_第5頁
已閱讀5頁,還剩8頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

第SpringBoot使用Caffeine實現(xiàn)緩存的示例代碼目錄為什么要在應(yīng)用程序中添加緩存在SpringBoot應(yīng)用程序中實現(xiàn)緩存SpringBoot提供了什么緩存支持?添加生成依賴項緩存配置緩存方法結(jié)果測試緩存是否正常工作為什么緩存有時會很危險緩存更新/失效緩存復(fù)制嵌入式緩存遠(yuǎn)程緩存服務(wù)器緩存自定義緩存密鑰條件緩存@CachePut緩存失效在本博客中,我們將探討如何使用Spring的緩存框架向任何SpringBoot應(yīng)用程序添加基本緩存支持,如果沒有正確實現(xiàn),還將探討緩存的一些問題。最后但并非最不重要的一點是,我們將看幾個在真實場景中有用的緩存示例。

為什么要在應(yīng)用程序中添加緩存

在深入探討如何向應(yīng)用程序添加緩存之前,首先想到的問題是為什么我們需要在應(yīng)用程序中使用緩存。

假設(shè)有一個包含客戶數(shù)據(jù)的應(yīng)用程序,用戶發(fā)出兩個請求來獲取客戶的數(shù)據(jù)(id=100)。

這就是沒有緩存時的情況。

如您所見,對于每個請求,應(yīng)用程序都會轉(zhuǎn)到數(shù)據(jù)庫獲取數(shù)據(jù)。從數(shù)據(jù)庫獲取數(shù)據(jù)是一項成本高昂的操作,因為它涉及IO。

但是,如果中間有一個緩存存儲,可以在其中臨時存儲短時間的數(shù)據(jù),則可以將這些往返保存到數(shù)據(jù)庫并在IO時間保存。

這就是使用緩存時上述交互的樣子。

在SpringBoot應(yīng)用程序中實現(xiàn)緩存

SpringBoot提供了什么緩存支持?

SpringBoot只提供了一個緩存抽象,您可以使用它將緩存透明、輕松地添加到Spring應(yīng)用程序中。它不提供實際的緩存存儲。但是,它可以與不同類型的緩存提供程序一起工作,如Ehcache、Hazelcast、Redis、Caffee等。SpringBoot的緩存抽象可以添加到方法中(使用注釋)基本上,在執(zhí)行方法之前,Spring框架將檢查方法數(shù)據(jù)是否已經(jīng)緩存如果是,則它將從緩存中獲取數(shù)據(jù)。否則它將執(zhí)行該方法并緩存數(shù)據(jù)它還提供了從緩存中更新或刪除數(shù)據(jù)的抽象。在我們當(dāng)前的博客中,我們將了解如何使用Caffeine添加緩存,Caffeine是一種基于Java8的高性能、接近最優(yōu)的緩存庫。

您可以在application.yaml文件中指定使用哪個緩存提供程序來設(shè)置spring.cache.type屬性。

但是,如果沒有提供屬性,Spring將根據(jù)添加的庫自動檢測緩存提供程序。

添加生成依賴項

現(xiàn)在假設(shè)您已經(jīng)啟動并運行了基本的Springboot應(yīng)用程序,讓我們添加緩存依賴項。

打開build.gradle文件,并添加以下依賴項以啟用SpringBoot的緩存

compile('org.springframework.boot:spring-boot-starter-cache')

接下來我們將添加對Caffeine的依賴

compilegroup:'com.github.ben-manes.caffeine',name:'caffeine',version:'2.8.5'

緩存配置

現(xiàn)在我們需要在SpringBoot應(yīng)用程序中啟用緩存。

為此,我們需要創(chuàng)建一個配置類并提供注釋@EnableCaching。

@Configuration

@EnableCaching

publicclassCacheConfig{

}

現(xiàn)在這個類是一個空類,但是我們可以向它添加更多配置(如果需要)。

現(xiàn)在我們已經(jīng)啟用了緩存,讓我們提供緩存名稱和緩存屬性的配置,如緩存大小、緩存過期時間等

最簡單的方法是在application.yaml中添加配置

spring:

cache:

cache-names:customers,users,roles

caffeine:

spec:maximumSize=500,expireAfterAccess=60s

上述配置執(zhí)行以下操作

將可用緩存名稱限制為客戶、用戶和角色。將最大緩存大小設(shè)置為500。當(dāng)緩存中的對象數(shù)達(dá)到此限制時,將根據(jù)緩存逐出策略從緩存中刪除對象。將緩存過期時間設(shè)置為1分鐘。這意味著項目將在添加到緩存1分鐘后從緩存中刪除。

還有另一種配置緩存的方法,而不是在application.yaml文件中配置緩存。

您可以在緩存配置類中添加并提供一個CacheManagerBean,該Bean可以完成與上面在application.yaml中的配置完全相同的工作

@Bean

publicCacheManagercacheManager(){

CaffeineObject,ObjectcaffeineCacheBuilder=

Caffeine.newBuilder()

.maximumSize(500)

.expireAfterAccess(

1,TimeUnit.MINUTES);

CaffeineCacheManagercacheManager=

newCaffeineCacheManager(

"customers","roles","users");

cacheManager.setCaffeine(caffeineCacheBuilder);

returncacheManager;

}

在我們的代碼示例中,我們將使用Java配置。

我們可以在Java中做更多的事情,比如配置RemovalListener,當(dāng)一個項從緩存中刪除時執(zhí)行RemovalListener,或者啟用緩存統(tǒng)計記錄,等等。

緩存方法結(jié)果

在我們使用的示例Springboot應(yīng)用程序中,我們已經(jīng)有了以下APIGET/API/v1/customer/{id}來檢索客戶記錄。

我們將向CustomerService類的getCustomerByd(longCustomerId)方法添加緩存。

要做到這一點,我們只需要做兩件事

1.將注釋@CacheConfig(cacheNames=customers)添加到CustomerService類

提供此選項將確保CustomerService的所有可緩存方法都將使用緩存名稱customers

2.向方法OptionalgetCustomerById(LongcustomerId)添加注釋@Cacheable

@Service

@Log4j2

@CacheConfig(cacheNames="customers")

publicclassCustomerService{

@Autowired

privateCustomerRepositorycustomerRepository;

@Cacheable

publicOptionalCustomergetCustomerById(LongcustomerId){

("Fetchingcustomerbyid:{}",customerId);

returncustomerRepository.findById(customerId);

}

另外,在方法getCustomerById()中添加一個LOGGER語句,以便我們知道服務(wù)方法是否得到執(zhí)行,或者值是否從緩存返回。

復(fù)制代碼代碼如下:("Fetchingcustomerbyid:{}",customerId);

測試緩存是否正常工作

這就是緩存工作所需的全部內(nèi)容?,F(xiàn)在是測試緩存的時候了。

啟動您的應(yīng)用程序,并點擊客戶獲取url

http://localhost:8080/api/v1/customer/

在第一次API調(diào)用之后,您將在日志中看到以下行Fetchingcustomerbyid。

但是,如果再次點擊API,您將不會在日志中看到任何內(nèi)容。這意味著該方法沒有得到執(zhí)行,并且從緩存返回客戶記錄。

現(xiàn)在等待一分鐘(因為緩存過期時間設(shè)置為1分鐘)。

一分鐘后再次點擊GETAPI,您將看到下面的語句再次被記錄通過id獲取客戶。

這意味著客戶記錄在1分鐘后從緩存中刪除,必須再次從數(shù)據(jù)庫中獲取。

為什么緩存有時會很危險

緩存更新/失效

通常我們緩存GET調(diào)用,以提高性能。

但我們需要非常小心的是緩存對象的更新/刪除。

@CachePut

@cacheexecute

如果未將@CachePut/@cacheexecute放入更新/刪除方法中,GET調(diào)用中緩存返回的對象將與數(shù)據(jù)庫中存儲的對象不同??紤]下面的示例場景。

如您所見,第二個請求已將人名更新為JohnSmith。但由于它沒有更新緩存,因此從此處開始的所有請求都將從緩存中獲取過時的個人記錄(JohnDoe),直到該項在緩存中被刪除/更新。

緩存復(fù)制

大多數(shù)現(xiàn)代web應(yīng)用程序通常有多個應(yīng)用程序節(jié)點,并且在大多數(shù)情況下都有一個負(fù)載平衡器,可以將用戶請求重定向到一個可用的應(yīng)用程序節(jié)點。

這種類型的部署為應(yīng)用程序提供了可伸縮性,任何用戶請求都可以由任何一個可用的應(yīng)用程序節(jié)點提供服務(wù)。

在這些分布式環(huán)境(具有多個應(yīng)用服務(wù)器節(jié)點)中,緩存可以通過兩種方式實現(xiàn)

應(yīng)用服務(wù)器中的嵌入式緩存(正如我們現(xiàn)在看到的)遠(yuǎn)程緩存服務(wù)器

嵌入式緩存

嵌入式緩存駐留在應(yīng)用程序服務(wù)器中,它隨應(yīng)用程序服務(wù)器啟動/停止。由于每臺服務(wù)器都有自己的緩存副本,因此對其緩存的任何更改/更新都不會自動反映在其他應(yīng)用程序服務(wù)器的緩存中。

考慮具有嵌入式緩存的多節(jié)點應(yīng)用服務(wù)器的下面場景,其中用戶可以根據(jù)應(yīng)用服務(wù)器為其請求服務(wù)而得到不同的結(jié)果。

正如您在上面的示例中所看到的,更新請求更新了ApplicationNode2的數(shù)據(jù)庫和嵌入式緩存。

但是,ApplicationNode1的嵌入式緩存未更新,并且包含過時數(shù)據(jù)。因此,ApplicationNode1的任何請求都將繼續(xù)服務(wù)于舊數(shù)據(jù)。

要解決這個問題,您需要實現(xiàn)CACHEREPLICATION其中任何一個緩存中的任何更新都會自動復(fù)制到其他緩存(下圖中顯示為藍(lán)色虛線)

遠(yuǎn)程緩存服務(wù)器

解決上述問題的另一種方法是使用遠(yuǎn)程緩存服務(wù)器(如下所示)。

然而,這種方法的最大缺點是增加了響應(yīng)時間這是由于從遠(yuǎn)程緩存服務(wù)器獲取數(shù)據(jù)時的網(wǎng)絡(luò)延遲(與內(nèi)存緩存相比)

緩存自定義

到目前為止,我們看到的緩存示例是向應(yīng)用程序添加基本緩存所需的唯一代碼。

然而,現(xiàn)實世界的場景可能不是那么簡單,可能需要進(jìn)行一些定制。在本節(jié)中,我們將看到幾個這樣的例子

緩存密鑰

我們知道緩存是密鑰、值對的存儲。

示例1:默認(rèn)緩存鍵具有單參數(shù)的方法

最簡單的緩存鍵是當(dāng)方法只有一個參數(shù),并且該參數(shù)成為緩存鍵時。在下面的示例中,LongcustomerId是緩存鍵

示例2:默認(rèn)緩存鍵具有多個參數(shù)的方法

在下面的示例中,緩存鍵是所有三個參數(shù)的SimpleKeycountryId、regionId、personId。

示例3:自定義緩存密鑰

在下面的示例中,我們將此人的emailAddress指定為緩存的密鑰

示例4:使用KeyGenerator的自定義緩存密鑰

讓我們看看下面的示例如果要緩存當(dāng)前登錄用戶的所有角色,該怎么辦。

該方法中沒有提供任何參數(shù),該方法在內(nèi)部獲取當(dāng)前登錄用戶并返回其角色。

為了實現(xiàn)這個需求,我們需要創(chuàng)建一個如下所示的自定義密鑰生成器

然后我們可以在我們的方法中使用這個鍵生成器,如下所示。

條件緩存

在某些用例中,我們只希望在滿足某些條件的情況下緩存結(jié)果

示例1(支持java.util.Optional僅當(dāng)存在時才緩存)

僅當(dāng)結(jié)果中存在person對象時,才緩存person對象。

@Cacheable(value="persons",unless="#result.id")

publicOptionalPersongetPerson(LongpersonId)

示例2(如果需要,by-pass緩存)

@Cacheable(value="persons",condition="#fetchFromCache")

publicOptionalPersongetPerson(longpersonId,booleanfetchFromCache)

僅當(dāng)方法參數(shù)fetchFromCache為true時,才從緩存中獲取人員。通過這種方式,方法的調(diào)用方有時可以決定繞過緩存并直接從數(shù)據(jù)庫獲取值。

示例3(基于對象屬性的條件計算)

僅當(dāng)價格低于500且產(chǎn)品有庫存時,才緩存產(chǎn)品。

@Cacheable(

value="products",

condition="#product.price500",

unless="#result.outOfStock")

publicProductfindProduct(Productproduct)

@CachePut

我們已經(jīng)看到@Cacheable用于將項目放入緩存。

但是,如果該對象被更新,并且我們想要更新緩存,該怎么辦?

我們已經(jīng)在前面的一節(jié)中看到,不更新緩存post任何更新操作都可能導(dǎo)致從緩存返回錯誤的結(jié)

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論