读书人

利用Spring IoC跟EHCache 拦截缓存方法

发布时间: 2012-12-22 12:05:06 作者: rapoo

利用Spring IoC和EHCache 拦截缓存方法,缓存结果

EHCache作为一种通用缓存解决方案集成进 Spring。

我将示范拦截器的例子,它能把方法返回的结果缓存起来。

?

利用 Spring IoC 配置 EHCache

在 Spring 里配置 EHCache 很简单。你只需一个 ehcache.xml 文件,该文件用于配置 EHCache:

?

?

拦截器将使用 ”constantSeviceCache” 区域缓存方法返回结果。下面利用 Spring IoC 让 bean 来访问这一区域。

可以灵活的根据缓存的时间来建立多个这样的缓存,来控制不同的缓存时间

?

?

构建我们的 MethodCacheInterceptor

该拦截器根据spring2.0规范。一旦运行起来(kicks-in),它首先检查被拦截方法是否被配置为可缓存的。这将可选择性的配置想要缓存的 bean 方法。只要调用的方法配置为可缓存,拦截器将为该方法生成 cache key 并检查该方法返回的结果是否已缓存。如果已缓存,就返回缓存的结果,否则再次调用被拦截方法,并缓存结果供下次调用。

?

com.heshen.cache.MethodCacheInterceptor

?

