1.技術背景:java
系統緩存是位於應用程序與物理數據源之間,用於臨時存放複製數據的內存區域,目的是爲減小應用程序對物理數據源訪問的次數,從而提升應用程序的運行性能。緩存設想內存是有限的,緩存的時效性也是有限的,因此能夠設定內存數量的大小能夠執行失效算法,能夠在內存滿了的狀況下,按照最少訪問等算法將緩存直接移除或切換到硬盤上。web
Ehcache從Hibernate發展而來,逐漸涵蓋了Cache界的所有功能,是目前發展勢頭最好的一個項目,具備快速、簡單、低消耗、擴展性強、支持對象或序列化緩存,支持緩存或元素的失效,提供LRU、LFU和FIFO緩存策略,支持內存緩存和硬盤緩存和分佈式緩存機制等特色。其中Cache的存儲方式爲內存或磁盤(ps:無須擔憂容量問題)算法
2.EhCahe的類層次介紹:sql
主要分爲三層,最上層是CacheManager,它是操做Ehcache的入口。能夠經過CacheManager.getInstance()得到一個單子的CacheManager,或者經過CacheManager的構造函數建立一個新的CacheManager。每一個CacheManger都管理多個Cache。每一個Cache都以一種類Hash的方式,關聯多個Element。Element就是咱們用於存放緩存內容的地方。數據庫
3.環境搭建:瀏覽器
很簡單隻須要將ehcache-2.1.0-distribution.tar.gz和ehcache-web-2.0.2-distribution.tar.gz擠壓的jar包放入WEB-INF/lib下。緩存
再建立一個重要的配置文件ehcache.xml,能夠從ehcache組件包中拷貝一個,也能夠本身創建一個,須要放到classpath下,通常放於/WEB-INF/classed/ehcache.xml;具體的配置文件能夠網上搜一下服務器
4.實際運用app
一個網站的首頁估計是被訪問次數最多的,咱們能夠考慮給首頁作一個頁面緩存;框架
緩存策略:應該是某個固定時間以內不變的,好比說2分鐘更新一次,以應用結構page-filter-action-service-dao-db爲例。
位置:頁面緩存作到儘可能靠近客戶的地方,就是在page和filter之間,這樣的優勢就是第一個用戶請求後,頁面被緩存,第二個用戶在請求,走到filter這個請求就結束了,須要在走到action-service-dao-db,好處固然是服務器壓力大大下降和客戶端頁面響應速度加快。
首頁頁面緩存存活時間定爲2分鐘,也就是參數timeToLiveSeconds(緩存的存活時間)應該設置爲120,同時timeToIdleSeconds(多長時間不訪問緩存,就清楚該緩存)最好也設爲2分鐘或者小於2分鐘。
接着咱們來看一下SimplePageCachingFilter 的配置,
<filter> <filter-name>indexCacheFilterfilter-name> <filter-class> net.sf.ehcache.constructs.web.filter.SimplePageCachingFilter <filter-class> <filter> <filter-mapping> <filter-name>indexCacheFilterfilter-name> <url-pattern>*index.actionurl-pattern> <filter-mapping>
將上述代碼加入到web.xml,那麼當打開首頁時,你會發現2分鐘纔會有一堆sql語句出如今控制檯,也能夠調整爲5分鐘,總之一切盡在掌控之中。
固然,若是你像緩存首頁的部份內容時,你須要使用SimplePageFragmentCachingFilter這個filter,我看一下:
<filter> <filter-name>indexCacheFilterfilter-name> <filter-class> net.sf.ehcache.constructs.web.filter.SimplePageFragmentCachingFilter <filter-class> filter> <filter-mapping> <filter-name>indexCacheFilterfilter-name> <url-pattern>*/index_right.jsp<url-pattern> <filter-mapping>
如此咱們將jsp頁面經過jsp:include到其餘頁面,這樣就作到了頁面局部緩存的效果,這一點貌似沒有oscache的tag好用。
此外cachefilter中還有一個特性,就是gzip,也就是緩存中的元素是被壓縮過的,若是客戶端瀏覽器支持壓縮的話,filter會直接返回壓縮過的流,這樣節省了帶寬,把解壓的工做交給了客戶端瀏覽便可,固然若是客戶端不支持gzip,那麼filter會把緩存的元素拿出來解壓後在返回給客戶端瀏覽器(大多數爬蟲是不支持gzip的,因此filter也會解壓後在返回流)。
總之,Ehcache是一個很是輕量級的緩存實現,並且從1.2以後支持了集羣,並且是hibernate默認的緩存provider,本文主要介紹Ehcahe對頁面緩存的支持,可是它的功能遠不止如此,要用好緩存,對J2ee中緩存的原理、適用範圍、適用場景等等都須要比較深入的理解,這樣才能用好用對緩存。
爲了你們經過實際例子加深瞭解與場景運用,在奉獻一個實例:
*在Spring中運用EhCache
適用任意一個現有開源Cache Framework,要求能夠Cache系統中service或者DAO層的get/find等方法返回結果,若是數據更新(適用了Create/update/delete),則刷新cache中相應的內容。
根據需求,計劃適用Spring AOP+enCache來實現這個功能,採用ehCache緣由之一就是Spring提供了enCache的支持,至於爲什麼僅僅支持ehcache而不支持oscache和jbosscache就無從得知了。
AOP少不了攔截器,先建立一個實現了MethodInterceptor接口的攔截器,用來攔截Service/DAO的方法調用,攔截到方法後,搜索該方法的結果在cache中是否存在,若是存在,返回cache中結果,若是不存在返回數據庫查詢結果,並將結果返回到緩存。
public class MethodCacheInterceptor implements MethodInterceptor, InitializingBean { private static final Log logger = LogFactory.getLog(MethodCacheInterceptor.class); private Cache cache; public void setCache(Cache cache) { this.cache = cache; } public MethodCacheInterceptor() { super(); } /** * 攔截Service/DAO 的方法,並查找該結果是否存在,若是存在就返回cache 中的值, * 不然,返回數據庫查詢結果,並將查詢結果放入cache */ public Object invoke(MethodInvocation invocation) throws Throwable { String targetName = invocation.getThis().getClass().getName(); String methodName = invocation.getMethod().getName(); Object[] arguments = invocation.getArguments(); Object result; logger.debug("Find object from cache is " + cache.getName()); String cacheKey = getCacheKey(targetName, methodName, arguments); Element element = cache.get(cacheKey); Page 13 of 26 if (element == null) { logger.debug("Hold up method , Get method result and create cache........!"); result = invocation.proceed(); element = new Element(cacheKey, (Serializable) result); cache.put(element); } return element.getValue(); } /** * 得到cache key 的方法,cache key 是Cache 中一個Element 的惟一標識 * cache key 包括包名+類名+方法名,如com.co.cache.service.UserServiceImpl.getAllUser */ private String getCacheKey(String targetName, String methodName, Object[] arguments) { StringBuffer sb = new StringBuffer(); sb.append(targetName).append(".").append(methodName); if ((arguments != null) && (arguments.length != 0)) { for (int i = 0; i < arguments.length; i++) { sb.append(".").append(arguments[i]); } } return sb.toString(); } /** * implement InitializingBean,檢查cache 是否爲空 */ public void afterPropertiesSet() throws Exception { Assert.notNull(cache, "Need a cache. Please use setCache(Cache) create it."); } }
上面的代碼能夠看到,在方法invoke中,完成了搜索cache/新建cache的功能
隨後,再創建一個攔截器MethodCacheAfterAdvice,做用是在用戶進行create/update/delete操做時來刷新、remove相關cache內容,這個攔截器須要實現AfterRetruningAdvice接口,將會在所攔截的方法執行後執行在afterReturning(object arg0,Method arg1,Object[] arg2,object arg3)方法中所預約的操做
public class MethodCacheAfterAdvice implements AfterReturningAdvice, InitializingBean { private static final Log logger = LogFactory.getLog(MethodCacheAfterAdvice.class); private Cache cache; Page 15 of 26 public void setCache(Cache cache) { this.cache = cache; } public MethodCacheAfterAdvice() { super(); } public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable { String className = arg3.getClass().getName(); List list = cache.getKeys(); for(int i = 0;i<list.size();i++){ String cacheKey = String.valueOf(list.get(i)); if(cacheKey.startsWith(className)){ cache.remove(cacheKey); logger.debug("remove cache " + cacheKey); } } } public void afterPropertiesSet() throws Exception { Assert.notNull(cache, "Need a cache. Please use setCache(Cache) create it."); } }
該方法獲取目標class的全名,如:com.co.cache.test.TestServiceImpl,而後循環cache的key list,刷新/remove cache中全部和該class相關的element。
接着就是配置encache的屬性,如最大緩存數量、cache刷新的時間等等。
<ehcache> <diskStore path="c:\\myapp\\cache"/> <defaultCache maxElementsInMemory="1000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" /> <cache name="DEFAULT_CACHE" maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="300000" timeToLiveSeconds="600000" overflowToDisk="true" /> </ehcache>
這裏須要注意的是defaultCache定義了一個默認的cache,這個Cache不能刪除,不然會拋出No default cache is configured異常。另外因爲使用攔截器來刷新Cache內容,所以在定義cache生命週期時能夠定義較大的數值,timeToIdleSeconds="30000000",timeToLiveSeconds="6000000",好像還不夠大?
而後再將Cache和兩個攔截器配置到Spring的配置文件cache.xml中便可,須要建立兩個「切入點」,分別用於攔截不一樣方法名的方法。在配置application.xml而且導入cache.xml。這樣一個簡單的Spring+Encache框架就搭建完成。
因爲時間關係就介紹到這裏,之後有機會還會介紹Ehcache在分佈式集羣系統中的使用,謝謝你們。
轉自:http://blog.csdn.net/yangchao228/article/details/7027485