AOP,当然需要拦截器,这里需要2个拦截器:
一个是方法执行前查找缓存的拦截器;(query方法执行前先查找是否有缓存,如果有,走缓存,如果没有,执行方法,并且把结果缓存)
另一个是方法执行后销毁缓存的拦截器;(update,insert,delete等方法执行后需要销毁缓存)
---------------------------------------------------------------------------------------------------------------------------------------
方法执行前的拦截器MethodCacheInterceptor.java:
---------------------------------------------------------------------------------------------------------------------------------------
方法执行后的拦截器MethodCacheAfterAdvice.java:
---------------------------------------------------------------------------------------------------------------------------------------
测试用的测试方法TestService.java:
---------------------------------------------------------------------------------------------------------------------------------------
缓存配置文件ehcache.xml:
缓存配置文件ehcache-config.xml
---------------------------------------------------------------------------------------------------------------------------------------
Spring配置文件applicationContext.xml
---------------------------------------------------------------------------------------------------------------------------------------
测试用Main方法:
---------------------------------------------------------------------------------------------------------------------------------------
运行结果:
可以看到,第一次调用时没走缓存,第二次就走缓存
然后执行update操作,执行完后销毁缓存
第三次调用,又没走缓存。
一个是方法执行前查找缓存的拦截器;(query方法执行前先查找是否有缓存,如果有,走缓存,如果没有,执行方法,并且把结果缓存)
另一个是方法执行后销毁缓存的拦截器;(update,insert,delete等方法执行后需要销毁缓存)
---------------------------------------------------------------------------------------------------------------------------------------
方法执行前的拦截器MethodCacheInterceptor.java:
package ehcache;
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;
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);
}else{
logger.debug("get 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();
}
}
---------------------------------------------------------------------------------------------------------------------------------------
方法执行后的拦截器MethodCacheAfterAdvice.java:
package ehcache;
import java.lang.reflect.Method;
import java.util.List;
import net.sf.ehcache.Cache;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
public class MethodCacheAfterAdvice implements AfterReturningAdvice, InitializingBean
{
private static final Log logger = LogFactory.getLog(MethodCacheAfterAdvice.class);
private Cache cache;
public void setCache(Cache cache) {
this.cache = cache;
}
public MethodCacheAfterAdvice() {
super();
}
public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
String className = arg3.getClass().getName();
List list = cache.getKeys();
for(int i = 0;i<list.size();i++){
String cacheKey = String.valueOf(list.get(i));
if(cacheKey.startsWith(className)){
cache.remove(cacheKey);
logger.debug("remove cache " + cacheKey);
}
}
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(cache, "Need a cache. Please use setCache(Cache) create it.");
}
}
---------------------------------------------------------------------------------------------------------------------------------------
测试用的测试方法TestService.java:
package ehcache;
public class TestService{
public String testMethod(){
System.out.println("没走缓存,直接调用TestService.testMethod()");
return "1";
}
public void updateMethod(){
System.out.println("updateMethod");
}
public void insertMethod(){
System.out.println("insertMethod");
}
public void deleteMethod(){
System.out.println("deleteMethod");
}
}
---------------------------------------------------------------------------------------------------------------------------------------
缓存配置文件ehcache.xml:
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="false"
diskSpoolBufferSizeMB="30"
maxElementsOnDisk="10000000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
/>
<cache name="testCache"
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="150"
timeToLiveSeconds="150"
overflowToDisk="false"
memoryStoreEvictionPolicy="LRU"
/>
缓存配置文件ehcache-config.xml
<beans>
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation">
<value>src/ehcache/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>testCache</value>
</property>
</bean>
<!-- 创建cache拦截器 -->
<bean id="methodCacheInterceptor" class="ehcache.MethodCacheInterceptor">
<property name="cache">
<ref local="methodCache" />
</property>
</bean>
<!-- 销毁cache拦截器 -->
<bean id="methodCacheAfterAdvice" class="ehcache.MethodCacheAfterAdvice">
<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>.*TestService.testMethod</value>
</list>
</property>
</bean>
<bean id="methodCacheDestory" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice">
<ref local="methodCacheAfterAdvice"/>
</property>
<property name="patterns">
<list>
<value>.*TestService.update*</value>
<value>.*TestService.insert*</value>
<value>.*TestService.delete*</value>
</list>
</property>
</bean>
</beans>
---------------------------------------------------------------------------------------------------------------------------------------
Spring配置文件applicationContext.xml
<beans default-autowire="byName">
<import resource="ehcache-config.xml"/>
<bean id="testService" class="org.springframework.aop.framework.ProxyFactoryBean" >
<property name="target">
<bean class="ehcache.TestService"/>
</property>
<property name="interceptorNames">
<list>
<value>methodCachePointCut</value>
<value>methodCacheDestory</value>
</list>
</property>
</bean>
</beans>
---------------------------------------------------------------------------------------------------------------------------------------
测试用Main方法:
package ehcache;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class TestMain {
public static void main(String args[]) throws Exception{
ApplicationContext ctx = new FileSystemXmlApplicationContext("src/ehcache/applicationContext.xml");
TestService t = (TestService)ctx.getBean("testService");
System.out.println("第一次调用:" + t.testMethod());
System.out.println("第二次调用:" + t.testMethod());
System.out.print("更新操作:");
t.updateMethod();
System.out.println("第三次调用:" + t.testMethod());
}
}
---------------------------------------------------------------------------------------------------------------------------------------
运行结果:
没走缓存,直接调用TestService.testMethod()
第一次调用:1
第二次调用:1
更新操作:updateMethod
没走缓存,直接调用TestService.testMethod()
第三次调用:1
可以看到,第一次调用时没走缓存,第二次就走缓存
然后执行update操作,执行完后销毁缓存
第三次调用,又没走缓存。