Spring 3.1 M1:快取抽象

工程 | Costin Leau | 2011 年 2 月 23 日 | ...

Spring Framework 3.1 M1 中新增的主要功能之一是通用的快取抽象,用於透明地將快取應用於 Spring 應用程式。就像事務支援一樣,快取抽象允許以對程式碼影響最小的方式一致地使用各種快取解決方案。

目的

快取通常用於透過以更快的方式(例如從本地記憶體而不是網路提供資料)透明地提供頻繁訪問的資料來提高應用程式效能。你們中的許多人已經使用過快取,無論是有意還是無意:大多數 ORM/JPA 框架提供了專用的快取功能(也稱為二級快取)。然而,Spring 3.1 M1 引入了一種通用的快取機制,可以應用於任何 Java 類、方法或庫:可以將其與現有快取基礎設施結合使用,為沒有此類支援的 API(例如 JDBC)新增快取,或者僅僅為了提高慢速、耗時且佔用資源的方法的效能。

瞭解 @Cacheable@CacheEvict 和 SpEL

讓我們看看如何快取一個任意方法
@Cacheable("books")
public Book findBook(ISBN isbn) {...}

透過使用 @Cacheable 註解標記方法,我們告訴容器 findBook 方法由 books 快取條目支援。也就是說,每次呼叫該方法時,都會使用方法引數(在本例中為 isbn 引數)作為鍵執行快取查詢。如果找到值,將返回該值並跳過方法執行。但是,如果未找到鍵,則照常執行該方法,並將其結果儲存在快取中,以便下次呼叫該方法時,無需實際執行(昂貴或緩慢的)方法即可返回結果。

在實踐中,並非所有方法都只有一個引數,或者更糟的是,引數不適合作為快取鍵 - 例如,請看上面方法的一個變體

public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

在這種情況下,可以使用 Spring 3 Spring Expression Language 或 SpEL 來挑選合適的引數,遍歷物件樹

// use property 'rawNumber' on isbn argument as key
@Cacheable(value="book", key="#isbn.rawNumber")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

或者即時計算鍵,甚至呼叫任意方法而無需編寫任何程式碼

// get the key by calling someType#hash(isbn)
@Cacheable(value="book", key="T(someType).hash(#isbn)")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

此外,可以指定何時或是否應該發生快取:是應該檢查快取還是完全忽略快取並正常執行方法。由開發人員決定標準是什麼:可以是鍵的大小或型別,也可以是一天中的時間或任意方法的結果:SpEL 支援所有這些

// cache only names shorter then 32 chars
@Cacheable(value="book", condition="#name.length < 32")
public Book findBook(String name)
// do not cache on weekends
@Cacheable(value="book", condition="!T(TimeUtils).isWeekend()")
public Book findBook(String name)

快取抽象還透過 @CacheEvict 註解支援驅逐快取條目或整個快取。要在快取失效時(例如因為快取資料已更新)驅逐快取,可以使用以下方式

// evict all cache entries
@CacheEvict(value = "books", allEntries=true)
public void loadBooks(InputStream batch)

一旦註解就位,只需一行(如果算上 schema 宣告,就是三行)即可簡單地“啟用”快取功能

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:cache="http://www.springframework.org/schema/cache"
   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
  
  <cache:annotation-driven />
  ...
</beans>

就像其他 annotation-driven 元素一樣,使用的快取採用其最簡單的預設形式,但可用於在快取類的代理和位元組碼織入之間進行選擇,或注入所需的快取實現。

宣告快取實現

到目前為止,我們討論了快取抽象的宣告性方面:如何根據 POJO 新增和移除快取中的資料。但是可以使用哪些底層快取實現呢?Spring 開箱即用地提供了與 ehcache 和 JDK ConcurrentHashMap 的整合,這對於小型、非分散式環境或測試非常有用
<!-- generic cache manager -->
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
  <property name="caches">
    <set>
      <bean class="org.springframework.cache.concurrent.ConcurrentCacheFactoryBean" p:name="default"/>
      <bean class="org.springframework.cache.concurrent.ConcurrentCacheFactoryBean" p:name="books"/>
    </set>
  </property>
</bean>

那 [xx] 庫呢 - 它什麼時候會得到支援?

目前,我們不打算在 Spring Framework 內部支援其他快取庫,原因僅僅是因為可選項數量眾多、依賴項影響(許多庫的體積比快取抽象本身大)以及維護和許可問題。為了外掛自定義快取提供程式,我們鼓勵開發人員檢視快取 SPI 及其兩個介面:CacheManagerCache。除了開箱即用的實現之外,還可以檢視 GemFire 實現,該實現計劃在 Spring GemFire 的下一個主要釋出版本中提供。

快取抽象與其他快取(例如 JPA 二級快取)相比如何?

一般來說,只要開發人員注意任何領域重疊,這兩種快取機制就可以很好地共存。以 JPA 二級快取為例,可以透過 JPA 進行資料訪問時使用它,同時使用 Spring 快取用於 Web 層或遠端服務呼叫。如果適用,可以透過在這兩種機制之間重用底層快取來更進一步。

總結

希望您喜歡這篇關於 Spring 3.1 新快取功能的快速介紹。更多資訊,請參閱相關的參考文件章節和 SPI javadoc。請務必告訴我們您的想法 - 我們很期待您的反饋!您可以透過論壇、部落格評論、我們的問題追蹤器或在 Twitter 上聯絡我本人。

訂閱 Spring 新聞通訊

保持與 Spring 新聞通訊的聯絡

訂閱

領先一步

VMware 提供培訓和認證,助您快速提升。

瞭解更多

獲取支援

Tanzu Spring 透過一個簡單的訂閱提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位制檔案。

瞭解更多

即將舉辦的活動

檢視 Spring 社群中所有即將舉辦的活動。

檢視全部