使用spring cache和ehcache之前必須瞭解的,springehcache
好長時間沒寫部落格了,真的是沒時間啊。ps:其實就是懶!!接下來幾篇要寫下緩衝,這裡主要寫下ehcache與spring整合的內容,包括aop形式的緩衝,基於註解的緩衝,頁面緩衝這三方面吧。在這之前先要瞭解下spring cache 和ehcache!!
這篇部落格http://haohaoxuexi.iteye.com/blog/2123030寫的真的特別清楚了,我這裡只是做下總結。
一.spring cache
Spring Cache是作用在方法上的,其核心思想是這樣的:當我們在調用一個緩衝方法時會把該方法參數和返回結果作為一個索引值對存放在緩衝中,等到下次利用同樣的參數來調用該方法時將不再執行該方法,而是直接從緩衝中擷取結果進行返回。所以在使用Spring Cache的時候我們要保證我們緩衝的方法對於相同的方法參數要有相同的返回結果。使用Spring Cache需要我們做兩方面的事:1.聲明某些方法使用緩衝 2.配置Spring對Cache的支援
Spring為我們提供了幾個註解來支援Spring Cache。其核心主要是@Cacheable和@CacheEvict。使用@Cacheable標記的方法在執行後Spring Cache將緩衝其返回結果,而使用@CacheEvict標記的方法會在方法執行前或者執行後移除Spring Cache中的某些元素。
這裡只介紹幾個常用的屬性。
基於註解的相關概念:
1.@Cacheable
可以標記在一個方法上,也可以標記在一個類上。當標記在一個方法上時表示該方法是支援緩衝的,當標記在一個類上時則表示該類所有的方法都是支援緩衝的。對於一個支援緩衝的方法,Spring會在其被調用後將其傳回值緩衝起來,以保證下次利用同樣的參數來執行該方法時可以直接從緩衝中擷取結果,而不需要再次執行該方法。Spring在緩衝方法的傳回值時是以索引值對進行緩衝的,值就是方法的返回結果,至於鍵的話,Spring又支援兩種策略,預設策略和自訂策略。
需要注意的是當一個支援緩衝的方法在對象內部被調用時是不會觸發緩衝功能的。@Cacheable可以指定三個屬性,value、key和condition。
2.@CachePut
在支援Spring Cache的環境下,對於使用@Cacheable標註的方法,Spring在每次執行前都會檢查Cache中是否存在相同key的緩衝元素,如果存在就不再執行該方法,而是直接從緩衝中擷取結果進行返回,否則才會執行並將返回結果存入指定的緩衝中。而@CachePut也可以聲明一個方法支援緩衝功能。與@Cacheable不同的是使用@CachePut標註的方法在執行前不會去檢查緩衝中是否存在之前執行過的結果,而是每次都會執行該方法,並將執行結果以索引值對的形式存入指定的緩衝中。
@CachePut也可以標註在類上和方法上。使用@CachePut時我們可以指定的屬性跟@Cacheable是一樣的。
3.@CacheEvict
@CacheEvict是用來標註在需要清除緩衝元素的方法或類上的。當標記在一個類上時表示其中所有的方法的執行都會觸發緩衝的清除操作。@CacheEvict可以指定的屬性有value、key、condition、allEntries和beforeInvocation。其中value、key和condition的語義與@Cacheable對應的屬性類似。即value表示清除操作是發生在哪些Cache上的(對應Cache的名稱);key表示需要清除的是哪個key,如未指定則會使用預設策略產生的key;condition表示清除操作發生的條件。
屬性一 :value
必須指定的,其表示當前方法的傳回值是會被緩衝在哪個Cache上的,對應Cache的名稱,為ehcache.xml中的<cache name="myCache"/> 。其可以是一個Cache也可以是多個Cache,當需要指定多個Cache時其是一個數組。
屬性二 :key
緩衝的Key,當我們沒有指定該屬性時,Spring將使用預設策略產生key(表示使用方法的參數類型及參數值作為key),key屬性是用來指定Spring緩衝方法的返回結果時對應的key的。該屬性支援SpringEL運算式。我們還可以自訂策略:自訂策略是指我們可以通過Spring的EL運算式來指定我們的key。這裡的EL運算式可以使用方法參數及它們對應的屬性。使用方法參數時我們可以直接使用“#參數名”或者“#p參數index”
key的建置原則有兩種:一種是預設策略,一種是自訂策略
¹預設的key建置原則是通過KeyGenerator產生的,其預設策略如下:
1.如果方法沒有參數,則使用0作為key。
2.如果只有一個參數的話則使用該參數作為key。
3.如果參數多餘一個的話則使用所有參數的hashCode作為key
²自訂策略是指我們可以通過Spring的EL運算式來指定我們的key。這裡的EL運算式可以使用方法參數及它們對應的屬性。使用方法參數時我們可以直接使用“#參數名”或者“#p參數index
屬性三 :condition
有的時候我們可能並不希望緩衝一個方法所有的返回結果。通過condition屬性可以實現這一功能。
condition屬性預設為空白,表示將緩衝所有的調用情形。其值是通過SpringEL運算式來指定的,當為true時表示進行緩衝處理;當為false時表示不進行緩衝處理,即每次調用該方法時該方法都會執行一次。如下樣本表示只有當user的id為偶數時才會進行緩衝
@Cacheable(value={"users"}, key="#user.id", condition="#user.id%2==0")
public User find(User user) {
System.out.println("find user by user " + user);
return user;
}
屬性四 :allEntries
是boolean類型,表示是否需要清除緩衝中的所有元素。預設為false,表示不需要。當指定了allEntries為true時,Spring Cache將忽略指定的key。有的時候我們需要Cache一下清除所有的元素,這比一個一個清除元素更有效率。
@CacheEvict(value="users", allEntries=true)
public void delete(Integer id) {
System.out.println("delete user by id: " + id);
}
屬性五 :beforeInvocation
清除操作預設是在對應方法成功執行之後觸發的,即方法如果因為拋出異常而未能成功返回時也不會觸發清除操作。使用beforeInvocation可以改變觸發清除操作的時間,當我們指定該屬性值為true時,Spring會在調用該方法之前清除緩衝中的指定元素。
@CacheEvict(value="users", beforeInvocation=true)
public void delete(Integer id) {
System.out.println("delete user by id: " + id);
}
注意我們也可以使用ehcache的去除策略最近使用(LRU)"策略,其它還有先入先出FIFO,最少使用LFU,較少使用LRU
基於註解配置:
配置Spring對基於註解的Cache的支援,首先我們需要在Spring的設定檔中引入cache命名空間,其次通過<cache:annotation-driven />就可以啟用Spring對基於註解的Cache的支援。
<cache:annotation-driven/>有一個mode屬性,可選值有proxy和aspectj。預設是使用proxy。當mode為proxy時,只有緩衝方法在外部被調用的時候Spring Cache才會發生作用,這也就意味著如果一個緩衝方法在其聲明對象內部被調用時Spring Cache是不會發生作用的。而mode為aspectj時就不會有這種問題。另外使用proxy時,只有public方法上的@Cacheable等標註才會起作用,如果需要非public方法上的方法也可以使用Spring Cache時把mode設定為aspectj。此外,<cache:annotation-driven/>還可以指定一個proxy-target-class屬性,表示是否要代理class,預設為false。我們前面提到的@Cacheable、@cacheEvict等也可以標註在介面上,這對於基於介面的代理來說是沒有什麼問題的,但是需要注意的是當我們設定proxy-target-class為true或者mode為aspectj時,是直接基於class進行操作的,定義在介面上的@Cacheable等Cache註解不會被識別到,那對應的Spring Cache也不會起作用了。
需要注意的是<cache:annotation-driven/>只會去尋找定義在同一個ApplicationContext下的@Cacheable等緩衝註解。
基於XML配置:
1 <cache:advice id="cacheAdvice" cache-manager="cacheManager"> 2 3 <cache:caching cache="users"> 4 5 <cache:cacheable method="findById" key="#p0"/> 6 7 <cache:cacheable method="find" key="#user.id"/> 8 9 <cache:cache-evict method="deleteAll" all-entries="true"/>10 11 </cache:caching>12 13 </cache:advice>
上面配置定義了一個名為cacheAdvice的cache:advice,其中指定了將緩衝findById方法和find方法到名為users的緩衝中。這裡的方法還可以使用萬用字元“*”,比如“find*”表示任何以“find”開始的方法。有了cache:advice之後,我們還需要引入aop命名空間,然後通過aop:config指定定義好的cacheAdvice要應用在哪些pointcut上。如:
1 <aop:config proxy-target-class="false">2 3 <aop:advisor advice-ref="cacheAdvice" pointcut="execution(* com.xxx.UserService.*(..))"/>4 5 </aop:config>
二.EhCache 是一個純Java的進程內緩衝架構,具有快速、精乾等特點。
ehcache官網:http://www.ehcache.org/ 可以下載文檔看看,裡面寫的很清楚。
主要的特性有:1. 快速2. 簡單3. 多種緩衝策略4. 快取資料有兩級:記憶體和磁碟,因此無需擔心容量問題5. 快取資料會在虛擬機器重啟的過程中寫入磁碟6. 可以通過RMI、可插入API等方式進行分布式緩衝7. 具有緩衝和緩衝管理器的偵聽介面8. 支援多緩衝管理器執行個體,以及一個執行個體的多個快取區域9. 提供Hibernate的緩衝實現 ehcache.xml:裡面的注釋寫的很清楚了。
<diskStore> : 當記憶體緩衝中對象數量超過maxElementsInMemory時,將緩衝對象寫到磁碟緩衝中(需對象實現序列化介面)
<diskStore path=""> : 用來配置磁碟緩衝使用的實體路徑,Ehcache磁碟緩衝使用的檔案尾碼名是*.data和*.index
name : "緩衝名稱,cache的唯一標識(ehcache會把這個cache放到HashMap裡)
maxElementsInMemory : 緩衝最大個數。
eternal="false" : 對象是否永久有效,一但設定了,timeout將不起作用。 (必須設定)
maxEntriesLocalHeap="1000" : 堆記憶體中最大緩衝對象數,0沒有限制(必須設定)
maxEntriesLocalDisk= "1000" : 硬碟最大緩衝個數。
overflowToDisk="false" : 當緩衝達到maxElementsInMemory值是,是否允許溢出到磁碟(必須設定)(記憶體不足時,是否啟用磁碟緩衝。)
diskSpoolBufferSizeMB : 這個參數設定DiskStore(磁碟緩衝)的緩衝區大小。預設是30MB。每個Cache都應該有自己的一個緩衝區。
diskPersistent="false" : 磁碟緩衝在JVM重新啟動時是否保持(預設為false)
timeToIdleSeconds="0" : 導致元素到期的訪問間隔(秒為單位),即當緩衝閑置n秒後銷毀。 當eternal為false時,這個屬性才有效,0表示可以永遠空閑,預設為0
timeToLiveSeconds="600" : 元素在緩衝裡存在的時間(秒為單位),即當緩衝存活n秒後銷毀. 0 表示永遠存在不到期
memoryStoreEvictionPolicy="LFU" : 當達到maxElementsInMemory時,如何強制進行驅逐預設使用"最近使用(LRU)"策略,其它還有先入先出FIFO,最少使用LFU,較少使用LRU
diskExpiryThreadIntervalSeconds :磁碟失效線程已耗用時間間隔,預設是120秒。
clearOnFlush : 記憶體數量最大時是否清除。
<?xml version="1.0" encoding="UTF-8"?><ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true" monitoring="autodetect" dynamicConfig="true"> <diskStore path="java.io.tmpdir"/> <defaultCache maxEntriesLocalHeap="10000" eternal="false" overflowToDisk="false" timeToIdleSeconds="120" timeToLiveSeconds="120" diskSpoolBufferSizeMB="30" maxEntriesLocalDisk="10000000" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"> <persistence strategy="localTempSwap"/> </defaultCache> <cache name="myCache" maxEntriesLocalHeap="10000" maxEntriesLocalDisk="1000" eternal="false" diskSpoolBufferSizeMB="30" timeToIdleSeconds="300" timeToLiveSeconds="600" memoryStoreEvictionPolicy="LFU" transactionalMode="off"> <persistence strategy="localTempSwap"/> </cache> </ehcache>
好了,這裡只是介紹下Spring cache和ehcache的基礎,下一篇我會做下執行個體,基於AOP的緩衝實現,基於註解的緩衝實現,還有對頁面實現緩衝。如有寫的不好,請大家指正哈!!