快取抽象化:JCache (JSR-107) 註解支援

工程 | Stéphane Nicoll | 2014 年 4 月 14 日 | ...

Spring 的快取抽象化功能自 Spring 3.1 起提供,現在是時候讓它獲得更多關注了。在這篇文章中,我想帶您了解該領域的主要改進,即 JCache (JSR-107) 註解的支援。

您可能已經聽說過,在最初提案的 13 年後,JSR-107 終於定案。對於熟悉 Spring 快取註解的人來說,下表描述了 Spring 註解與 JSR-107 對應項之間的映射關係。

Spring JSR-107
@Cacheable @CacheResult
@CachePut @CachePut
@CacheEvict @CacheRemove
@CacheEvict(allEntries=true) @CacheRemoveAll

JCache 註解

讓我們先看看每個註解,並描述它們的使用方式。這將是一個更好的機會來了解它們支援什麼,以及您已經習慣的 Spring 註解,更重要的是這些註解帶來的功能。

@CacheResult

@CacheResult@Cacheable 非常相似,以下使用 @CacheResult 註解重寫了 原始範例

@CacheResult(cacheName = "books")
public Book findBook(ISBN isbn) {...}

可以使用 CacheKeyGenerator 介面自訂鍵的產生。如果沒有指定特定的實作,則預設實作根據規範,會採用所有參數,除非一個或多個參數使用 @CacheKey 註解,在這種情況下,只會使用這些參數。假設上面的方法現在需要一個額外的屬性,不應成為鍵的一部分,這就是我們使用 JCache 編寫它的方式。

@CacheResult(cacheName = "book")
public Book findBook(@CacheKey ISBN isbn, boolean checkWarehouse) { ... }

@CacheResult 帶來了例外快取的概念:每當方法執行失敗時,可以快取引發的例外,以防止再次呼叫該方法。 假設如果 ISBN 的結構無效,則會擲回 InvalidIsbnNotFoundException。這是一個永久性失敗,永遠無法使用此參數檢索書籍。以下快取例外,以便以後使用相同無效 ISBN 的呼叫直接擲回快取的例外,而不是再次呼叫該方法。

@CacheResult(cacheName = "books", exceptionCacheName = "failures"
             cachedExceptions = InvalidIsbnNotFoundException.class)
public Book findBook(@CacheKey ISBN isbn) { ... }

當然,盲目地擲回快取的例外可能會非常令人困惑,因為呼叫堆疊可能與目前的呼叫上下文不符。 我們會盡最大努力確保堆疊追蹤匹配,方法是複製具有一致呼叫堆疊的例外。

JCache 具有 CacheResolver 這個很棒的概念,允許在執行時解析要使用的快取。由於 JCache 支援常規快取和例外快取,因此要使用的 CacheResolver 實例由 CacheResolverFactory 確定。 顯而易見的預設是分別根據 cacheNameexceptionCacheName 屬性解析要使用的快取。 但是,也可以自訂每個操作要使用的工廠。

@CacheResult(cacheName = "books", cacheResolverFactory = MyFactory.class)
public Book findBook(@CacheKey ISBN isbn) { ... }

最後,@CacheResult 具有一個 skipGet 屬性,可以啟用該屬性以始終呼叫該方法,而不管快取的狀態如何。 這實際上與我們自己使用 @CachePut 非常相似。

@CachePut

雖然註解具有相同的名稱,但 JCache 中的語義卻大不相同。 我們的書的簡單更新可以這樣編寫

@CachePut(value = "books", key = "#p0")
public Book update(ISBN isbn, Book updatedBook) { ... }

雖然 JCache 會要求你這樣編寫它

@CachePut(cacheName = "books")
public void update(ISBN isbn, @CacheValue Book updatedBook) { ... }

請注意,即使 updatedBook 不應成為鍵的一部分,我們也不必將 @CacheKey 新增到第一個參數。 這是因為使用 @CacheValue 註解的參數會自動從鍵產生中排除。

對於 @CacheResult@CachePut 允許管理執行方法時擲回的任何例外,如果擲回的例外與註解上指定的篩選器匹配,則防止發生 put 操作。

最後,可以控制是在呼叫註解的方法之前還是之後更新快取。 當然,如果在之前更新,則不會進行例外處理。

@CacheRemove 和 @CacheRemoveAll

它們分別與 @CacheEvict@CacheEvict(allEntries = true) 非常相似。 @CacheRemove 具有特殊的例外處理,以防止在註解的方法擲回與註解上指定的篩選器匹配的例外時,發生逐出。

其他功能

CacheDefaults

@CacheDefaults 是一個類別層級的註解,允許您共享在類別上定義的任何快取操作的通用設定。 這些是

  • 快取的名稱
  • 自訂 CacheResolverFactory
  • 自訂 CacheKeyGenerator

在下面的範例中,任何與快取相關的操作都將使用 books 快取

@CacheDefaults(cacheName = "books")
public class BookRepositoryImpl implements BookRepository {

    @CacheResult
    public Book findBook(@CacheKey ISBN isbn) { ... }
}

啟用 JSR-107 支援

JCache 支援的實作使用我們自己的 CacheCacheManager 抽象化,這意味著您可以使用現有的 CacheManager 基礎架構,並且仍然可以使用標準註解!

要啟用 Spring 快取註解的支援,您可以使用 @EnableCaching<cache:annotation-driven/> xml 元素,例如

@Configuration
@EnableCaching
public class AppConfig {
    @Bean
    public CacheManager cacheManager() { ...}

    ...
}

那麼,將標準註解的支援引入混合中需要什麼? 嗯,不多。 如果您還沒有在類別路徑中新增 JCache API 和 spring-context-support 模組,您就可以開始了。

現有的基礎架構實際上會尋找 JCache API 的存在,並且當與 Spring 的 JCache 支援一起找到時,它還將配置必要的基礎架構以支援標準註解。

#總結

長話短說,如果您已經在使用 Spring 的快取抽象化,並且想要嘗試標準註解,那麼只需向您的專案新增另外兩個依賴項即可開始使用。

想試試看嗎? 獲取 Spring 4.1 的 每日 SNAPSHOT 版本,並將 javax.cache:cache-api:1.0.0org.springframework:spring-context-support:4.1.0.BUILD-SNAPSHOT 依賴項新增到您的專案。 如果您需要更多詳細信息,文件也已更新。

在下一篇文章中,我將介紹支援 JSR-107 註解如何影響我們自己的支援以及其他一些與快取相關的改進。

獲取 Spring 新聞通訊

與 Spring 新聞通訊保持聯繫

訂閱

領先一步

VMware 提供培訓和認證,以加速您的進度。

了解更多

獲取支援

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援與二進位檔案,只需一個簡單的訂閱。

了解更多

近期活動

查看 Spring 社群所有即將舉辦的活動。

查看全部