<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
在本部落格中,我們將探討如何使用Spring的快取框架向任何Spring Boot應用程式新增基本快取支援,如果沒有正確實現,還將探討快取的一些問題。最後但並非最不重要的一點是,我們將看幾個在真實場景中有用的快取範例。
在深入探討如何嚮應用程式新增快取之前,首先想到的問題是為什麼我們需要在應用程式中使用快取。
假設有一個包含客戶資料的應用程式,使用者發出兩個請求來獲取客戶的資料(id=100)。
這就是沒有快取時的情況。
如您所見,對於每個請求,應用程式都會轉到資料庫獲取資料。從資料庫獲取資料是一項成本高昂的操作,因為它涉及IO。
但是,如果中間有一個快取儲存,可以在其中臨時儲存短時間的資料,則可以將這些往返儲存到資料庫並在IO時間儲存。
這就是使用快取時上述互動的樣子。
您可以在 application.yaml
檔案中指定使用哪個快取提供程式來設定 spring.cache.type
屬性。
但是,如果沒有提供屬性,Spring將根據新增的庫自動檢測快取提供程式。
現在假設您已經啟動並執行了基本的Spring boot應用程式,讓我們新增快取依賴項。
開啟 build.gradle
檔案,並新增以下依賴項以啟用Spring Boot的快取
compile('org.springframework.boot:spring-boot-starter-cache')
接下來我們將新增對Caffeine的依賴
compile group: 'com.github.ben-manes.caffeine', name: 'caffeine', version: '2.8.5'
現在我們需要在Spring Boot應用程式中啟用快取。
為此,我們需要建立一個設定類並提供註釋 @EnableCaching
。
@Configuration @EnableCaching public class CacheConfig { }
現在這個類是一個空類,但是我們可以向它新增更多設定(如果需要)。
現在我們已經啟用了快取,讓我們提供快取名稱和快取屬性的設定,如快取大小、快取過期時間等
最簡單的方法是在 application.yaml
中新增設定
spring: cache: cache-names: customers, users, roles caffeine: spec: maximumSize=500, expireAfterAccess=60s
上述設定執行以下操作
還有另一種設定快取的方法,而不是在 application.yaml
檔案中設定快取。
您可以在快取設定類中新增並提供一個 CacheManager
Bean,該Bean可以完成與上面在 application.yaml
中的設定完全相同的工作
@Bean public CacheManager cacheManager() { Caffeine<Object, Object> caffeineCacheBuilder = Caffeine.newBuilder() .maximumSize(500) .expireAfterAccess( 1, TimeUnit.MINUTES); CaffeineCacheManager cacheManager = new CaffeineCacheManager( "customers", "roles", "users"); cacheManager.setCaffeine(caffeineCacheBuilder); return cacheManager; }
在我們的程式碼範例中,我們將使用Java設定。
我們可以在Java中做更多的事情,比如設定 RemovalListener
,當一個項從快取中刪除時執行 RemovalListener
,或者啟用快取統計記錄,等等。
在我們使用的範例Spring boot應用程式中,我們已經有了以下API GET /API/v1/customer/{id}
來檢索客戶記錄。
我們將向CustomerService類的 getCustomerByd(longCustomerId)
方法新增快取。
要做到這一點,我們只需要做兩件事
1. 將註釋 @CacheConfig(cacheNames=“customers”)
新增到 CustomerService
類
提供此選項將確保 CustomerService
的所有可快取方法都將使用快取名稱“customers”
2. 向方法 Optional getCustomerById(Long customerId)
新增註釋 @Cacheable
@Service @Log4j2 @CacheConfig(cacheNames = "customers") public class CustomerService { @Autowired private CustomerRepository customerRepository; @Cacheable public Optional<Customer> getCustomerById(Long customerId) { log.info("Fetching customer by id: {}", customerId); return customerRepository.findById(customerId); } }
另外,在方法 getCustomerById()
中新增一個 LOGGER
語句,以便我們知道服務方法是否得到執行,或者值是否從快取返回。
複製程式碼 程式碼如下:log.info("Fetching customer by id: {}", customerId);
這就是快取工作所需的全部內容。現在是測試快取的時候了。
啟動您的應用程式,並點選客戶獲取url
http://localhost:8080/api/v1/customer/
在第一次API呼叫之後,您將在紀錄檔中看到以下行—“ Fetching customer by id
”。
但是,如果再次點選API,您將不會在紀錄檔中看到任何內容。這意味著該方法沒有得到執行,並且從快取返回客戶記錄。
現在等待一分鐘(因為快取過期時間設定為1分鐘)。
一分鐘後再次點選GETAPI,您將看到下面的語句再次被記錄——“通過id獲取客戶”。
這意味著客戶記錄在1分鐘後從快取中刪除,必須再次從資料庫中獲取。
通常我們快取 GET
呼叫,以提高效能。
但我們需要非常小心的是快取物件的更新/刪除。
@CachePut @cacheexecute
如果未將 @CachePut/@cacheexecute
放入更新/刪除方法中,GET呼叫中快取返回的物件將與資料庫中儲存的物件不同。考慮下面的範例場景。
如您所見,第二個請求已將人名更新為“ John Smith
”。但由於它沒有更新快取,因此從此處開始的所有請求都將從快取中獲取過時的個人記錄(“ John Doe
”),直到該項在快取中被刪除/更新。
大多數現代web應用程式通常有多個應用程式節點,並且在大多數情況下都有一個負載平衡器,可以將使用者請求重定向到一個可用的應用程式節點。
這種型別的部署為應用程式提供了可伸縮性,任何使用者請求都可以由任何一個可用的應用程式節點提供服務。
在這些分散式環境(具有多個應用伺服器節點)中,快取可以通過兩種方式實現
嵌入式快取駐留在應用程式伺服器中,它隨應用程式伺服器啟動/停止。由於每臺伺服器都有自己的快取副本,因此對其快取的任何更改/更新都不會自動反映在其他應用程式伺服器的快取中。
考慮具有嵌入式快取的多節點應用伺服器的下面場景,其中使用者可以根據應用伺服器為其請求服務而得到不同的結果。
正如您在上面的範例中所看到的,更新請求更新了 Application Node2
的資料庫和嵌入式快取。
但是, Application Node1
的嵌入式快取未更新,並且包含過時資料。因此, Application Node1
的任何請求都將繼續服務於舊資料。
要解決這個問題,您需要實現 CACHE REPLICATION
—其中任何一個快取中的任何更新都會自動複製到其他快取(下圖中顯示為藍色虛線)
解決上述問題的另一種方法是使用遠端快取伺服器(如下所示)。
然而,這種方法的最大缺點是增加了響應時間——這是由於從遠端快取伺服器獲取資料時的網路延遲(與記憶體快取相比)
到目前為止,我們看到的快取範例是嚮應用程式新增基本快取所需的唯一程式碼。
然而,現實世界的場景可能不是那麼簡單,可能需要進行一些客製化。在本節中,我們將看到幾個這樣的例子
我們知道快取是金鑰、值對的儲存。
範例1:預設快取鍵–具有單引數的方法
最簡單的快取鍵是當方法只有一個引數,並且該引數成為快取鍵時。在下面的範例中, Long customerId
是快取鍵
範例2:預設快取鍵–具有多個引數的方法
在下面的範例中,快取鍵是所有三個引數的SimpleKey– countryId
、 regionId
、 personId
。
範例3:自定義快取金鑰
在下面的範例中,我們將此人的 emailAddress
指定為快取的金鑰
範例4:使用 KeyGenerator
的自定義快取金鑰
讓我們看看下面的範例–如果要快取當前登入使用者的所有角色,該怎麼辦。
該方法中沒有提供任何引數,該方法在內部獲取當前登入使用者並返回其角色。
為了實現這個需求,我們需要建立一個如下所示的自定義金鑰生成器
然後我們可以在我們的方法中使用這個鍵生成器,如下所示。
在某些用例中,我們只希望在滿足某些條件的情況下快取結果
範例1(支援 java.util.Optional
–僅當存在時才快取)
僅當結果中存在 person
物件時,才快取 person
物件。
@Cacheable( value = "persons", unless = "#result?.id") public Optional<Person> getPerson(Long personId)
範例2(如果需要,by-pass快取)
@Cacheable(value = "persons", condition="#fetchFromCache") public Optional<Person> getPerson(long personId, boolean fetchFromCache)
僅當方法引數“ fetchFromCache
”為true時,才從快取中獲取人員。通過這種方式,方法的呼叫方有時可以決定繞過快取並直接從資料庫獲取值。
範例3(基於物件屬性的條件計算)
僅當價格低於500且產品有庫存時,才快取產品。
@Cacheable( value="products", condition="#product.price<500", unless="#result.outOfStock") public Product findProduct(Product product)
我們已經看到 @Cacheable
用於將專案放入快取。
但是,如果該物件被更新,並且我們想要更新快取,該怎麼辦?
我們已經在前面的一節中看到,不更新快取post任何更新操作都可能導致從快取返回錯誤的結果。
@CachePut(key = "#person.id") public Person update(Person person)
但是如果 @Cacheable
和 @CachePut
都將一個專案放入快取,它們之間有什麼區別?
主要區別在於實際的方法執行
@Cacheable @CachePut
快取失效與將物件放入快取一樣重要。
當我們想要從快取中刪除一個或多個物件時,有很多場景。讓我們看一些例子。
例1
假設我們有一個用於批次匯入個人記錄的API。
我們希望在呼叫此方法之前,應該清除整個 person
快取(因為大多數 person
記錄可能會在匯入時更新,而快取可能會過時)。我們可以這樣做如下
@CacheEvict( value = "persons", allEntries = true, beforeInvocation = true) public void importPersons()
例2
我們有一個Delete Person API,我們希望它在刪除時也能從快取中刪除 Person
記錄。
@CacheEvict( value = "persons", key = "#person.emailAddress") public void deletePerson(Person person)
預設情況下 @CacheEvict
在方法呼叫後執行。
到此這篇關於SpringBoot使用Caffeine實現快取的範例程式碼的文章就介紹到這了,更多相關SpringBoot Caffeine快取內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45