公司要做的在线统计,由于数据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代理。”