利用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 代码说明了:
使用 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"
??????? />
提供缓存拦截的类
?
/***/
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){
??? }
?? ....
}