Spring整合Ehcache管理緩存(轉)

前言

Ehcache 是一個成熟的緩存框架,你能夠直接使用它來管理你的緩存。
Spring 提供了對緩存功能的抽象:即容許綁定不一樣的緩存解決方案(如Ehcache),但自己不直接提供緩存功能的實現。它支持註解方式使用緩存,很是方便。
本文先經過Ehcache獨立應用的範例來介紹它的基本使用方法,而後再介紹與Spring整合的方法。html

概述

Ehcache是什麼?
EhCache 是一個純Java的進程內緩存框架,具備快速、精幹等特色。它是Hibernate中的默認緩存框架。
Ehcache已經發布了3.1版本。可是本文的講解基於2.10.2版本。
爲何不使用最新版呢?由於Spring4還不能直接整合Ehcache 3.x。雖然能夠經過JCache間接整合,Ehcache也支持JCache,可是我的以爲不是很方便。java

安裝

Ehcache
若是你的項目使用maven管理,添加如下依賴到你的pom.xml中。git

<dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache</artifactId> <version>2.10.2</version> <type>pom</type> </dependency>

若是你的項目不使用maven管理,請在 Ehcache官網下載地址 下載jar包。github

Spring
若是你的項目使用maven管理,添加如下依賴到你的pom.xml中。
spring-context-support這個jar包中含有Spring對於緩存功能的抽象封裝接口。spring

<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>4.1.4.RELEASE</version> </dependency>

Ehcache的使用

HelloWorld範例

接觸一種技術最快最直接的途徑老是一個Hello World例子,畢竟動手實踐印象更深入,不是嗎?編程

(1) 在classpath下添加ehcache.xml
添加一個名爲helloworld的緩存。api

<?xml version="1.0" encoding="UTF-8"?> <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"> <!-- 磁盤緩存位置 --> <diskStore path="java.io.tmpdir/ehcache"/> <!-- 默認緩存 --> <defaultCache  maxEntriesLocalHeap="10000"  eternal="false"  timeToIdleSeconds="120"  timeToLiveSeconds="120"  maxEntriesLocalDisk="10000000"  diskExpiryThreadIntervalSeconds="120"  memoryStoreEvictionPolicy="LRU"/> <!-- helloworld緩存 --> <cache name="helloworld"  maxElementsInMemory="1000"  eternal="false"  timeToIdleSeconds="5"  timeToLiveSeconds="5"  overflowToDisk="false"  memoryStoreEvictionPolicy="LRU"/> </ehcache>

(2) EhcacheDemo.java
Ehcache會自動加載classpath根目錄下名爲ehcache.xml文件。
EhcacheDemo的工做步驟以下:
在EhcacheDemo中,咱們引用ehcache.xml聲明的名爲helloworld的緩存來建立Cache對象;
而後咱們用一個鍵值對來實例化Element對象;
Element對象添加到Cache
而後用Cache的get方法獲取Element對象。緩存

public class EhcacheDemo { public static void main(String[] args) throws Exception { // Create a cache manager final CacheManager cacheManager = new CacheManager(); // create the cache called "helloworld" final Cache cache = cacheManager.getCache("helloworld"); // create a key to map the data to final String key = "greeting"; // Create a data element final Element putGreeting = new Element(key, "Hello, World!"); // Put the element into the data store cache.put(putGreeting); // Retrieve the data element final Element getGreeting = cache.get(key); // Print the value System.out.println(getGreeting.getObjectValue()); } }

輸出框架

Hello, World!

Ehcache基本操做

ElementCacheCacheManager是Ehcache最重要的API。maven

  • Element:緩存的元素,它維護着一個鍵值對。
  • Cache:它是Ehcache的核心類,它有多個Element,並被CacheManager管理。它實現了對緩存的邏輯行爲。
  • CacheManager:Cache的容器對象,並管理着Cache的生命週期。

    建立CacheManager

