JetCache簡介
一、簡介
在本文中,我們將了解JetCache 。我們將了解它是什麼、我們可以用它做什麼以及如何使用它。
JetCache 是一個快取抽象化庫,我們可以在應用程式中的一系列快取實作之上使用它。這使我們能夠以與確切的快取實現無關的方式編寫程式碼,並允許我們隨時更改實現,而不會影響應用程式中的任何其他內容。
2. 依賴關係
在使用 JetCache 之前,我們需要在建置中包含最新版本,在撰寫本文時為2.7.6 。
JetCache 附帶了我們需要的幾個依賴項,取決於我們的特定需求。此功能的核心相依性位於com.alicp.jetcache:jetcache-core 。
如果我們使用 Maven,我們可以將其包含在pom.xml中:
<dependency>
<groupId>com.alicp.jetcache</groupId>
<artifactId>jetcache-core</artifactId>
<version>2.7.6</version>
</dependency>
如果核心庫尚未包含我們想要使用的任何實際快取實現,我們可能還需要包含它們。沒有任何額外的依賴項,我們可以選擇兩個可以使用的記憶體快取 - LinkedHashMapCache (建立在標準java.util.LinkedHashMap之上)和CaffeineCache,建立在Caffeine 快取庫之上)。
3. 手動使用快取
一旦 JetCache 可用,我們就可以立即使用它來快取資料。
3.1.創建快取
為此,我們首先需要建立快取。當我們手動執行此操作時,我們需要確切地知道要使用什麼類型的快取並使用適當的建構器類別。例如,如果我們想使用LinkedHashMapCache ,我們可以使用LinkedHashMapCacheBuilder來建構一個:
Cache<Integer, String> cache = LinkedHashMapCacheBuilder.createLinkedHashMapCacheBuilder()
.limit(100)
.expireAfterWrite(10, TimeUnit.SECONDS)
.buildCache();
不同的快取框架可能有不同的可用配置設定。但是,一旦我們建立了緩存,JetCache 就會將其公開為Cache<K, V>對象,無論使用什麼底層框架。這意味著我們可以改變快取框架,唯一需要改變的是快取的建置。例如,我們可以透過更改建構器將上面的LinkedHashMapCache交換為CaffeineCache :
Cache<Integer, String> cache = CaffeineCacheBuilder.createCaffeineCacheBuilder()
.limit(100)
.expireAfterWrite(10, TimeUnit.SECONDS)
.buildCache();
我們可以看到cache欄位的類型和之前一樣,所有與它的互動也和之前一樣。
3.2.快取和檢索值
一旦我們獲得了快取實例,我們就可以使用它來儲存和檢索值。
最簡單的是,我們使用put()方法將值放入快取中,並get()方法將值取回:
cache.put(1, "Hello");
assertEquals("Hello", cache.get(1));
如果快取中沒有所需的值,則使用get()方法將傳回null 。這意味著要么緩存從未緩存過所提供的密鑰,要么緩存由於某種原因彈出了緩存條目——因為它過期了,或者因為緩存緩存了太多其他值。
如果需要,我們可以使用GET()方法來取得CacheGetResult<V>物件。這絕不是 null 並代表快取值 - 包括那裡沒有值的原因:
// This was expired.
assertEquals(CacheResultCode.EXPIRED, cache.GET(1).getResultCode());
// This was never present.
assertEquals(CacheResultCode.NOT_EXISTS, cache.GET(2).getResultCode());
傳回的確切結果程式碼將取決於所使用的底層快取庫。例如, CaffeineCache不支援指示條目已過期,因此在這兩種情況下都會傳回NOT_EXISTS ,而其他快取庫可能會給予更好的回應。
如果需要,我們也可以使用remove()呼叫來手動清除快取中的內容:
cache.remove(1);
我們可以使用它來透過刪除不再需要的條目來幫助避免彈出其他條目。
3.3.批量操作
除了處理單一條目外,我們還可以批次快取和取得條目。這與我們期望的完全一樣,只是使用適當的集合而不是單一值。
批次快取條目需要我們建置並傳入具有對應值的Map<K, V> 。然後將其傳遞給putAll()方法以快取條目:
Map<Integer, String> putMap = new HashMap<>();
putMap.put(1, "One");
putMap.put(2, "Two");
putMap.put(3, "Three");
cache.putAll(putMap);
根據底層快取實現,這可能與單獨調用每個條目完全相同,但可能更有效。例如,如果我們使用 Redis 等遠端緩存,那麼這可能會減少所需的網路呼叫數量。
批次檢索條目是透過使用包含我們希望檢索的鍵的Set<K>呼叫getAll()方法來完成的。然後傳回一個包含快取中所有條目的Map<K, V> 。我們請求的任何不在快取中的內容(例如,因為它從未被快取或因為它已過期)將不會出現在傳回的映射中:
Map<Integer, String> values = cache.getAll(keys);
最後,我們可以使用removeAll()方法批次刪除條目。與getAll()相同,我們為其提供要刪除的鍵的Set<K> ,它將確保所有這些都已刪除。
cache.removeAll(keys);
4. Spring Boot集成
手動建立和使用快取非常容易,但使用 Spring Boot 會使事情變得更加容易。
4.1.配置
JetCache 附帶了一個 Spring Boot 自動設定庫,可以自動為我們設定一切。我們只需要將其包含在我們的應用程式中,Spring Boot 將在啟動時自動偵測並載入它。為了使用它,我們需要將com.alicp.jetcache:jetcache-autoconfigure加入我們的專案。
如果我們使用 Maven,我們可以將其包含在pom.xml中:
<dependency>
<groupId>com.alicp.jetcache</groupId>
<artifactId>jetcache-autoconfigure</artifactId>
<version>2.7.6</version>
</dependency>
此外,JetCache 附帶了許多 Spring Boot Starter,我們可以將它們包含在 Spring Boot 應用程式中,以幫助我們配置特定的快取。然而,只有當我們想要核心功能以外的東西時,這些才是必要的。
4.2.以程式方式使用緩存
新增依賴項後,我們可以在應用程式中建立和使用快取。
將 JetCache 與 Spring Boot 結合使用會自動公開com.alicp.jetcache.CacheManager類型的 bean。這在概念上與 Spring org.springframework.cache. CacheManager但專為 JetCache 使用而設計。我們可以使用它來創建緩存,而不是手動創建緩存。這樣做將有助於確保快取正確連接到 Spring 生命週期中,並有助於定義一些全域屬性以使我們的生活更輕鬆。
我們可以使用getOrCreateCache()方法來建立一個新的緩存,並傳入一些特定於快取的配置以供使用:
QuickConfig quickConfig = QuickConfig.newBuilder("testing")
.cacheType(CacheType.LOCAL)
.expire(Duration.ofSeconds(100))
.build();
Cache<Integer, String> cache = cacheManager.getOrCreateCache(quickConfig);
我們可以在最有意義的地方執行此操作 - 無論是在@Bean定義中、直接在元件中還是在我們需要的任何地方。快取是根據其名稱註冊的,因此我們可以直接從快取管理器取得對它的引用,而無需根據需要建立 bean 定義,但是,建立 bean 定義可以讓它們輕鬆自動組裝。
Spring Boot 設定具有本機快取和遠端快取的概念。本機快取完全位於正在運行的應用程式的記憶體中 - 例如LinkedHashMapCache或CaffeineCache 。遠端快取是應用程式所依賴的獨立基礎設施,例如 Redis。
當我們建立快取時,我們可以指定是需要本地快取還是遠端快取。如果我們兩者都不指定,JetCache 將同時創建本地和遠端緩存,並在遠端快取之前使用本地快取來幫助提高效能。這種設定意味著我們可以獲得共享快取基礎設施的好處,同時降低了我們最近在應用程式中看到的資料的網路呼叫成本。
一旦我們獲得了快取實例,我們就可以像以前一樣使用它。我們得到了完全相同的類,並且支援所有相同的功能。
4.3.快取配置
這裡需要注意的一件事是我們從未指定要建立的快取類型。當 JetCache 與 Spring Boot 整合時,我們可以按照標準 Spring Boot 實踐,使用application.properties檔案指定一些常見的設定。這完全是可選的,如果我們不這樣做,那麼大多數事情都有合理的預設值。
例如,將LinkedHashMapCache用於本地快取並使用 Redis with Lettuce 用於遠端快取的配置可能如下所示:
jetcache.local.default.type=linkedhashmap
jetcache.remote.default.type=redis.lettuce
jetcache.remote.default.uri=redis://127.0.0.1:6379/
5.方法級緩存
除了我們已經看到的快取的標準使用之外,JetCache 在 Spring Boot 應用程式中還支援包裝整個方法並快取結果。我們透過註釋我們想要快取結果的方法來做到這一點。
為了使用它,我們首先需要啟用它。我們透過適當的配置類別上的@EnableMethodCache註解來完成此操作,包括基包名稱,我們要在其中找到我們想要啟用快取的所有類別:
@Configuration
@EnableMethodCache(basePackages = "com.baeldung.jetcache")
public class Application {}
5.1.緩存方法結果
此時,JetCache 現在將自動在任何適當的註解的方法上設定快取:
@Cached
public String doSomething(int i) {
// .....
}
如果我們對預設值感到滿意,那麼我們根本不需要註釋參數 - 具有本地和遠端快取的未命名緩存,沒有明確的過期配置,並使用快取鍵的所有方法參數。這直接等價於:
QuickConfig quickConfig = QuickConfig.newBuilder("cbjaAnnotationCacheUnitTest$TestService.doSomething(I)")
.build();
cacheManager.getOrCreateCache(quickConfig);
請注意,即使我們沒有指定快取名稱,我們也確實有一個快取名稱。預設情況下,快取名稱是我們註解的完全限定方法簽章。這有助於確保快取不會意外發生衝突,因為每個方法簽章在同一 JVM 中必須是唯一的。
此時,對此方法的每次呼叫都將根據快取鍵進行緩存,預設為整個方法參數集。如果我們隨後使用相同的參數來呼叫該方法並且我們有一個有效的快取條目,那麼它將立即返回,而根本不需要呼叫該方法。
然後,我們可以使用註釋參數配置緩存,就像以編程方式配置緩存一樣:
@Cached(cacheType = CacheType.LOCAL, expire = 3600, timeUnit = TimeUnit.SECONDS, localLimit = 100)
在本例中,我們使用僅本地緩存,其中元素將在 3,600 秒後過期,並且最多儲存 100 個元素。
此外,我們也可以指定用於快取鍵的方法參數。我們使用 SpEL 表達式來準確描述鍵應該是什麼:
@Cached(name="userCache", key="#userId", expire = 3600)
User getUserById(long userId) {
// .....
}
請注意,與 SpEL 一樣,我們在編譯程式碼時需要使用-parameters標誌,以便按名稱引用參數。如果沒有,那麼我們可以使用args[]數組按位置引用參數:
@Cached(name="userCache", key="args[0]", expire = 3600) User getUserById(long userId) { // ..... }
5.2.更新快取條目
除了用於快取方法結果的@Cached註解之外,我們還可以從其他方法更新已快取的條目。
最簡單的情況是由於方法呼叫而使快取條目無效。我們可以使用@CacheInvalidate註解來做到這一點。這需要使用與首先進行快取的方法完全相同的快取名稱和快取鍵進行配置,然後如果調用,將導致從快取中刪除適當的條目:
@Cached(name="userCache", key="#userId", expire = 3600)
User getUserById(long userId) {
// .....
}
@CacheInvalidate(name = "userCache", key = "#userId")
void deleteUserById(long userId) {
// .....
}
我們也可以使用@CacheUpdate註解根據方法呼叫直接更新快取條目。這是使用與之前完全相同的快取名稱和鍵進行配置的,而且還使用定義要儲存在快取中的值的表達式:
@Cached(name="userCache", key="#userId", expire = 3600)
User getUserById(long userId) {
// .....
}
@CacheUpdate(name = "userCache", key = "#user.userId", value = "#user")
void updateUser(User user) {
// .....
}
這樣做將始終調用帶註釋的方法,但隨後會將所需的值填入快取中。
六,結論
在本文中,我們對 JetCache 進行了廣泛的介紹。這個庫可以做更多的事情,所以為什麼不嘗試看看呢?
所有範例都可以在 GitHub 上取得。