前言
Ehcache 是一個(gè)成熟的緩存框架,你可以直接使用它來(lái)管理你的緩存。
Spring 提供了對(duì)緩存功能的抽象:即允許綁定不同的緩存解決方案(如Ehcache),但本身不直接提供緩存功能的實(shí)現(xiàn)。它支持注解方式使用緩存,非常方便。
本文先通過(guò)Ehcache獨(dú)立應(yīng)用的范例來(lái)介紹它的基本使用方法,然后再介紹與Spring整合的方法。
概述
Ehcache是什么?
EhCache 是一個(gè)純Java的進(jìn)程內(nèi)緩存框架,具有快速、精干等特點(diǎn)。它是Hibernate中的默認(rèn)緩存框架。
Ehcache已經(jīng)發(fā)布了3.1版本。但是本文的講解基于2.10.2版本。
為什么不使用最新版呢?因?yàn)镾pring4還不能直接整合Ehcache 3.x。雖然可以通過(guò)JCache間接整合,Ehcache也支持JCache,但是個(gè)人覺(jué)得不是很方便。
安裝
Ehcache
如果你的項(xiàng)目使用maven管理,添加以下依賴(lài)到你的pom.xml中。
1
2
3
4
5
6
|
< dependency > < groupId >net.sf.ehcache</ groupId > < artifactId >ehcache</ artifactId > < version >2.10.2</ version > < type >pom</ type > </ dependency > |
如果你的項(xiàng)目不使用maven管理,請(qǐng)?jiān)?Ehcache官網(wǎng)下載地址 下載jar包。
Spring
如果你的項(xiàng)目使用maven管理,添加以下依賴(lài)到你的pom.xml中。
spring-context-support
這個(gè)jar包中含有Spring對(duì)于緩存功能的抽象封裝接口。
1
2
3
4
5
|
< dependency > < groupId >org.springframework</ groupId > < artifactId >spring-context-support</ artifactId > < version >4.1.4.RELEASE</ version > </ dependency > |
Ehcache的使用
HelloWorld范例
接觸一種技術(shù)最快最直接的途徑總是一個(gè)Hello World例子,畢竟動(dòng)手實(shí)踐印象更深刻,不是嗎?
(1) 在classpath下添加ehcache.xml
添加一個(gè)名為helloworld的緩存。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
<? xml version = "1.0" encoding = "UTF-8" ?> < ehcache xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation = "http://ehcache.org/ehcache.xsd" > <!-- 磁盤(pán)緩存位置 --> < diskStore path = "java.io.tmpdir/ehcache" /> <!-- 默認(rèn)緩存 --> < 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會(huì)自動(dòng)加載classpath根目錄下名為ehcache.xml文件。
EhcacheDemo的工作步驟如下:
在EhcacheDemo中,我們引用ehcache.xml聲明的名為helloworld的緩存來(lái)創(chuàng)建Cache
對(duì)象;
然后我們用一個(gè)鍵值對(duì)來(lái)實(shí)例化Element
對(duì)象;
將Element
對(duì)象添加到Cache
;
然后用Cache
的get方法獲取Element
對(duì)象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
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基本操作
Element
、Cache
、CacheManager
是Ehcache最重要的API。
- Element:緩存的元素,它維護(hù)著一個(gè)鍵值對(duì)。
-
Cache:它是Ehcache的核心類(lèi),它有多個(gè)
Element
,并被CacheManager
管理。它實(shí)現(xiàn)了對(duì)緩存的邏輯行為。 -
CacheManager:
Cache
的容器對(duì)象,并管理著Cache
的生命周期。
創(chuàng)建CacheManager
下面的代碼列舉了創(chuàng)建CacheManager
的五種方式。
使用靜態(tài)方法create
()會(huì)以默認(rèn)配置來(lái)創(chuàng)建單例的CacheManager
實(shí)例。
newInstance()
方法是一個(gè)工廠方法,以默認(rèn)配置創(chuàng)建一個(gè)新的CacheManager
實(shí)例。
此外,newInstance()
還有幾個(gè)重載函數(shù),分別可以通過(guò)傳入String
、URL
、InputStream
參數(shù)來(lái)加載配置文件,然后創(chuàng)建CacheManager
實(shí)例。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
// 使用Ehcache默認(rèn)配置獲取單例的CacheManager實(shí)例 CacheManager.create(); String[] cacheNames = CacheManager.getInstance().getCacheNames(); // 使用Ehcache默認(rèn)配置新建一個(gè)CacheManager實(shí)例 CacheManager.newInstance(); String[] cacheNames = manager.getCacheNames(); // 使用不同的配置文件分別創(chuàng)建一個(gè)CacheManager實(shí)例 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下的配置文件創(chuàng)建CacheManager實(shí)例 URL url = getClass().getResource( "/anotherconfigurationname.xml" ); CacheManager manager = CacheManager.newInstance(url); // 基于文件流得到配置文件,并創(chuàng)建CacheManager實(shí)例 InputStream fis = new FileInputStream( new File ( "src/config/ehcache.xml" ).getAbsolutePath()); try { CacheManager manager = CacheManager.newInstance(fis); } finally { fis.close(); } |
添加緩存
需要強(qiáng)調(diào)一點(diǎn),Cache
對(duì)象在用addCache
方法添加到CacheManager
之前,是無(wú)效的。
使用CacheManager的addCache方法可以根據(jù)緩存名將ehcache.xml中聲明的cache添加到容器中;它也可以直接將Cache對(duì)象添加到緩存容器中。
Cache
有多個(gè)構(gòu)造函數(shù),提供了不同方式去加載緩存的配置參數(shù)。
有時(shí)候,你可能需要使用API來(lái)動(dòng)態(tài)的添加緩存,下面的例子就提供了這樣的范例。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
// 除了可以使用xml文件中配置的緩存,你也可以使用API動(dòng)態(tài)增刪緩存 // 添加緩存 manager.addCache(cacheName); // 使用默認(rèn)配置添加緩存 CacheManager singletonManager = CacheManager.create(); singletonManager.addCache( "testCache" ); Cache test = singletonManager.getCache( "testCache" ); // 使用自定義配置添加緩存,注意緩存未添加進(jìn)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); |
刪除緩存
刪除緩存比較簡(jiǎn)單,你只需要將指定的緩存名傳入removeCache
方法即可。
1
2
|
CacheManager singletonManager = CacheManager.create(); singletonManager.removeCache( "sampleCache1" ); |
實(shí)現(xiàn)基本緩存操作
Cache最重要的兩個(gè)方法就是put和get,分別用來(lái)添加Element和獲取Element。
Cache還提供了一系列的get、set方法來(lái)設(shè)置或獲取緩存參數(shù),這里不一一列舉,更多API操作可參考官方API開(kāi)發(fā)手冊(cè)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
/** * 測(cè)試:使用默認(rèn)配置或使用指定配置來(lái)創(chuàng)建CacheManager * * @author victor zhang */ public class CacheOperationTest { private final Logger log = LoggerFactory.getLogger(CacheOperationTest. class ); /** * 使用Ehcache默認(rèn)配置(classpath下的ehcache.xml)獲取單例的CacheManager實(shí)例 */ @Test public void operation() { CacheManager manager = CacheManager.newInstance( "src/test/resources/ehcache/ehcache.xml" ); // 獲得Cache的引用 Cache cache = manager.getCache( "userCache" ); // 將一個(gè)Element添加到Cache cache.put( new Element( "key1" , "value1" )); // 獲取Element,Element類(lèi)支持序列化,所以下面兩種方法都可以用 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的元素?cái)?shù) log.debug( "cache size:{}" , cache.getSize()); // 獲取MemoryStore的元素?cái)?shù) log.debug( "MemoryStoreSize:{}" , cache.getMemoryStoreSize()); // 獲取DiskStore的元素?cái)?shù) log.debug( "DiskStoreSize:{}" , cache.getDiskStoreSize()); // 移除Element cache.remove( "key1" ); log.debug( "cache size:{}" , cache.getSize()); // 關(guān)閉當(dāng)前CacheManager對(duì)象 manager.shutdown(); // 關(guān)閉CacheManager單例實(shí)例 CacheManager.getInstance().shutdown(); } } |
緩存配置
Ehcache支持通過(guò)xml文件和API兩種方式進(jìn)行配置。
xml方式
Ehcache的CacheManager
構(gòu)造函數(shù)或工廠方法被調(diào)用時(shí),會(huì)默認(rèn)加載classpath下名為ehcache.xml的配置文件。如果加載失敗,會(huì)加載Ehcache jar包中的ehcache-failsafe.xml文件,這個(gè)文件中含有簡(jiǎn)單的默認(rèn)配置。
ehcache.xml配置參數(shù)說(shuō)明:
- name:緩存名稱(chēng)。
- maxElementsInMemory:緩存最大個(gè)數(shù)。
- eternal:緩存中對(duì)象是否為永久的,如果是,超時(shí)設(shè)置將被忽略,對(duì)象從不過(guò)期。
- timeToIdleSeconds:置對(duì)象在失效前的允許閑置時(shí)間(單位:秒)。僅當(dāng)eternal=false對(duì)象不是永久有效時(shí)使用,可選屬性,默認(rèn)值是0,也就是可閑置時(shí)間無(wú)窮大。
- timeToLiveSeconds:緩存數(shù)據(jù)的生存時(shí)間(TTL),也就是一個(gè)元素從構(gòu)建到消亡的最大時(shí)間間隔值,這只能在元素不是永久駐留時(shí)有效,如果該值是0就意味著元素可以停頓無(wú)窮長(zhǎng)的時(shí)間。
- maxEntriesLocalDisk:當(dāng)內(nèi)存中對(duì)象數(shù)量達(dá)到maxElementsInMemory時(shí),Ehcache將會(huì)對(duì)象寫(xiě)到磁盤(pán)中。
- overflowToDisk:內(nèi)存不足時(shí),是否啟用磁盤(pán)緩存。
- diskSpoolBufferSizeMB:這個(gè)參數(shù)設(shè)置DiskStore(磁盤(pán)緩存)的緩存區(qū)大小。默認(rèn)是30MB。每個(gè)Cache都應(yīng)該有自己的一個(gè)緩沖區(qū)。
- maxElementsOnDisk:硬盤(pán)最大緩存?zhèn)€數(shù)。
- diskPersistent:是否在VM重啟時(shí)存儲(chǔ)硬盤(pán)的緩存數(shù)據(jù)。默認(rèn)值是false。
- diskExpiryThreadIntervalSeconds:磁盤(pán)失效線程運(yùn)行時(shí)間間隔,默認(rèn)是120秒。
- memoryStoreEvictionPolicy:當(dāng)達(dá)到maxElementsInMemory限制時(shí),Ehcache將會(huì)根據(jù)指定的策略去清理內(nèi)存。默認(rèn)策略是LRU(最近最少使用)。你可以設(shè)置為FIFO(先進(jìn)先出)或是LFU(較少使用)。
- clearOnFlush:內(nèi)存數(shù)量最大時(shí)是否清除。
ehcache.xml的一個(gè)范例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
<? xml version = "1.0" encoding = "UTF-8" ?> < ehcache xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation = "http://ehcache.org/ehcache.xsd" > <!-- 磁盤(pán)緩存位置 --> < diskStore path = "java.io.tmpdir/ehcache" /> <!-- 默認(rèn)緩存 --> < 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配置的參數(shù)也可以直接通過(guò)編程方式來(lái)動(dòng)態(tài)的進(jìn)行配置(dynamicConfig沒(méi)有設(shè)為false)。
1
2
3
4
5
6
|
Cache cache = manager.getCache( "sampleCache" ); CacheConfiguration config = cache.getCacheConfiguration(); config.setTimeToIdleSeconds( 60 ); config.setTimeToLiveSeconds( 120 ); config.setmaxEntriesLocalHeap( 10000 ); config.setmaxEntriesLocalDisk( 1000000 ); |
也可以通過(guò)disableDynamicFeatures()
方式關(guān)閉動(dòng)態(tài)配置開(kāi)關(guān)。配置以后你將無(wú)法再以編程方式配置參數(shù)。
1
2
|
Cache cache = manager.getCache( "sampleCache" ); cache.disableDynamicFeatures(); |
Spring整合Ehcache
Spring3.1開(kāi)始添加了對(duì)緩存的支持。和事務(wù)功能的支持方式類(lèi)似,緩存抽象允許底層使用不同的緩存解決方案來(lái)進(jìn)行整合。
Spring4.1開(kāi)始支持JSR-107注解。
注:我本人使用的Spring版本為4.1.4.RELEASE,目前Spring版本僅支持Ehcache2.5以上版本,但不支持Ehcache3。
綁定Ehcache
org.springframework.cache.ehcache.EhCacheManagerFactoryBean
這個(gè)類(lèi)的作用是加載Ehcache配置文件。
org.springframework.cache.ehcache.EhCacheCacheManager
這個(gè)類(lèi)的作用是支持net.sf.ehcache.CacheManager。
spring-ehcache.xml的配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<? 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 > <!-- 啟用緩存注解開(kāi)關(guān) --> < cache:annotation-driven cache-manager = "cacheManager" /> </ beans > |
使用Spring的緩存注解
開(kāi)啟注解
Spring為緩存功能提供了注解功能,但是你必須啟動(dòng)注解。
你有兩個(gè)選擇:
(1) 在xml中聲明
像上一節(jié)spring-ehcache.xml中的做法一樣,使用<cache:annotation-driven/>
1
|
< cache:annotation-driven cache-manager = "cacheManager" /> |
(2) 使用標(biāo)記注解
你也可以通過(guò)對(duì)一個(gè)類(lèi)進(jìn)行注解修飾的方式在這個(gè)類(lèi)中使用緩存注解。
范例如下:
1
2
3
4
|
@Configuration @EnableCaching public class AppConfig { } |
注解基本使用方法
Spring對(duì)緩存的支持類(lèi)似于對(duì)事務(wù)的支持。
首先使用注解標(biāo)記方法,相當(dāng)于定義了切點(diǎn),然后使用Aop技術(shù)在這個(gè)方法的調(diào)用前、調(diào)用后獲取方法的入?yún)⒑头祷刂担M(jìn)而實(shí)現(xiàn)了緩存的邏輯。
下面三個(gè)注解都是方法級(jí)別:
@Cacheable
表明所修飾的方法是可以緩存的:當(dāng)?shù)谝淮握{(diào)用這個(gè)方法時(shí),它的結(jié)果會(huì)被緩存下來(lái),在緩存的有效時(shí)間內(nèi),以后訪問(wèn)這個(gè)方法都直接返回緩存結(jié)果,不再執(zhí)行方法中的代碼段。
這個(gè)注解可以用condition
屬性來(lái)設(shè)置條件,如果不滿足條件,就不使用緩存能力,直接執(zhí)行方法。
可以使用key
屬性來(lái)指定key的生成規(guī)則。
@CachePut
與@Cacheable
不同,@CachePut
不僅會(huì)緩存方法的結(jié)果,還會(huì)執(zhí)行方法的代碼段。
它支持的屬性和用法都與@Cacheable
一致。
@CacheEvict
與@Cacheable
功能相反,@CacheEvict
表明所修飾的方法是用來(lái)刪除失效或無(wú)用的緩存數(shù)據(jù)。
下面是@Cacheable、@CacheEvict
和@CachePut
基本使用方法的一個(gè)集中展示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
@Service public class UserService { // @Cacheable可以設(shè)置多個(gè)緩存,形式如:@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
如果需要使用同一個(gè)緩存注解(@Cacheable、@CacheEvict或@CachePut
)多次修飾一個(gè)方法,就需要用到@Caching
。
1
2
|
@Caching (evict = { @CacheEvict ( "primary" ), @CacheEvict (cacheNames= "secondary" , key= "#p0" ) }) public Book importBooks(String deposit, Date date) |
@CacheConfig
與前面的緩存注解不同,這是一個(gè)類(lèi)級(jí)別的注解。
如果類(lèi)的所有操作都是緩存操作,你可以使用@CacheConfig
來(lái)指定類(lèi),省去一些配置。
1
2
3
4
5
|
@CacheConfig ( "books" ) public class BookRepositoryImpl implements BookRepository { @Cacheable public Book findBook(ISBN isbn) {...} } |
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。
原文鏈接:http://www.cnblogs.com/jingmoxukong/p/5975994.html