<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Ehcache學習 轉

    http://ligf06.iteye.com/blog/1710887

    5.     Spring 中運用 EHCache

    需要使用 Spring 來實現一個 Cache 簡單的解決方案,具體需求如下:使用任意一個現有開源 Cache Framework,要求使用 Cache 系統中 Service 或則 DAO 層的 get/find 等方法返回結果,如果數據更新(使用 Create/update/delete 方法),則刷新 cache 中相應的內容。根據需求,計劃使用 Spring AOP + ehCache 來實現這個功能,采用 ehCache 原因之一是Spring 提供了 ehCache 的支持,至于為何僅僅支持 ehCache 而不支持 osCache 和JBossCache 無從得知(Hibernate???),但畢竟 Spring 提供了支持,可以減少一部分工作量:)。二是后來實現了 OSCache 和 JBoss Cache 的方式后,經過簡單測試發現幾個 Cache 在效率上沒有太大的區別(不考慮集群),決定采用 ehCahce。AOP 嘛,少不了攔截器,先創建一個實現了 MethodInterceptor 接口的攔截器,用來攔截Service/DAO 的方法調用,攔截到方法后,搜索該方法的結果在 cache 中是否存在,如果存在,返回 cache 中的緩存結果,如果不存在,返回查詢數據庫的結果,并將結果緩存到 cache 中。

    MethodCacheInterceptor.java

    Java 代碼

    package com.co.cache.ehcache;

    import java.io.Serializable;

    import net.sf.ehcache.Cache;

    import net.sf.ehcache.Element;

    import org.aopalliance.intercept.MethodInterceptor;

    import org.aopalliance.intercept.MethodInvocation;

    import org.apache.commons.logging.Log;

    import org.apache.commons.logging.LogFactory;

    import org.springframework.beans.factory.InitializingBean;

    import org.springframework.util.Assert;

    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);

    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.");

    }

    }

    上面的代碼中可以看到,在方法 public Object invoke(MethodInvocation invocation) 中,完成了搜索Cache/ 新建 cache 的功能。

    Element element = cache.get(cacheKey);

    這句代碼的作用是獲取 cache 中的 element ,如果 cacheKey 所對應的 element 不存在,將會返回一個 null 值。

    Java 代碼

    result = invocation.proceed();

    這句代碼的作用是獲取所攔截方法的返回值,詳細請查閱 AOP 相關文檔。隨后,再建立一個攔截器MethodCacheAfterAdvice ,作用是在用戶進行 create/update/delete 操作時來刷新 /remove 相關cache 內容,這個攔截器實現了 AfterReturningAdvice 接口,將會在所攔截的方法執行后執行在 public void afterReturning(Object arg0, Method arg1,Object[] arg2, Object arg3) 方法中所預定的操作

    Java 代碼

    package com.co.cache.ehcache;

    import java.lang.reflect.Method;

    import java.util.List;

    import net.sf.ehcache.Cache;

    import org.apache.commons.logging.Log;

    import org.apache.commons.logging.LogFactory;

    import org.springframework.aop.AfterReturningAdvice;

    import org.springframework.beans.factory.InitializingBean;

    import org.springframework.util.Assert;

    public class MethodCacheAfterAdvice implements AfterReturningAdvice, InitializingBean

    {

    private static final Log logger = LogFactory.getLog(MethodCacheAfterAdvice.class);

    private Cache cache;

    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.");

    }

    }

    上面的代碼很簡單,實現了 afterReturning 方法實現自 AfterReturningAdvice 接口,方法中所定義的內容將會在目標方法執行后執行,在該方法中的作用是獲取目標 class 的全名,如:com.co.cache.test.TestServiceImpl ,然后循環 cache  key list , remove cache 中所有和該 class 相關的 element 。

    Java 代碼

    String className = arg3.getClass().getName();

    隨后,開始配置 ehCache 的屬性, ehCache 需要一個 xml 文件來設置 ehCache 相關的一些屬性,如最大緩存數量、 cache 刷新的時間等等 .

    ehcache.xml

    <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>

    配置每一項的詳細作用不再詳細解釋,有興趣的請 google 下 ,這里需要注意一點 defaultCache 標簽定義了一個默認的 Cache ,這個 Cache 是不能刪除的,否則會拋出 No default cache is configured異常。另外,由于使用攔截器來刷新 Cache 內容,因此在定義 cache 生命周期時可以定義較大的數值, timeToIdleSeconds="300000" , timeToLiveSeconds="600000" ,好像還不夠大?然后,在將Cache 和兩個攔截器配置到 Spring ,這里沒有使用 2.0 里面 AOP 的標簽。

    cacheContext.xml

    <?xml version="1.0" encoding="UTF-8"?>

    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"

    "http://www.springframework.org/dtd/spring-beans.dtd ">

    <beans>

    <!-- 引用 ehCache 的配置 -->

    <bean id="defaultCacheManager"

    class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">

    <property name="configLocation">

    <value>ehcache.xml</value>

    </property>

    </bean>

    <!-- 定義 ehCache 的工廠,并設置所使用的 Cache name -->

    <bean id="ehCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean">

    <property name="cacheManager">

    <ref local="defaultCacheManager"/>

    </property>

    <property name="cacheName">

    <value>DEFAULT_CACHE</value>

    </property>

    </bean>

    <!-- find/create cache 攔截器 -->

    <bean id="methodCacheInterceptor"

    class="com.co.cache.ehcache.MethodCacheInterceptor">

    <property name="cache">

    <ref local="ehCache" />

    </property>

    </bean>

    <!-- flush cache 攔截器 -->

    <bean id="methodCacheAfterAdvice"

    class="com.co.cache.ehcache.MethodCacheAfterAdvice">

    <property name="cache">

    <ref local="ehCache" />

    </property>

    </bean>

    <bean id="methodCachePointCut"

    class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">

    <property name="advice">

    <ref local="methodCacheInterceptor"/>

    </property>

    <property name="patterns">

    <list>

    <value>.*find.*</value>

    <value>.*get.*</value>

    </list>

    </property>

    </bean>

    <bean id="methodCachePointCutAdvice"

    class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">

    <property name="advice">

    <ref local="methodCacheAfterAdvice"/>

    </property>

    <property name="patterns">

    <list>

    <value>.*create.*</value>

    <value>.*update.*</value>

    <value>.*delete.*</value>

    </list>

    </property>

    </bean>

    </beans>

    上面的代碼最終創建了兩個 " 切入點 " , methodCachePointCut  methodCachePointCutAdvice ,分別用于攔截不同方法名的方法,可以根據需要任意增加所需要攔截方法的名稱。需要注意的是 Java代碼

    <bean id="ehCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean">

    <property name="cacheManager">

    <ref local="defaultCacheManager"/>

    </property>

    <property name="cacheName">

    <value>DEFAULT_CACHE</value>

    </property>

    </bean>

    如果 cacheName 屬性內設置的 name  ehCache.xml 中無法找到,那么將使用默認的

    cache(defaultCache 標簽定義 ) ,事實上到了這里,一個簡單的 Spring + ehCache Framework 基本完成了,為了測試效果,舉一個實際應用的例子,定義一個 TestService 和它的實現類 TestServiceImpl ,里面包含兩個方法 getAllObject()  updateObject(Object Object) ,具體代碼如下:

    TestService.java

    Java 代碼

    package com.co.cache.test;

    import java.util.List;

    public interface TestService {

    public List getAllObject();

    public void updateObject(Object Object);

    }

    TestServiceImpl.java

    Java 代碼

    package com.co.cache.test;

    import java.util.List;

    public class TestServiceImpl implements TestService

    {

    public List getAllObject() {

    System.out.println("---TestService  Cache 內不存在該 element ,查找并放入 Cache  ");

    return null;

    }

    public void updateObject(Object Object) {

    System.out.println("---TestService :更新了對象,這個 Class 產生的 cache 都將被 remove !

    ");

    }

    }

    使用 Spring 提供的 AOP 進行配置

    applicationContext.xml

    XML/HTML 代碼

    <?xml version="1.0" encoding="UTF-8"?>

    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"

    "http://www.springframework.org/dtd/spring-beans.dtd ">

    <beans>

    <import resource="cacheContext.xml"/>

    <bean id="testServiceTarget" class="com.co.cache.test.TestServiceImpl"/>

    <bean id="testService" class="org.springframework.aop.framework.ProxyFactoryBean">

    <property name="target">

    <ref local="testServiceTarget"/>

    </property>

    <property name="interceptorNames">

    <list>

    <value>methodCachePointCut</value>

    <value>methodCachePointCutAdvice</value>

    </list>

    </property>

    </bean>

    </beans>

    這里一定不能忘記 import cacheContext.xml 文件,不然定義的兩個攔截器就沒辦法使用

    了。

    最后,寫一個測試的代碼

    MainTest.java

    Java 代碼

    (DEFAULT_CONTEXT_FILE);

    TestService testService = (TestService)context.getBean("testService");

    System.out.println("1-- 第一次查找并創建 cache");

    testService.getAllObject();

    System.out.println("2--  cache 中查找 ");

    testService.getAllObject();

    System.out.println("3--remove cache");

    testService.updateObject(null);

    System.out.println("4-- 需要重新查找并創建 cache");

    testService.getAllObject();

    }

    }

    運行,結果如下

    Java 代碼

    1-- 第一次查找并創建 cache

    ---TestService  Cache 內不存在該 element ,查找并放入 Cache 

    2--  cache 中查找

    3--remove cache

    ---TestService :更新了對象,這個 Class 產生的 cache 都將被 remove !

    4-- 需要重新查找并創建 cache

    ---TestService  Cache 內不存在該 element ,查找并放入 Cache !

    大功告成 . 可以看到,第一步執行 getAllObject() ,執行 TestServiceImpl 內的方法,并創建了 cache,在第二次執行 getAllObject() 方法時,由于 cache 有該方法的緩存,直接從 cache  get 出方法的結果,所以沒有打印出 TestServiceImpl 中的內容,而第三步,調用了 updateObject 方法,和TestServiceImpl 相關的 cache  remove ,所以在第四步執行時,又執行 TestServiceImpl 中的方法,創建 Cache 。網上也有不少類似的例子,但是很多都不是很完備,自己參考了一些例子的代碼,其實在 spring-modules 中也提供了對幾種 cache 的支持, ehCache  OSCache , JBossCache 這些,看了一下,基本上都是采用類似的方式,只不過封裝的更完善一些,主要思路也還是 Spring  AOP ,有興趣的可以研究一下。


    posted on 2016-06-18 15:45 youngturk 閱讀(150) 評論(0)  編輯  收藏 所屬分類: 筆試題

    <2016年6月>
    2930311234
    567891011
    12131415161718
    19202122232425
    262728293012
    3456789

    導航

    統計

    公告

    this year :
    1 jQuery
    2 freemarker
    3 框架結構
    4 口語英語

    常用鏈接

    留言簿(6)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    相冊

    EJB學習

    Flex學習

    learn English

    oracle

    spring MVC web service

    SQL

    Struts

    生活保健

    解析文件

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 内射干少妇亚洲69XXX| 久久久久无码专区亚洲av| 亚洲精品在线视频观看| 无码人妻一区二区三区免费n鬼沢 无码人妻一区二区三区免费看 | 亚洲高清中文字幕综合网| 四虎国产精品永久免费网址| 亚洲成a人片在线观看无码专区 | 在线免费观看你懂的| 日韩亚洲Av人人夜夜澡人人爽| 性无码免费一区二区三区在线| 久久精品国产亚洲AV香蕉| 1000部拍拍拍18勿入免费凤凰福利| 亚洲视频国产视频| 皇色在线视频免费网站| 亚洲熟妇无码一区二区三区| 免费看美女让人桶尿口| 黄色三级三级免费看| 国产亚洲美女精品久久久| 久久精品免费电影| 亚洲日本在线播放| 国产精品嫩草影院免费| jizz日本免费| 亚洲宅男永久在线| 黑人粗长大战亚洲女2021国产精品成人免费视频 | 亚洲日韩中文字幕一区| 妞干网免费视频在线观看| 精品一区二区三区无码免费直播| 亚洲人成网站18禁止一区 | 一级毛片免费播放试看60分钟| 国内精品99亚洲免费高清| 久久精品一本到99热免费| 亚洲 日韩 色 图网站| 亚洲国产精品日韩专区AV| 久久国产精品国产自线拍免费| 亚洲国产高清美女在线观看| 国产做床爱无遮挡免费视频| 国产免费人成视频在线播放播| 亚洲精品日韩专区silk| 亚洲av高清在线观看一区二区| 日本视频免费高清一本18| 亚洲中文字幕乱码一区|