一. 概述JCachehtml
Java臨時緩存API(JSR-107),也被稱爲JCache,它是一個規範在javax.cache.API中定義的。該規範是在Java Community Process下開發的,它的目的是爲java應用程序提供一個標準的緩存概念和機制。java
這套API用起來很方便,它被設計成緩存標準而且是平臺無關的,它消除了過去不一樣供應商之間API是不一樣的,這致使開發人員堅持使用他們已經使用的專有API,而不是研究新的API,由於研究其餘產品的門檻過高了。編程
做爲應用程序開發人員,您能夠很容易地使用來自某個供應商的JCache API開發應用程序,若是您願意,能夠嘗試使用其餘供應商的JCache實現,而不須要更改應用程序的任何一行代碼。您所要作的就是使用所選供應商的JCache緩存庫。這意味着您能夠避免在應用程序中爲了嘗試新的緩存解決方案而重寫大量與緩存相關的代碼。api
二. 使用Ehcache爲JCache提供實現緩存
爲了在應用程序中使用JCache的API,你須要下面的兩個jar包:dom
你可使用JCacheAPI去開發一個完整的應用,不須要調用任何Ehcache的API。ide
三. 開始使用Ehcache和JCacheui
JCache規範除了定義Cache接口,還定義了CachingProvider和CacheManager規範。應用程序須要使用CacheManager去建立/獲取一個cache,一樣的使用CachingProvider去獲取/訪問CacheManager.atom
下面有個代碼樣例顯示了基本JCache配置的API:spa
CachingProvider provider = Caching.getCachingProvider(); (1) CacheManager cacheManager = provider.getCacheManager(); (2) MutableConfiguration<Long, String> configuration = new MutableConfiguration<Long, String>() (3) .setTypes(Long.class, String.class) (4) .setStoreByValue(false) (5) .setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(Duration.ONE_MINUTE)); (6) Cache<Long, String> cache = cacheManager.createCache("jCache", configuration); (7) cache.put(1L, "one"); (8) String value = cache.get(1L);(9)
(1). 從應用程序的classpath中得到一個默認的CachingProvider實現。當classpath中只有一個實現時這個方法才能夠正常使用。若是classpath中有多個實現,那麼使用全限定名org.ehcache.jsr107.EhcacheCachingProvider去獲取Ehcache的實現。你能夠經過使用靜態方法Caching.getCachingProvider(String)來實現這一點。
(2). 經過Provider來獲取默認的CacheManager
(3). 使用MutableConfiguration建立一個cache配置
(4). 設置key-type和value-type
(5). 設置經過引用存儲cache entries
(6). 設置過時時間爲從建立的那一刻起以後的一分鐘
(7). 使用CacheManager和第三步建立的configuration,建立一個名爲JCache的cache
(8). 向cache中存入一些數據
(9). 從cache中獲取數據
四. 集成JCache和Ehcache的配置
正如前面提到的,JCache提供了一組最小的配置,對於內存緩存很是理想。可是Ehcache原生api支持複雜得多的拓撲,而且提供了更多的特性。有時,應用程序開發人員可能但願配置比JCache MutableConfiguration容許的緩存複雜得多的緩存(就拓撲或特性而言),同時仍然可以使用JCache緩存的api。因此Ehcache提供了幾種實現此目的的方法,以下面的部分所述。
1. 經過JCache配置訪問底層的Ehcache配置
當你使用CacheManager和MutableConfiguration建立Cache,換句話說只是用JCache類型時,你仍然能夠訪問底層的Ehcache CacheRuntimeConfiguration:
MutableConfiguration<Long, String> configuration = new MutableConfiguration<>(); configuration.setTypes(Long.class, String.class); Cache<Long, String> cache = cacheManager.createCache("someCache", configuration);(1) CompleteConfiguration<Long, String> completeConfiguration = cache.getConfiguration(CompleteConfiguration.class); (2) Eh107Configuration<Long, String> eh107Configuration = cache.getConfiguration(Eh107Configuration.class); (3) CacheRuntimeConfiguration<Long, String> runtimeConfiguration = eh107Configuration.unwrap(CacheRuntimeConfiguration.class); (4)
(1). 使用JCache規範中的MutableConfiuration接口建立JCache cache
(2). 獲取CompleteConfiguration
(3). 獲取鏈接Ehcache和JCache的配置橋
(4). 換成CacheRuntimeConfiguration類型
2. 使用Ehcache API構建JCache配置
若是你須要在CacheManager級別配置,就像持久化目錄那樣,你須要使用特定的API,你能夠像下面這麼作:
CachingProvider cachingProvider = Caching.getCachingProvider(); EhcacheCachingProvider ehcacheProvider = (EhcacheCachingProvider) cachingProvider; (1) DefaultConfiguration configuration = new DefaultConfiguration(ehcacheProvider.getDefaultClassLoader(), new DefaultPersistenceConfiguration(getPersistenceDirectory())); (2) CacheManager cacheManager = ehcacheProvider.getCacheManager(ehcacheProvider.getDefaultURI(), configuration); (3)
(1). 轉換CachingProvider爲Ehcache指定的實現org.ehcache.jsr107.EhcacheCachingProvider
(2). 使用指定的Ehcache DefaultConfiguration建立一個configuration並把它傳給CacheManager級別的配置中
(3). 使用參數爲Ehcache configuration的方法建立CacheManager
3. 緩存級別配置
還可使用Ehcache CacheConfiguration建立JCache緩存。當使用此機制時,沒有使用JCache complete teconfiguration,所以您不能使用它
CacheConfiguration<Long, String> cacheConfiguration = CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class, ResourcePoolsBuilder.heap(10)).build(); (1) Cache<Long, String> cache = cacheManager.createCache("myCache", Eh107Configuration.fromEhcacheCacheConfiguration(cacheConfiguration)); (2) Eh107Configuration<Long, String> configuration = cache.getConfiguration(Eh107Configuration.class); configuration.unwrap(CacheConfiguration.class); (3) configuration.unwrap(CacheRuntimeConfiguration.class); (4) try { cache.getConfiguration(CompleteConfiguration.class); (5) throw new AssertionError("IllegalArgumentException expected"); } catch (IllegalArgumentException iaex) { // Expected }
(1). 你可使用象上面使用的構建器或者使用XML配置來建立Ehcache CacheConfiguration
(2). 經過包裝Ehcache配置得到JCache配置
(3). 獲取Ehcache CacheConfiguration
(4). 獲取運行時配置
(5). 在這個上下文中沒有JCache CompleteConfiguration能夠得到
4. 使用Ehcache XML配置構建JCache配置
JCache緩存上擁有完整的Ehcache配置選項的另外一種方法是使用基於xml的配置,有關用XML配置緩存的更多細節,請參閱XML文檔。下面是一個XML配置的例子:
<config xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='http://www.ehcache.org/v3' xsi:schemaLocation=" http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.0.xsd"> <cache alias="ready-cache"> <key-type>java.lang.Long</key-type> <value-type>com.pany.domain.Product</value-type> <loader-writer> <class>com.pany.ehcache.integration.ProductCacheLoaderWriter</class> </loader-writer> <heap unit="entries">100</heap> </cache> </config>
下面是如何使用JCache訪問XML配置的示例:
CachingProvider cachingProvider = Caching.getCachingProvider(); CacheManager manager = cachingProvider.getCacheManager( (1) getClass().getResource("/org/ehcache/docs/ehcache-jsr107-config.xml").toURI(), (2) getClass().getClassLoader()); (3) Cache<Long, Product> readyCache = manager.getCache("ready-cache", Long.class, Product.class); (4)
(1). 調用javax.cache.spi.CachingProvider.getCacheManager(java.net.URI, java.lang.ClassLoader)
(2). 而且傳入URI,
它解析爲Ehcache XML配置文件
(3). 第二個參數是ClassLoader,
在須要時用於加載用戶類型,Class
實例存儲在由CacheManager管理的Cache中
(4). 從CacheManager中獲取Cache
5. 使用/禁止 MBeans
當使用Ehcache XML配置時,您可能但願爲JCache緩存啓用管理或統計mbean。這使您能夠控制如下內容:
javax.cache.configuration.CompleteConfiguration.isStatisticsEnabled
javax.cache.configuration.CompleteConfiguration.isManagementEnabled
您能夠在兩個不一樣的級別上這樣作:
<config xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='http://www.ehcache.org/v3' xmlns:jsr107='http://www.ehcache.org/v3/jsr107' xsi:schemaLocation=" http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.0.xsd http://www.ehcache.org/v3/jsr107 http://www.ehcache.org/schema/ehcache-107-ext-3.0.xsd"> <service> <jsr107:defaults enable-management="true" enable-statistics="true"/> (1) </service> <cache alias="stringCache"> (2) <key-type>java.lang.String</key-type> <value-type>java.lang.String</value-type> <heap unit="entries">2000</heap> </cache> <cache alias="overrideCache"> <key-type>java.lang.String</key-type> <value-type>java.lang.String</value-type> <heap unit="entries">2000</heap> <jsr107:mbeans enable-management="false" enable-statistics="false"/> (3) </cache> <cache alias="overrideOneCache"> <key-type>java.lang.String</key-type> <value-type>java.lang.String</value-type> <heap unit="entries">2000</heap> <jsr107:mbeans enable-statistics="false"/> (4) </cache> </config>
(1). 使用JCache服務擴展,默認狀況下能夠啓用MBean
(2). 根據服務配置,緩存stringCache
將啓用這兩個MBean
(3). 緩存overrideCache
將禁用兩個MBean
(4). 緩存overrideOneCache將禁用統計MBean,而管理MBean將根據服務配置啓用
6. 使用EhcacheXML擴展來補充JCache的配置
您還能夠建立cache-templates。有關詳細信息,請參閱XML文檔的緩存模板部分。Ehcache做爲JCache的緩存的實現,提供了對常規XML配置的擴展,因此你能夠:
這個特性對於配置超出JCache規範範圍的緩存特別有用,例如爲緩存提供容量約束。爲此在XML configura中添加一個jsr107服務
<config xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='http://www.ehcache.org/v3' xmlns:jsr107='http://www.ehcache.org/v3/jsr107' xsi:schemaLocation=" http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.0.xsd http://www.ehcache.org/v3/jsr107 http://www.ehcache.org/schema/ehcache-107-ext-3.0.xsd"> (1) <service> (2) <jsr107:defaults default-template="tinyCache"> (3) <jsr107:cache name="foos" template="clientCache"/> (4) <jsr107:cache name="byRefCache" template="byRefTemplate"/> <jsr107:cache name="byValCache" template="byValueTemplate"/> <jsr107:cache name="weirdCache1" template="mixedTemplate1"/> <jsr107:cache name="weirdCache2" template="mixedTemplate2"/> </jsr107:defaults> </service> <cache-template name="clientCache"> <key-type>java.lang.String</key-type> <value-type>com.pany.domain.Client</value-type> <expiry> <ttl unit="minutes">2</ttl> </expiry> <heap unit="entries">2000</heap> </cache-template> <cache-template name="tinyCache"> <heap unit="entries">20</heap> </cache-template> <cache-template name="byRefTemplate"> <key-type copier="org.ehcache.impl.copy.IdentityCopier">java.lang.Long</key-type> <value-type copier="org.ehcache.impl.copy.IdentityCopier">com.pany.domain.Client</value-type> <heap unit="entries">10</heap> </cache-template> <cache-template name="byValueTemplate"> <key-type copier="org.ehcache.impl.copy.SerializingCopier">java.lang.Long</key-type> <value-type copier="org.ehcache.impl.copy.SerializingCopier">com.pany.domain.Client</value-type> <heap unit="entries">10</heap> </cache-template> <cache-template name="mixedTemplate1"> <key-type copier="org.ehcache.impl.copy.IdentityCopier">java.lang.Long</key-type> <value-type copier="org.ehcache.impl.copy.SerializingCopier">com.pany.domain.Client</value-type> <heap unit="entries">10</heap> </cache-template> <cache-template name="mixedTemplate2"> <key-type copier="org.ehcache.impl.copy.SerializingCopier">java.lang.Long</key-type> <value-type copier="org.ehcache.impl.copy.IdentityCopier">com.pany.domain.Client</value-type> <heap unit="entries">10</heap> </cache-template> </config>
(1). 首先,爲JCache擴展聲明一個命名空間,例如jsr107
(2). 在配置頂部的服務元素中,添加jsr107:defaults
元素
(3). 元素接受一個可選屬性default-template,該屬性引用全部javax.cache的cache-template。使用javax.cache.CacheManager.createCache在運行時緩存應用程序建立的元素。在本例中,使用的缺省Cache -template將是tinyCache,這意味着除了它們的特定配置以外,任何經過編程建立的緩存實例的容量都將限制在20個條目。
(4). 嵌套在jsr107:defaults元素中,爲給定名字的緩存添加指定的Cache -templates。例如,在運行時建立名爲foos的緩存,Ehcache將加強其配置,使其容量爲2000個條目,並確保鍵和值類型都是字符串。
使用上面的配置,您不只能夠補充並且能夠覆蓋jcache建立的緩存的配置,而無需修改應用程序代碼
MutableConfiguration<Long, Client> mutableConfiguration = new MutableConfiguration<>(); mutableConfiguration.setTypes(Long.class, Client.class); (1) Cache<Long, Client> anyCache = manager.createCache("anyCache", mutableConfiguration); (2) CacheRuntimeConfiguration<Long, Client> ehcacheConfig = (CacheRuntimeConfiguration<Long, Client>)anyCache.getConfiguration( Eh107Configuration.class).unwrap(CacheRuntimeConfiguration.class); (3) ehcacheConfig.getResourcePools().getPoolForResource(ResourceType.Core.HEAP).getSize(); (4) Cache<Long, Client> anotherCache = manager.createCache("byRefCache", mutableConfiguration); assertFalse(anotherCache.getConfiguration(Configuration.class).isStoreByValue()); (5) MutableConfiguration<String, Client> otherConfiguration = new MutableConfiguration<>(); otherConfiguration.setTypes(String.class, Client.class); otherConfiguration.setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(Duration.ONE_MINUTE)); (6) Cache<String, Client> foosCache = manager.createCache("foos", otherConfiguration);(7) CacheRuntimeConfiguration<Long, Client> foosEhcacheConfig = (CacheRuntimeConfiguration<Long, Client>)foosCache.getConfiguration( Eh107Configuration.class).unwrap(CacheRuntimeConfiguration.class); Client client1 = new Client("client1", 1); foosEhcacheConfig.getExpiryPolicy().getExpiryForCreation(42L, client1).toMinutes(); (8) CompleteConfiguration<String, String> foosConfig = foosCache.getConfiguration(CompleteConfiguration.class); try { final Factory<ExpiryPolicy> expiryPolicyFactory = foosConfig.getExpiryPolicyFactory(); ExpiryPolicy expiryPolicy = expiryPolicyFactory.create(); (9) throw new AssertionError("Expected UnsupportedOperationException"); } catch (UnsupportedOperationException e) { // Expected }
(1). 假設現有的JCache配置代碼,默認狀況下是按值存儲的
(2). 建立JCache緩存
(3). 若是您要訪問Ehcache RuntimeConfiguration
(4). 您能夠驗證配置的模板容量是否應用於緩存,並在這裏返回20
(5). 緩存模板將覆蓋JCache的按值存儲配置到按引用存儲,由於用於建立緩存的byRefTemplate是使用IdentityCopier顯式配置的。
(6). 模板還將覆蓋JCache配置,在本例中使用的配置是Time to Live (TTL) 1分鐘
(7). 建立一個緩存,其中模板將TTL設置爲2分鐘
(8). 咱們確實能夠驗證模板中提供的配置是否已被應用;持續時間爲2分鐘,而不是1分鐘
(9). 這樣作的一個缺點是,當得到CompleteConfiguration時,您再也不可以從JCache訪問工廠
五. Ehcache和經過JCache使用的Ehcache默認行爲的差別
使用Ehcache和經過JCache使用的Ehcache在默認行爲上並不老是一致的。雖然Ehcache能夠按照JCache指定的方式運行,但這取決於使用的配置機制,您可能會看到缺省值的差別。
按引用調用或傳遞的
Ehcache和Ehcache經過JCache在僅支持堆緩存的默認模式上存在分歧。
使用JCache配置Ehcache
除非您調用mutableconimage.setstorebyvalue (boolean),默認值爲true。這意味着在使用Ehcache時,只能使用可序列化的鍵和值。
這將觸發使用serializing copiers ,並從默認的序列化器中選擇適當的序列化器。
使用本地XML或代碼配置Ehcache
Heap only: 當僅使用堆緩存時,默認值爲by-reference,除非配置了Copier。
其餘分層配置: 當使用任何其餘層時,因爲序列化起做用,默認是按值進行的。
有關信息,請參閱序列化器和複印機部分。
Cache-through和比較交換操做
Ehcache和Ehcache經過JCache對緩存加載器在比較和交換操做中的做用存在不一樣
經過JCache使用Ehcache的行爲
當使用比較和交換操做(如putIfAbsent(K, V))時,若是緩存沒有映射,則不會使用緩存加載器。若是putIfAbsent(K, V)成功,那麼緩存寫入器將用於將更新傳播到記錄系統。這可能致使緩存的行爲相似於INSERT,但實際上會致使底層記錄系統的盲目更新。
使用Ehcache的行爲
CacheLoaderWriter將始終用於加載缺乏的映射並寫更新。這使得cache-through中的putIfAbsent(K, V)能夠做爲記錄系統上的INSERT操做。
若是您須要經過JCache行爲使用Ehcache,下面顯示了相關的XML配置:
<service> <jsr107:defaults jsr-107-compliant-atomics="true"/> </service>