利用 Spring 和 EHCache 緩存結果(翻譯)

原文地址:
http://opensource.atlassian.com/confluence/spring/display/DISC/Caching+the+result+of+methods+using+Spring+and+EHCache



導言<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

Spring 1.1.1 開始,EHCache 就作爲一種通用緩存解決方案集成進 Spring

我將示範攔截器的例子,它能把方法返回的結果緩存起來。

 

利用 Spring IoC 配置 EHCache

Spring 裏配置 EHCache 很簡單。你只需一個 ehcache.xml 文件,該文件用於配置 EHCache

 

<ehcache>

    <!—設置緩存文件 .data 的創建路徑。

         如果該路徑是 Java 系統參數,當前虛擬機會重新賦值。

         下面的參數這樣解釋:
         user.home – 用戶主目錄
         user.dir      – 用戶當前工作目錄
         java.io.tmpdir – 默認臨時文件路徑 -->
    <diskStore path="java.io.tmpdir"/>


    <!—缺省緩存配置。CacheManager 會把這些配置應用到程序中。

        下列屬性是 defaultCache 必須的:

        maxInMemory           - 設定內存中創建對象的最大值。
        eternal                        - 設置元素(譯註:內存中對象)是否永久駐留。如果是,將忽略超
                                              時限制且元素永不消亡。
        timeToIdleSeconds  - 設置某個元素消亡前的停頓時間。
                                              也就是在一個元素消亡之前,兩次訪問時間的最大時間間隔值。
                                              這只能在元素不是永久駐留時有效(譯註:如果對象永恆不滅,則
                                              設置該屬性也無用)。
                                              如果該值是 0 就意味着元素可以停頓無窮長的時間。
        timeToLiveSeconds - 爲元素設置消亡前的生存時間。
                                               也就是一個元素從構建到消亡的最大時間間隔值。
                                               這只能在元素不是永久駐留時有效。
        overflowToDisk        - 設置當內存中緩存達到 maxInMemory 限制時元素是否可寫到磁盤
                                               上。
        -->

    <cache name="org.taha.cache.METHOD_CACHE"
        maxElementsInMemory="300"
        eternal="false"
        timeToIdleSeconds="500"
        timeToLiveSeconds="500"
        overflowToDisk="true"
        />
</ehcache>

 

攔截器將使用 org.taha.cache.METHOD_CACHE區域緩存方法返回結果。下面利用 Spring IoC bean 來訪問這一區域。

 

<!-- ======================   緩存   ======================= -->

<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
  <property name="configLocation">
    <value>classpath:ehcache.xml</value>
  </property>
</bean>

<bean id="methodCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
  <property name="cacheManager">
    <ref local="cacheManager"/>
  </property>
  <property name="cacheName">
    <value>org.taha.cache.METHOD_CACHE</value>
  </property>
</bean>

 

構建我們的 MethodCacheInterceptor

該攔截器實現org.aopalliance.intercept.MethodInterceptor接口。一旦運行起來(kicks-in),它首先檢查被攔截方法是否被配置爲可緩存的。這將可選擇性的配置想要緩存的 bean 方法。只要調用的方法配置爲可緩存,攔截器將爲該方法生成 cache key 並檢查該方法返回的結果是否已緩存。如果已緩存,就返回緩存的結果,否則再次調用被攔截方法,並緩存結果供下次調用。

 

org.taha.interceptor.MethodCacheInterceptor

 

/*
 * Copyright 2002-2004 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     
http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.taha.interceptor;

import java.io.Serializable;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.Log;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;

import net.sf.ehcache.Cache;
import net.sf.ehcache.Element;

/**
 * @author <a href="
mailto:[email protected]">Omar Irbouh</a>
 * @since 2004.10.07
 */
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 void afterPropertiesSet() throws Exception {
    Assert.notNull(cache, "A cache is required. Use setCache(Cache) to provide one.");
  }

  /**
   * 主方法
   * 如果某方法可被緩存就緩存其結果
   * 方法結果必須是可序列化的(serializable)
   */
  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("looking for method result in cache");
    String cacheKey = getCacheKey(targetName, methodName, arguments);
    Element element = cache.get(cacheKey);
    if (element == null) {
      //call target/sub-interceptor
      logger.debug("calling intercepted method");
      result = invocation.proceed();

      //cache method result
      logger.debug("caching result");
      element = new Element(cacheKey, (Serializable) result);
      cache.put(element);
    }
    return element.getValue();
  }

  /**
   * creates cache key: targetName.methodName.argument0.argument1...
   */
  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();
  }
}

 

MethodCacheInterceptor 代碼說明了:

  • 默認條件下,所有方法返回結果都被緩存了(methodNames null

  • 緩存區利用 IoC 形成

  • cacheKey 的生成還包括方法參數的因素(譯註:參數的改變會影響 cacheKey

使用 MethodCacheInterceptor

下面摘錄了怎樣配置 MethodCacheInterceptor

 

<bean id="methodCacheInterceptor" class="org.taha.interceptor.MethodCacheInterceptor">
  <property name="cache">
    <ref local="methodCache" />
  </property>
</bean>

<bean id="methodCachePointCut" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
  <property name="advice">
    <ref local="methodCacheInterceptor"/>
  </property>
  <property name="patterns">
    <list>
      <value>.*methodOne</value>
      <value>.*methodTwo</value>
    </list>
  </property>
</bean>

<bean id="myBean" class="org.springframework.aop.framework.ProxyFactoryBean">
  <property name="target">
   <bean class="org.taha.beans.MyBean"/>
  </property>
  <property name="interceptorNames">
    <list>
      <value>methodCachePointCut</value>
    </list>
  </property>
</bean>

 

 

譯註

夏昕所著《Hibernate 開發指南》,其中他這樣描述 EHCache 配置文件的:

 

<ehcache>
    <diskStore path="java.io.tmpdir"/>
    <defaultCache
        maxElementsInMemory="10000" //Cache中最大允許保存的數據數量
        eternal="false"                       //Cache中數據是否爲常量
        timeToIdleSeconds="120"     //緩存數據鈍化時間
        timeToLiveSeconds="120"     //緩存數據的生存時間
        overflowToDisk="true"       //內存不足時,是否啓用磁盤緩存
    />
</ehcache>
 

(請注意!引用、轉貼本文應註明原作者:Rosen Jiang 以及出處:http://blog.csdn.net/rosen
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章