    下面的代碼列舉了建立CacheManager的五種方式。
    使用靜態方法create()會以默認配置來建立單例的CacheManager實例。
    newInstance()方法是一個工廠方法,以默認配置建立一個新的CacheManager實例。
    此外,newInstance()還有幾個重載函數,分別能夠經過傳入StringURLInputStream參數來加載配置文件,而後建立CacheManager實例。

// 使用Ehcache默認配置獲取單例的CacheManager實例 CacheManager.create(); String[] cacheNames = CacheManager.getInstance().getCacheNames(); // 使用Ehcache默認配置新建一個CacheManager實例 CacheManager.newInstance(); String[] cacheNames = manager.getCacheNames(); // 使用不一樣的配置文件分別建立一個CacheManager實例 CacheManager manager1 = CacheManager.newInstance("src/config/ehcache1.xml"); CacheManager manager2 = CacheManager.newInstance("src/config/ehcache2.xml"); String[] cacheNamesForManager1 = manager1.getCacheNames(); String[] cacheNamesForManager2 = manager2.getCacheNames(); // 基於classpath下的配置文件建立CacheManager實例 URL url = getClass().getResource("/anotherconfigurationname.xml"); CacheManager manager = CacheManager.newInstance(url); // 基於文件流獲得配置文件,並建立CacheManager實例 InputStream fis = new FileInputStream(new File ("src/config/ehcache.xml").getAbsolutePath()); try { CacheManager manager = CacheManager.newInstance(fis); } finally { fis.close(); }

添加緩存

須要強調一點,Cache對象在用addCache方法添加到CacheManager以前,是無效的。
使用CacheManager的addCache方法能夠根據緩存名將ehcache.xml中聲明的cache添加到容器中;它也能夠直接將Cache對象添加到緩存容器中。
Cache有多個構造函數,提供了不一樣方式去加載緩存的配置參數。
有時候,你可能須要使用API來動態的添加緩存,下面的例子就提供了這樣的範例。

// 除了可使用xml文件中配置的緩存,你也可使用API動態增刪緩存 // 添加緩存 manager.addCache(cacheName); // 使用默認配置添加緩存 CacheManager singletonManager = CacheManager.create(); singletonManager.addCache("testCache"); Cache test = singletonManager.getCache("testCache"); // 使用自定義配置添加緩存,注意緩存未添加進CacheManager以前並不可用 CacheManager singletonManager = CacheManager.create(); Cache memoryOnlyCache = new Cache("testCache", 5000, false, false, 5, 2); singletonManager.addCache(memoryOnlyCache); Cache test = singletonManager.getCache("testCache"); // 使用特定的配置添加緩存 CacheManager manager = CacheManager.create(); Cache testCache = new Cache( new CacheConfiguration("testCache", maxEntriesLocalHeap) .memoryStoreEvictionPolicy(MemoryStoreEvictionPolicy.LFU) .eternal(false) .timeToLiveSeconds(60) .timeToIdleSeconds(30) .diskExpiryThreadIntervalSeconds(0) .persistence(new PersistenceConfiguration().strategy(Strategy.LOCALTEMPSWAP))); manager.addCache(testCache);

刪除緩存

刪除緩存比較簡單,你只須要將指定的緩存名傳入removeCache方法便可。

CacheManager singletonManager = CacheManager.create(); singletonManager.removeCache("sampleCache1");

實現基本緩存操做

Cache最重要的兩個方法就是put和get,分別用來添加Element和獲取Element。
Cache還提供了一系列的get、set方法來設置或獲取緩存參數,這裏不一一列舉,更多每天美劇API操做可參考官方API開發手冊

/**  * 測試:使用默認配置或使用指定配置來建立CacheManager  *  * @author victor zhang  */ public class CacheOperationTest { private final Logger log = LoggerFactory.getLogger(CacheOperationTest.class); /**  * 使用Ehcache默認配置(classpath下的ehcache.xml)獲取單例的CacheManager實例  */ @Test public void operation() { CacheManager manager = CacheManager.newInstance("src/test/resources/ehcache/ehcache.xml"); // 得到Cache的引用 Cache cache = manager.getCache("userCache"); // 將一個Element添加到Cache cache.put(new Element("key1", "value1")); // 獲取Element,Element類支持序列化,因此下面兩種方法均可以用 Element element1 = cache.get("key1"); // 獲取非序列化的值 log.debug("key:{}, value:{}", element1.getObjectKey(), element1.getObjectValue()); // 獲取序列化的值 log.debug("key:{}, value:{}", element1.getKey(), element1.getValue()); // 更新Cache中的Element cache.put(new Element("key1", "value2")); Element element2 = cache.get("key1"); log.debug("key:{}, value:{}", element2.getObjectKey(), element2.getObjectValue()); // 獲取Cache的元素數 log.debug("cache size:{}", cache.getSize()); // 獲取MemoryStore的元素數 log.debug("MemoryStoreSize:{}", cache.getMemoryStoreSize()); // 獲取DiskStore的元素數 log.debug("DiskStoreSize:{}", cache.getDiskStoreSize()); // 移除Element cache.remove("key1"); log.debug("cache size:{}", cache.getSize()); // 關閉當前CacheManager對象 manager.shutdown(); // 關閉CacheManager單例實例 CacheManager.getInstance().shutdown(); } }

緩存配置

Ehcache支持經過xml文件和API兩種方式進行配置。

xml方式

Ehcache的CacheManager構造函數或工廠方法被調用時,會默認加載classpath下名爲ehcache.xml的配置文件。若是加載失敗,會加載Ehcache jar包中的ehcache-failsafe.xml文件,這個文件中含有簡單的默認配置。
ehcache.xml配置參數說明:

  • name:緩存名稱。
  • maxElementsInMemory:緩存最大個數。
  • eternal:緩存中對象是否爲永久的,若是是,超時設置將被忽略,對象從不過時。
  • timeToIdleSeconds:置對象在失效前的容許閒置時間(單位:秒)。僅當eternal=false對象不是永久有效時使用,可選屬性,默認值是0,也就是可閒置時間無窮大。
  • timeToLiveSeconds:緩存數據的生存時間(TTL),也就是一個元素從構建到消亡的最大時間間隔值,這隻能在元素不是永久駐留時有效,若是該值是0就意味着元素能夠停頓無窮長的時間。
  • maxEntriesLocalDisk:當內存中對象數量達到maxElementsInMemory時,Ehcache將會對象寫到磁盤中。
  • overflowToDisk:內存不足時,是否啓用磁盤緩存。
  • diskSpoolBufferSizeMB:這個參數設置DiskStore(磁盤緩存)的緩存區大小。默認是30MB。每一個Cache都應該有本身的一個緩衝區。
  • maxElementsOnDisk:硬盤最大緩存個數。
  • diskPersistent:是否在VM重啓時存儲硬盤的緩存數據。默認值是false。
  • diskExpiryThreadIntervalSeconds:磁盤失效線程運行時間間隔,默認是120秒。
  • memoryStoreEvictionPolicy:當達到maxElementsInMemory限制時,Ehcache將會根據指定的策略去清理內存。默認策略是LRU(最近最少使用)。你能夠設置爲FIFO(先進先出)或是LFU(較少使用)。
  • clearOnFlush:內存數量最大時是否清除。

ehcache.xml的一個範例

<?xml version="1.0" encoding="UTF-8"?> <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"> <!-- 磁盤緩存位置 --> <diskStore path="java.io.tmpdir/ehcache"/> <!-- 默認緩存 --> <defaultCache  maxEntriesLocalHeap="10000"  eternal="false"  timeToIdleSeconds="120"  timeToLiveSeconds="120"  maxEntriesLocalDisk="10000000"  diskExpiryThreadIntervalSeconds="120"  memoryStoreEvictionPolicy="LRU"> <persistence strategy="localTempSwap"/> </defaultCache> <cache name="userCache"  maxElementsInMemory="1000"  eternal="false"  timeToIdleSeconds="3"  timeToLiveSeconds="3"  maxEntriesLocalDisk="10000000"  overflowToDisk="false"  memoryStoreEvictionPolicy="LRU"/> </ehcache>

API方式

xml配置的參數也能夠直接經過編程方式來動態的進行配置(dynamicConfig沒有設爲false)。

Cache cache = manager.getCache("sampleCache"); CacheConfiguration config = cache.getCacheConfiguration(); config.setTimeToIdleSeconds(60); config.setTimeToLiveSeconds(120); config.setmaxEntriesLocalHeap(10000); config.setmaxEntriesLocalDisk(1000000);

也能夠經過disableDynamicFeatures()方式關閉動態配置開關。配置之後你將沒法再以編程方式配置參數。

Cache cache = manager.getCache("sampleCache"); cache.disableDynamicFeatures();

Spring整合Ehcache

Spring3.1開始添加了對緩存的支持。和事務功能的支持方式相似,緩存抽象容許底層使用不一樣的緩存解決方案來進行整合。
Spring4.1開始支持JSR-107註解。
注:我本人使用的Spring版本爲4.1.4.RELEASE,目前Spring版本僅支持Ehcache2.5以上版本,但不支持Ehcache3。

綁定Ehcache

org.springframework.cache.ehcache.EhCacheManagerFactoryBean這個類的做用是加載Ehcache配置文件。
org.springframework.cache.ehcache.EhCacheCacheManager這個類的做用是支持net.sf.ehcache.CacheManager。

spring-ehcache.xml的配置

<?xml version="1.0" encoding="UTF-8"?> <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-3.0.xsd  http://www.springframework.org/schema/cache  http://www.springframework.org/schema/cache/spring-cache-3.2.xsd"> <description>ehcache緩存配置管理文件</description> <bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> <property name="configLocation" value="classpath:ehcache/ehcache.xml"/> </bean> <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"> <property name="cacheManager" ref="ehcache"/> </bean> <!-- 啓用緩存註解開關 --> <cache:annotation-driven cache-manager="cacheManager"/> </beans>

使用Spring的緩存註解

開啓註解

Spring爲緩存功能提供了註解功能,可是你必須啓動註解。
你有兩個選擇:

(1) 在xml中聲明
像上一節spring-ehcache.xml中的作法同樣,使用<cache:annotation-driven/>

<cache:annotation-driven cache-manager="cacheManager"/>

(2) 使用標記註解
你也能夠經過對一個類進行註解修飾的方式在這個類中使用緩存註解。
範例以下:

@Configuration @EnableCaching public class AppConfig { }

註解基本使用方法

Spring對緩存的支持相似於對事務的支持。
首先使用註解標記方法,至關於定義了切點,而後使用Aop技術在這個方法的調用前、調用後獲取方法的入參和返回值,進而實現了緩存的邏輯。
下面三個註解都是方法級別:

@Cacheable

代表所修飾的方法是能夠緩存的:當第一次調用這個方法時,它的結果會被緩存下來,在緩存的有效時間內,之後訪問這個方法都直接返回緩存結果,再也不執行方法中的代碼段。
這個註解能夠用condition屬性來設置條件,若是不知足條件,就不使用緩存能力,直接執行方法。
可使用key屬性來指定key的生成規則。

@CachePut

@Cacheable不一樣,@CachePut不只會緩存方法的結果,還會執行方法的代碼段。
它支持的屬性和用法都與@Cacheable一致。

@CacheEvict

@Cacheable功能相反,@CacheEvict代表所修飾的方法是用來刪除失效或無用的緩存數據。
下面是@Cacheable@CacheEvict@CachePut基本使用方法的一個集中展現:

@Service public class UserService { // @Cacheable能夠設置多個緩存,形式如:@Cacheable({"books", "isbns"}) @Cacheable({"users"}) public User findUser(User user) { return findUserInDB(user.getId()); } @Cacheable(value = "users", condition = "#user.getId() <= 2") public User findUserInLimit(User user) { return findUserInDB(user.getId()); } @CachePut(value = "users", key = "#user.getId()") public void updateUser(User user) { updateUserInDB(user); } @CacheEvict(value = "users") public void removeUser(User user) { removeUserInDB(user.getId()); } @CacheEvict(value = "users", allEntries = true) public void clear() { removeAllInDB(); } }

@Caching

若是須要使用同一個緩存註解(@Cacheable@CacheEvict@CachePut)屢次修飾一個方法,就須要用到@Caching

@Caching(evict = { @CacheEvict("primary"), @CacheEvict(cacheNames="secondary", key="#p0") }) public Book importBooks(String deposit, Date date)

@CacheConfig

與前面的緩存註解不一樣,這是一個類級別的註解。
若是類的全部操做都是緩存操做,你可使用@CacheConfig來指定類,省去一些配置。

@CacheConfig("books") public class BookRepositoryImpl implements BookRepository { @Cacheable public Book findBook(ISBN isbn) {...} }

參考

若是想參考個人完整代碼示例,請點擊這裏訪問個人github。--好看的美劇

下面是我在寫做時參考的資料或文章。
Ehcache github
Ehcache官方文檔
Ehcache詳細解讀
註釋驅動的 Spring cache 緩存介紹
Spring官方文檔4.3.3.RELEASE 第36章緩存抽象

相關文章
相關標籤/搜索