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

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

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

    Ehcache學(xué)習(xí) 轉(zhuǎn)

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

    5.     Spring 中運(yùn)用 EHCache

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

    否則,返回?cái)?shù)據(jù)庫查詢結(jié)果,并將查詢結(jié)果放入 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 中一個(gè) Element 的唯一標(biāo)識(shí)

    * 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 所對(duì)應(yīng)的 element 不存在,將會(huì)返回一個(gè) null 值。

    Java 代碼

    result = invocation.proceed();

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

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

    }

    }

    上面的代碼很簡(jiǎn)單,實(shí)現(xiàn)了 afterReturning 方法實(shí)現(xiàn)自 AfterReturningAdvice 接口,方法中所定義的內(nèi)容將會(huì)在目標(biāo)方法執(zhí)行后執(zhí)行,在該方法中的作用是獲取目標(biāo) class 的全名,如:com.co.cache.test.TestServiceImpl ,然后循環(huán) cache  key list  remove cache 中所有和該 class 相關(guān)的 element 

    Java 代碼

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

    隨后,開始配置 ehCache 的屬性, ehCache 需要一個(gè) xml 文件來設(shè)置 ehCache 相關(guān)的一些屬性,如最大緩存數(shù)量、 cache 刷新的時(shí)間等等 .

    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>

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

    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 的工廠,并設(shè)置所使用的 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>

    上面的代碼最終創(chuàng)建了兩個(gè) " 切入點(diǎn) "  methodCachePointCut  methodCachePointCutAdvice ,分別用于攔截不同方法名的方法,可以根據(jù)需要任意增加所需要攔截方法的名稱。需要注意的是 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 屬性內(nèi)設(shè)置的 name  ehCache.xml 中無法找到,那么將使用默認(rèn)的

    cache(defaultCache 標(biāo)簽定義 ) ,事實(shí)上到了這里,一個(gè)簡(jiǎn)單的 Spring + ehCache Framework 基本完成了,為了測(cè)試效果,舉一個(gè)實(shí)際應(yīng)用的例子,定義一個(gè) TestService 和它的實(shí)現(xiàn)類 TestServiceImpl ,里面包含兩個(gè)方法 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 內(nèi)不存在該 element ,查找并放入 Cache  ");

    return null;

    }

    public void updateObject(Object Object) {

    System.out.println("---TestService :更新了對(duì)象,這個(gè) Class 產(chǎn)生的 cache 都將被 remove 

    ");

    }

    }

    使用 Spring 提供的 AOP 進(jìn)行配置

    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 文件,不然定義的兩個(gè)攔截器就沒辦法使用

    了。

    最后,寫一個(gè)測(cè)試的代碼

    MainTest.java

    Java 代碼

    (DEFAULT_CONTEXT_FILE);

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

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

    testService.getAllObject();

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

    testService.getAllObject();

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

    testService.updateObject(null);

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

    testService.getAllObject();

    }

    }

    運(yùn)行,結(jié)果如下

    Java 代碼

    1-- 第一次查找并創(chuàng)建 cache

    ---TestService  Cache 內(nèi)不存在該 element ,查找并放入 Cache 

    2--  cache 中查找

    3--remove cache

    ---TestService :更新了對(duì)象,這個(gè) Class 產(chǎn)生的 cache 都將被 remove 

    4-- 需要重新查找并創(chuàng)建 cache

    ---TestService  Cache 內(nèi)不存在該 element ,查找并放入 Cache 

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


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

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

    導(dǎo)航

    統(tǒng)計(jì)

    公告

    this year :
    1 jQuery
    2 freemarker
    3 框架結(jié)構(gòu)
    4 口語英語

    常用鏈接

    留言簿(6)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    相冊(cè)

    EJB學(xué)習(xí)

    Flex學(xué)習(xí)

    learn English

    oracle

    spring MVC web service

    SQL

    Struts

    生活保健

    解析文件

    搜索

    最新評(píng)論

    閱讀排行榜

    評(píng)論排行榜

    主站蜘蛛池模板: 免费人成网站在线高清| 亚洲人成国产精品无码| 久久亚洲精品无码播放| 亚洲国产视频网站| 99亚洲乱人伦aⅴ精品| 精品在线免费观看| 免费观看a级毛片| 亚洲va中文字幕无码久久| 中国china体内裑精亚洲日本| 一级黄色免费网站| 国产桃色在线成免费视频| 国产啪亚洲国产精品无码| 亚洲一区在线观看视频| 亚洲黄片手机免费观看| 久久WWW免费人成人片| 亚洲av无码国产精品色午夜字幕| 亚洲依依成人亚洲社区| 久久久久久一品道精品免费看| 永久免费av无码网站大全| 亚洲一区二区成人| 一级毛片在线免费视频| 毛片在线看免费版| 亚洲av无码精品网站| 日本激情猛烈在线看免费观看| 香蕉97超级碰碰碰免费公| 亚洲AV无码不卡在线播放| 免费一级全黄少妇性色生活片| 国产1024精品视频专区免费| 亚洲国产精品成人精品无码区在线 | 亚洲色成人WWW永久在线观看| 久久免费精品一区二区| 又黄又爽无遮挡免费视频| 亚洲AV无码乱码麻豆精品国产| 久久伊人免费视频| 超清首页国产亚洲丝袜| 亚洲aⅴ无码专区在线观看春色| 曰批全过程免费视频网址| 亚洲线精品一区二区三区| 羞羞漫画在线成人漫画阅读免费 | 久久精品国产亚洲精品| 日本系列1页亚洲系列|