EHCache讲解
EHCache是來自sourceforge(http://ehcache.sourceforge.net/)的開源項目,也是純Java實現的簡單、快速的Cache組件。EHCache支持內存和磁盤的緩存,支持LRU、LFU和FIFO多種淘汰算法,支持分布式的Cache,可以作為Hibernate的緩存插件。同時它也能提供基于Filter的Cache,該Filter可以緩存響應的內容并采用Gzip壓縮提高響應速度。
1. EHCache API的基本用法
1.1 CacheManager類
作用:主要負責讀取配置文件,并根據配置文件創建和管理Cache類。默認讀取CLASSPATH下的ehcache.xml。
// 使用默認配置文件創建CacheManager CacheManager manager = CacheManager.create(); // 通過manager可以生成指定名稱的Cache對象 Cache cache = cache = manager.getCache("myCache"); // 使用manager移除指定名稱的Cache對象 manager.removeCache("myCache"); //可用來移除所有的Cache manager.removalAll(); //關閉CacheManager manager.shutdown();1.2 Cache類
//往cache中添加元素 Element element = new Element("key", "value"); cache.put(element); //從cache中取回元素 Element element = cache.get("key"); element.getValue(); //從Cache中移除一個元素 cache.remove("key");注意:對于緩存的對象必須是可序列化的。
1.3 配置文件
配置文件ehcache.xml中命名為myCache的緩存配置:
<cache name="myCache" //該名字與manager里操作的名字一樣maxElementsInMemory="10000" // 緩存中允許創建的最大對象數eternal="false" //緩存中對象是否為永久。如果是,超時設置將被忽略,對象從不過期。overflowToDisk="true" //內存不足時,是否啟用磁盤緩存timeToIdleSeconds="300" //緩存數據的鈍化時間,即在一個元素消亡之前,兩次訪問時間的最大時間間隔值。這只能在元素不是永久駐留時有效,如果該值是 0 就意味著元素可以停頓無窮長的時間。timeToLiveSeconds="600" //緩存數據的生存時間,也就是一個元素從構建到消亡的最大時間間隔值。這只能在元素不是永久駐留時有效,如果該值是0就意味著元素可以停頓無窮長的時間。memoryStoreEvictionPolicy="LFU" //緩存滿了之后的淘汰算法。LFU算法直接淘汰使用比較少的對象,在內存保留的都是一些經常訪問的對象。對于大部分網站項目,該算法比較適用。/>如果應用需要配置多個不同命名并采用不同參數的Cache,可以相應修改配置文件,增加需要的Cache配置即可。
2. 利用Spring APO整合EHCache
首先,在CLASSPATH下面放置ehcache.xml配置文件。在Spring的配置文件中先添加如下cacheManager配置:
<bean id="cacheManager1" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"><property name="configLocation"><value>classpath:ehcache.xml</value></property> </bean> // 配置myCache: <bean id="myCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean"><property name="cacheManager" ref="cacheManager1" /><property name="cacheName"><value>myCache</value> <!-- 在咖啡 --></property> </bean>接下來,寫一個實現org.aopalliance.intercept.MethodInterceptor接口的攔截器類。
有了攔截器就可以有選擇性的配置想要緩存的 bean 方法。如果被調用的方法配置為可緩存,攔截器將為該方法生成 cache key 并檢查該方法返回的結果是否已緩存。如果已緩存,就返回緩存的結果,否則再次執行被攔截的方法,并緩存結果供下次調用。具體代碼如下:
接下來,完成攔截器和Bean的配置:
<bean id="methodCacheInterceptor" class="com.xiebing.utils.interceptor.MethodCacheInterceptor"><property name="cache"><ref local="myCache" /></property> </bean> <bean id="methodCachePointCut" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"><property name="advice"><ref local="methodCacheInterceptor" /></property><property name="patterns"><list><!-- 所有以myMethod結尾的方法都會被緩存 --><value>.*myMethod</value></list></property> </bean><bean id="myServiceBean" class="com.xiebing.ehcache.spring.MyServiceBean"> </bean><bean id="myService" class="org.springframework.aop.framework.ProxyFactoryBean"><property name="target"><ref local="myServiceBean" /></property><property name="interceptorNames"><list><value>methodCachePointCut</value></list></property> </bean>使用AOP的方式極大地提高了系統的靈活性,通過修改配置文件就可以實現對方法結果的緩存,所有的對Cache的操作都封裝在了攔截器的實現中。
3. CachingFilter功能
作用:可以對HTTP響應的內容進行緩存。這種方式緩存數據的粒度比較粗,例如緩存整張頁面。
優點:使用簡單、效率高
缺點:不夠靈活,可重用程度不高。
EHCache使用SimplePageCachingFilter類實現Filter緩存。該類繼承自CachingFilter,有默認產生cache key的calculateKey()方法,該方法使用HTTP請求的URI和查詢條件來組成key。也可以自己實現一個Filter,同樣繼承CachingFilter類,然后覆寫calculateKey()方法,生成自定義的key。
有時在使用AJAX時,為保證JS請求的數據不被瀏覽器緩存,每次請求都會帶有一個隨機數參數i。如果使用SimplePageCachingFilter,那么每次生成的key都不一樣,緩存就沒有意義了。這種情況下,我們就會覆寫calculateKey()方法。
要使用SimplePageCachingFilter,首先在配置文件ehcache.xml中,增加下面的配置:
下面我們寫一個簡單的test.jsp文件進行測試,緩存后的頁面每次刷新,在600秒內顯示的時間都不會發生變化的。代碼如下:
<% out.println(new Date()); %>CachingFilter輸出的數據會根據瀏覽器發送的Accept-Encoding頭信息進行Gzip壓縮。經過測試,Gzip壓縮后的數據量是原來的1/4,速度是原來的4-5倍,所以緩存加上壓縮,效果非常明顯。
在使用Gzip壓縮時,需注意兩個問題:
1. Filter在進行Gzip壓縮時,采用系統默認編碼,對于使用GBK編碼的中文網頁來說,需要將操作系統的語言設置為:zh_CN.GBK,否則會出現亂碼的問題。
2. 默認情況下CachingFilter會根據瀏覽器發送的請求頭部所包含的Accept-Encoding參數值來判斷是否進行Gzip壓縮。雖然IE6/7瀏覽器是支持Gzip壓縮的,但是在發送請求的時候卻不帶該參數。為了對IE6/7也能進行Gzip壓縮,可以通過繼承CachingFilter,實現自己的Filter,然后在具體的實現中覆寫方法acceptsGzipEncoding。
具體實現參考:
4. EHCache在Hibernate中的使用
EHCache可以作為Hibernate的二級緩存使用。在hibernate.cfg.xml中需增加如下設置:
<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider </prop>然后在Hibernate映射文件的每個需要Cache的Domain中,加入類似如下格式信息:
<cache usage="read-write|nonstrict-read-write|read-only" />比如:
<cache usage="read-write" />最后在配置文件ehcache.xml中增加一段cache的配置,其中name為該domain的類名。
<cache name="domain.class.name" maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="300" timeToLiveSeconds="600" overflowToDisk="false" />5. EHCache的監控
對于Cache的使用,除了功能,在實際的系統運營過程中,我們會比較關注每個Cache對象占用的內存大小和Cache的命中率。有了這些數據,我們就可以對Cache的配置參數和系統的配置參數進行優化,使系統的性能達到最優。EHCache提供了方便的API供我們調用以獲取監控數據,其中主要的方法有:
//得到緩存中的對象數 cache.getSize(); //得到緩存對象占用內存的大小 cache.getMemoryStoreSize(); //得到緩存讀取的命中次數 cache.getStatistics().getCacheHits() //得到緩存讀取的錯失次數 cache.getStatistics().getCacheMisses()6. 分布式緩存
EHCache從1.2版本開始支持分布式緩存。分布式緩存主要解決集群環境中不同的服務器間的數據的同步問題。具體的配置如下:
在配置文件ehcache.xml中加入
另外,需要在每個cache屬性中加入
<cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"/>例如:
<cache name="demoCache" maxElementsInMemory="10000" eternal="true" overflowToDisk="true" ><cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"/> </cache>總結
EHCache是一個非常優秀的基于Java的Cache實現。它簡單、易用,而且功能齊全,并且非常容易與Spring、Hibernate等流行的開源框架進行整合。通過使用EHCache可以減少網站項目中數據庫服務器的訪問壓力,提高網站的訪問速度,改善用戶的體驗。
總結
- 上一篇: Java中的volatile关键字
- 下一篇: Jedis常用命令