保持領先
VMware 提供培訓和認證,助您加速進步。
瞭解更多Spring 的快取抽象自 Spring 3.1 起可用,是時候對其多加關注了。在本文中,我想向您介紹該領域的主要改進,即 JCache (JSR-107) 註解支援。
您可能聽說過,JSR-107 最終確定,距離最初的提案已有 13 年。對於熟悉 Spring 快取註解的人來說,下表描述了 Spring 註解與 JSR-107 對應註解之間的對映關係
Spring | JSR-107 |
---|---|
@Cacheable |
@CacheResult |
@CachePut |
@CachePut |
@CacheEvict |
@CacheRemove |
@CacheEvict(allEntries=true) |
@CacheRemoveAll |
讓我們先來看看每個註解並描述它們的用法。這將有助於更好地理解它們在您習慣使用的 Spring 註解基礎上提供了哪些支援,以及更重要的是這些註解帶來的**新**特性。
`@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` 確定。顯而易見的預設值是分別基於 `cacheName` 和 `exceptionCacheName` 屬性解析要使用的快取。但是,也可以自定義每次操作使用的工廠。
@CacheResult(cacheName = "books", cacheResolverFactory = MyFactory.class)
public Book findBook(@CacheKey ISBN isbn) { ... }
最後,`@CacheResult` 有一個 `skipGet` 屬性,啟用後無論快取狀態如何,都會*始終*呼叫該方法。這實際上與我們自己使用 `@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 操作發生。
最後,可以控制快取是在被註解方法呼叫之前還是之後更新。當然,如果在之前更新,則不會進行異常處理。
它們分別與 `@CacheEvict` 和 `@CacheEvict(allEntries = true)` 非常相似。`@CacheRemove` 有特殊的異常處理機制,如果被註解方法丟擲的異常與註解上指定的過濾器匹配,則阻止逐出(eviction)操作。
`@CacheDefaults` 是一個類級別的註解,允許您在類上定義的任何快取操作中*共享*通用設定。這些設定包括
在下面的示例中,任何與快取相關的操作都將使用 `books` 快取
@CacheDefaults(cacheName = "books")
public class BookRepositoryImpl implements BookRepository {
@CacheResult
public Book findBook(@CacheKey ISBN isbn) { ... }
}
JCache 支援的實現使用了我們自己的 `Cache` 和 `CacheManager` 抽象,這意味著您可以使用現有的 `CacheManager` 基礎設施,同時使用標準註解!
要啟用 Spring 快取註解的支援,您習慣使用 `@EnableCaching` 或 `
@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.0` 和 `org.springframework:spring-context-support:4.1.0.BUILD-SNAPSHOT` 依賴項新增到您的專案中。文件也已更新,以防您需要更多詳情。
在下一篇文章中,我將介紹支援 JSR-107 註解如何影響我們自己的支援以及其他一些與快取相關的改進。