公司要做的在线统计,由于数据10分钟才更新一次,因此打算让查询结果在内存中缓存1分钟,我这里拦截了service层的
getOnlineByDate方法
拦截的Interceptor代码如下,参考了http://www.blogjava.net/relax/archive/2005/04/11/3141.html :
package com.xxx.stat.online.aop; 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.springframework.beans.factory.InitializingBean; public class MethodCacheInterceptor implements MethodInterceptor, InitializingBean { private Cache cache; /** * sets cache name to be used */ public void setCache(Cache cache) { this.cache = cache; } @Override public void afterPropertiesSet() throws Exception { } @Override public Object invoke(MethodInvocation invocation) throws Throwable { String targetName = invocation.getThis().getClass().getName(); String methodName = invocation.getMethod().getName(); Object[] arguments = invocation.getArguments(); Object result; String cacheKey = getCacheKey(targetName, methodName, arguments); System.out.println("cacheKey is "+cacheKey); Element element = cache.get(cacheKey); if (element == null) { System.out.println("read result from db"); //call target/sub-interceptor result = invocation.proceed(); //cache method result element = new Element(cacheKey, (Serializable) result); cache.put(element); }else{ System.out.println("read result from cache"); } System.out.println("read result from cache"); 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(); } }
spring的配置如下
<!-- cache configuration starts here --> <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>com.xxx.stat.serverOnline.namedQuery.query1</value> </property> </bean> <bean id="methodCacheInterceptor" class="com.xxx.stat.online.aop.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>.*getOnlineByDate.*</value> </list> </property> </bean> <bean id="myBean" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="beanNames"><value>serverOnlineManager</value></property> <property name="interceptorNames"> <list> <value>methodCachePointCut</value> </list> </property> </bean>
注意这里的myBean的class是org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator
网上很多文章讲要这样配置(用org.springframework.aop.framework.ProxyFactoryBean ):
<bean id="myBean" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target"> <ref local="serverOnlineManager"/> </property> <property name="interceptorNames"> <list> <value>methodCachePointCut</value> </list> </property> </bean>
这样配置也是可以的,但是注意在给你的action层注入的时候,就不能注入serverOnlineManager这个bean而要改为myBean,或者,依然使用serverOnlineManager,但需要在你的spring配置文件里加上:
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
最后是ehcache.xml的配置,没啥说的
<ehcache> <diskStore path="java.io.tmpdir"/> <defaultCache maxElementsInMemory="10000" eternal="false" overflowToDisk="true" timeToIdleSeconds="120" timeToLiveSeconds="120" diskPersistent="false" diskExpiryThreadIntervalSeconds="120"/> <!-- See http://ehcache.sourceforge.net/documentation/#mozTocId258426 for how to configure caching for your objects --> <cache name="com.xxx.stat.serverOnline.namedQuery.query1" maxElementsInMemory="100000" eternal="false" timeToIdleSeconds="60" timeToLiveSeconds="60" overflowToDisk="true" /> </ehcache>
Spring文档里对ProxyFactoryBean的介绍------
“像其它的 FactoryBean
实现一样, ProxyFactoryBean
引入了一个间接层。如果你定义一个名为 foo
的 ProxyFactoryBean
, 引用 foo
的对象看到的将不是 ProxyFactoryBean
实例本身,而是一个 ProxyFactoryBean
实现里 getObject()
方法所创建的对象。 这个方法将创建一个AOP代理,它包装了一个目标对象。 ”
Spring文档里对BeanNameAutoProxyCreator的说明------
“ BeanNameAutoProxyCreator为名字匹配字符串或者通配符的bean自动创建AOP代理。”