MethodCacheInterceptor 代码说明了:

  • 默认条件下,所有方法返回结果都被缓存了(methodNames 是 null)
  • 缓存区利用 IoC 形成
  • cacheKey 的生成还包括方法参数的因素(译注:参数的改变会影响 cacheKey)

    使用 MethodCacheInterceptor

    下面摘录了怎样配置 MethodCacheInterceptor:

    ?

    ?

    ?

    译注

    夏昕所著《Hibernate 开发指南》,其中他这样描述 EHCache 配置文件的:

    ehcache.xml 文件

    ?

    ?

    ?

    <ehcache>
    ??? <diskStore path="java.io.tmpdir"/>
    ??? <defaultCache
    ??????? maxElementsInMemory="10000" //Cache中最大允许保存的数据数量
    ??????? eternal="false"????????????????????? ?//Cache中数据是否为常量
    ??????? timeToIdleSeconds="120"???? //缓存数据钝化时间
    ??????? timeToLiveSeconds="120"???? //缓存数据的生存时间
    ??????? overflowToDisk="true"?????? //内存不足时,是否启用磁盘缓存
    ??? />
    </ehcache>
    <cache name="constantSeviceCache"
    ??????? maxElementsInMemory="10000"
    ??????? eternal="false"
    ??????? timeToIdleSeconds="3600"
    ??????? timeToLiveSeconds="3600"
    ??????? overflowToDisk="true"
    ??????? />


    提供缓存拦截的类

    ?MethodCacheInterceptor.java

    ?

    /**
    */
    package com.heshen.cache;

    import java.io.Serializable;
    import java.lang.reflect.Method;

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

    import org.apache.log4j.Logger;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.Signature;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.springframework.beans.factory.InitializingBean;
    import org.springframework.util.Assert;

    /**
    ?* 针对方法切入,进行缓存的拦截器
    ?* @author wanggang
    ?? @version 2010-12-03
    ?*
    ?*?????? 缓存处理
    ?*/
    public class MethodCacheInterceptor implements InitializingBean {

    ??? private Logger logger = Logger.getLogger("Method-Cache-Inegceptor");

    ??? private Cache serviceCache;

    ??? /**
    ??? ?* 设置缓存名
    ??? ?*/
    ??? public void setServiceCache(Cache serviceCache) {
    ??? ??? this.serviceCache = serviceCache;
    ??? }

    ??? /**
    ??? ?* 主方法 如果某方法可被缓存就缓存其结果 方法结果必须是可序列化的(serializable)
    ??? ?*/
    ??? public Object doCacheOperation(ProceedingJoinPoint pjp)
    ??? ??? ??? throws Throwable {

    ??? ??? String targetName = pjp.getTarget().getClass().getName();
    ??? ??? Signature signature = pjp.getSignature();
    ??? ??? MethodSignature methodSignature = (MethodSignature) signature;
    ??? ??? Method method = methodSignature.getMethod();

    ??? ??? // String methodName = pjp.getThis()methodName.
    ??? ??? // invocation.getMethod().getName();
    ??? ??? String methodName = method.getName();

    ??? ??? Object[] arguments = pjp.getArgs();// invocation.getArguments();
    ??? ??? Object result;
    ??? ??? // logger.info("looking for method result in cache");
    ??? ??? String cacheKey = getCacheKey(targetName, methodName, arguments);
    ??? ??? logger.info("cache key" + cacheKey);
    ??? ??? Element element = serviceCache.get(cacheKey);
    ??? ??? if (element == null) {
    ??? ??? ??? // call target/sub-interceptor
    ??? ??? ??? logger.info("calling intercepted method");
    ??? ??? ??? result = pjp.proceed();

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

    ??? }

    ??? /**
    ??? ?* creates cache key: targetName.methodName.argument0.argument1...
    ??? ?*/
    ??? private String getCacheKey(String targetName, String methodName,
    ??? ??? ??? Object[] arguments) throws Exception {
    ??? ??? 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();
    ??? }
    ???
    ??? /**
    ??? ?* 检查是否提供必要参数。
    ??? ?*/
    ??? public void afterPropertiesSet() throws Exception {
    ??? ??? Assert.notNull(serviceCache,
    ??? ??? ??? ??? "A cache is required. Use setCache(Cache) to provide one.");
    ??? }


    }

    ?

    ??cacheInterceptor.xml缓存拦截器配置文件

    ?

    <?xml version="1.0" encoding="GBK"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    ??? xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    ??? xmlns:tx="http://www.springframework.org/schema/tx"
    ??? xsi:schemaLocation="http://www.springframework.org/schema/beans
    ??? http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
    ??? http://www.springframework.org/schema/tx
    ??? http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
    ??? http://www.springframework.org/schema/aop
    ??? http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"
    ??? default-autowire="byName">
    ???
    ??? <!-- 实际提供缓存服务的类 -->
    ?? <bean id="cacheManager" />??
    ??????? </property>??
    ??? </bean>
    ???
    ???
    ??? <!--? 缓存不会变动的服务 -->
    <aop:config>
    ??? ? <aop:aspect id="constantSeviceCacheOperation" ref="constantSeviceCacheMethodCacheInterceptor">
    ??? ??? <aop:pointcut id="test1ConstantSeviceCacheCut" expression="execution(* com.heshen.service.impl.Test1ServiceImpl.*(..))"/>
    ??? ??? <aop:pointcut id="test2ClassServiceCacheCut" expression="execution(* com.heshen.service.impl.Test2ServiceImpl.*(..))"/>
    ??? ??? ??? ???
    ??? ??? <aop:around pointcut-ref="test1ConstantSeviceCacheCut" method="doCacheOperation"/>??? ????
    ??? ??? <aop:around pointcut-ref="test2ClassServiceCacheCut" method="doCacheOperation"/>
    ??? ? </aop:aspect>
    ??? </aop:config>

    ??? <!--? 还可以继续配置其他的缓存切面 -->
    <!--
    <aop:config>
    ??? ? <aop:aspect id="constantSeviceCacheOperation" ref="constantSeviceCacheMethodCacheInterceptor">
    ??? ??? <aop:pointcut id="test1ConstantSeviceCacheCut" expression="execution(* com.heshen.service.impl.Test1ServiceImpl.*(..))"/>
    ??? ??? <aop:pointcut id="test2ClassServiceCacheCut" expression="execution(* com.heshen.service.impl.Test2ServiceImpl.*(..))"/>
    ??? ??? ??? ???
    ??? ??? <aop:around pointcut-ref="test1ConstantSeviceCacheCut" method="doCacheOperation"/>??? ????
    ??? ??? <aop:around pointcut-ref="test2ClassServiceCacheCut" method="doCacheOperation"/>
    ??? ? </aop:aspect>
    ??? </aop:config>-->
    </beans>

    ?

    cacheInterceptor.xml缓存拦截器配置文件

    ?

    /**
    */
    com.heshen.service.impl;


    /**
    ?* 具体的service类
    ?* @author wanggang
    ?? @version 2010-12-03
    ?*
    ?*?????? 缓存处理
    ?*/
    public class Test2ServiceImpl implements test2Service {

    ??? private Logger logger = Logger.getLogger("Test2ServiceImpl ");

    ??? public void doSomeThing1(String a){
    ??? }

    ?? public String doSomeThing2(String arg1,String arg2){
    ??? }
    ?? ....
    }

  • 读书人网 >编程

    热点推荐