它如何適應Java生態系統
該標準由JSR107開發,作者是共同規范負責人。 JSR107包含在JSR342開發的Java EE 7中。 Java EE 7將于2012年底完成。但是與此同時,javax.cache將在Java SE 6和更高版本以及Java EE 6環境以及Spring和其他流行環境中運行。
JSR107具有草稿狀態。 目前,我們的API版本為0.3,參考實現和TCK。 本文中的代碼示例對此版本適用。
采用
作為專家組的活躍成員或對實施規范感興趣的供應商是:
- 兵馬俑– Ehcache
- Oracle –一致性
- JBoss – Infinispan
- IBM – ExtemeScale
- SpringSource – Gemfire
- 電網增益
- 最高溫度
- Google App Engine Java
Terracotta將為Ehcache發布一個模塊,使其與最終草案一致,然后在最終版本需要時對其進行更新。
特征
從設計的角度來看,基本概念是CacheManager,用于保存和控制Cache的集合。 緩存具有條目。 基本的API可以像地圖一樣具有以下附加功能:
- 原子操作,類似于java.util.ConcurrentMap
- 直讀緩存
- 直寫式緩存
- 緩存事件監聽器
- 統計
- 交易,包括所有隔離級別
- 緩存注釋
- 具有定義的鍵和值類型的通用緩存
- 按引用定義存儲(僅適用于堆緩存)和按值存儲
可選功能
我們沒有采用針對不同用戶群體(例如Java SE和Spring / EE)的規范,而是采用了不同的方法。
首先,對于Java SE樣式緩存,沒有依賴性。 對于可能要使用批注和/或事務的Spring / EE,這些框架將滿足相關性。
其次,我們通過ServiceProvider.isSupported(OptionalFeature功能)具有功能API,因此您可以在運行時確定實現的功能。 可選功能包括:
- storeByReference-storeByValue是默認值
- 交易性的
- 注解
這使得實現有可能在不必支持所有功能的情況下支持規范,并允許最終用戶和框架發現功能是什么,以便他們可以動態配置適當的用法。
適用于獨立和分布式緩存
盡管該規范沒有規定特定的分布式緩存拓撲,但是可以意識到緩存很可能是分布式的。 我們有一個API涵蓋了這兩種用法,但它對分布式問題很敏感。 例如,CacheEntryListener具有偵聽事件的NotificationScope,因此可以將事件限制為本地傳遞。 我們沒有像keySet()和values()這樣的網絡成本高的映射方法。 而且,我們通常更喜歡零或低成本回報類型。 因此,雖然Map具有V put(K鍵,V值),但是javax.cache.Cache具有void put(K鍵,V值)。
類加載
緩存包含由多個線程共享的數據,這些線程本身可能正在一個JVM中的不同容器應用程序或OSGi捆綁軟件中運行,并且可能分布在集群中的多個JVM中。 這使類加載變得棘手。
我們已經解決了這個問題。 創建CacheManager時,可以指定類加載器。 如果未指定,則實現將提供默認值。 無論哪種方式,對象反序列化都將使用CacheManager的類加載器。
與使用后備方法的Ehcache這樣的緩存所采用的方法相比,這是一個很大的改進。 首先使用線程的上下文類加載器,然后失敗,然后嘗試另一個類加載器。 可以使它在大多數情況下都有效,但會遇到一些麻煩,并且因實現方式而有很大差異。
獲取代碼
該規范位于Maven中心。 Maven代碼段是:
<dependency><groupId>javax.cache</groupId><artifactId>cache-api</artifactId><version>0.3</version>
</dependency>
庫克API之旅
創建一個CacheManager
我們支持Java 6 java.util.ServiceLoader創建方法。 它將自動檢測您的類路徑中的緩存實現。 然后,使用以下命令創建一個CacheManager:
CacheManager cacheManager = Caching.getCacheManager();
它返回一個名為“ __default__”的單例CacheManager。 后續調用返回相同的CacheManager。
CacheManager可以在其中配置名稱和類加載器。
CacheManager cacheManager =Caching.getCacheManager("app1", Thread.currentThread().getContextClassLoader());
實現也可能支持直接創建新的功能,以實現最大的靈活性:
CacheManager cacheManager =new RICacheManager("app1", Thread.currentThread().getContextClassLoader());
或做同樣的事情而不在任何特定實現上增加編譯時間依賴項:
String className = "javax.cache.implementation.RIServiceProvider";
Class<ServiceProvider> clazz =(Class<ServiceProvider>)Class.forName(className);
ServiceProvider provider = clazz.newInstance();
return provider.createCacheManager(Thread.currentThread().getContextClassLoader(), "app1");
我們希望實現具有自己的知名配置文件,這些文件將用于配置CacheManager。 CacheManager的名稱可用于區分配置文件。 對于ehcache,這將是熟悉的ehcache.xml,它位于類路徑的根目錄,并帶有CacheManager名稱的連字符前綴。 因此,默認的CacheManager將僅是ehcache.xml,而“ myCacheManager”將是app1-ehcache.xml。
創建一個緩存
該API支持以編程方式創建緩存。 這補充了通常由聲明式配置緩存的約定,這些約定留給每個供應商。
以編程方式配置名為“ testCache”的緩存,該緩存設置為可讀取
cacheManager = getCacheManager();
CacheConfiguration cacheConfiguration = cacheManager.createCacheConfiguration();
cacheConfiguration.setReadThrough(true);
Cache testCache = cacheManager.createCacheBuilder("testCache").setCacheConfiguration(cacheConfiguration).build();
獲取對緩存的引用
您可以從CacheManager獲得緩存。 獲取名為“ testCache”的緩存:
Cache<Integer, Date> cache = cacheManager.getCache("testCache");
基本緩存操作
放入緩存:
Cache<Integer, Date> cache = cacheManager.getCache(cacheName);
Date value1 = new Date();
Integer key = 1;
cache.put(key, value1);
要從緩存中獲取:
Cache<Integer, Date> cache =cacheManager.getCache(cacheName);
Date value2 = cache.get(key);
要從緩存中刪除:
Cache<Integer, Date> cache =cacheManager.getCache(cacheName);
Integer key = 1;
cache.remove(key);
注解
JSR107引入了一組標準化的緩存注釋,它們對在依賴項注入容器中運行的帶注釋的類進行方法級別的緩存攔截。 緩存注釋正變得越來越流行,從Spring的Ehcache注釋開始,然后影響了Spring 3的緩存注釋。
JSR107批注涵蓋了最常見的緩存操作,包括:
- @CacheResult –使用緩存
- @CachePut –放入緩存
- @CacheRemoveEntry –從緩存中刪除單個條目
- @CacheRemoveAll –從緩存中刪除所有條目
當可以輸入所需的高速緩存名稱,鍵和值時,它們不是必需的。 有關詳細信息,請參見JavaDoc。 為了更好地控制,您可以指定所有這些以及更多。 在以下示例中,將cacheName屬性指定為“ domainCache”,將index指定為鍵,將domain指定為值。
public class DomainDao {@CachePut(cacheName="domainCache")public void updateDomain(String domainId, @CacheKeyParam int index,@CacheValue Domain domain) {...}
}
參考實現包括Spring和CDI的實現。 CDI是Java EE 6中引入的標準化容器驅動的注入。該實現已很好地模塊化以實現重用,并使用Apache許可證,因此,我們希望多個開源緩存可以重用它們。 盡管我們尚未完成Guice的實現,但這很容易做到。
注釋示例
此示例說明如何使用注釋使高速緩存與基礎數據結構(在本例中為Blog Manager)保持同步,以及如何使用高速緩存來加快響應(通過@CacheResult完成)
public class BlogManager {@CacheResult(cacheName="blogManager")public Blog getBlogEntry(String title) {...}@CacheRemoveEntry(cacheName="blogManager")public void removeBlogEntry(String title) {...}@CacheRemoveAll(cacheName="blogManager")public void removeAllBlogs() {...}@CachePut(cacheName="blogManager")public void createEntry(@CacheKeyParam String title, @CacheValue Blog blog) {...}@CacheResult(cacheName="blogManager")public Blog getEntryCached(String randomArg, @CacheKeyParam String title){...}}
接線彈簧
對于Spring,關鍵是以下配置行,該行將緩存注釋攔截器添加到Spring上下文中:
<jcache-spring:annotation-driven proxy-target-class="true"/>
一個完整的例子是:
<beans><context:annotation-config/><jcache-spring:annotation-driven proxy-target-class="true"/><bean id="cacheManager" factory-method="getCacheManager" />
</beans>
基于JSR107貢獻者Eric Dalquist的早期工作,Spring具有自己的緩存注釋。 這些注釋和JSR107將愉快地共存。
連接CDI
首先創建javax.cache.annotation.BeanProvider的實現,然后告訴CDI在/ META-INF / services /的類路徑中聲明一個名為javax.cache.annotation.BeanProvider的資源在哪里找到。
有關使用CDI的Weld實現的示例,請參見CDI測試工具中的CdiBeanProvider 。
進一步閱讀
要進一步閱讀,請訪問位于https://github.com/jsr107/jsr107spec的JSR主頁。
參考: javax.cache:我們的JCG合作伙伴 Greg Luck在Greg Luck的Blog上發布 的新Java緩存標準 。
- Spring 3.1緩存抽象教程
- Java EE6 CDI,命名組件和限定符
- JBoss 4.2.x Spring 3 JPA Hibernate教程
- JBoss 4.2.x Spring 3 JPA Hibernate教程第2部分
- Java教程和Android教程列表
翻譯自: https://www.javacodegeeks.com/2011/10/new-java-caching-standard-javaxcache.html