spring+ehcache 实现原理
引用:http://yaoweinan.iteye.com/blog/1199397
ehcache 大家都很熟悉,我这里主要通过总结记录下spring和ehcache结合的步骤,并对一些细节做详细的阐述。
首先我们需要配置ehcache的配置文件包含了缓存路径,大小,过期时间等 注意里面的defaultcache不要删除否则会出错滴。然后我们在把ehcache的jar包导入。
其次 我们需要写了两个类 这两个类一个用来对查询的缓存和再查询的缓存调用(代码1),一个用来处理如果对某一资源做了改动或者新增,则清除这中资源的所有缓存(代码2)。 接下来我们在spring配置文件中配置ehcache(你也可以单独文件中写),包括ehcache的引用,工厂,再将自己写的两个拦截器配置好之后在配置两个符合代理使用的两个bean,分别将两个拦截器注入。
最后我们为自己写的service/dao 在spring配置,再为他们分别配置代理,代理所要拦截的东西就是前面的两个拦截器。
接下来我将配置的具体内容贴出来
代码1 写道
package com.my.cache.ehcache;
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.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
/**
* ehCache 查询缓存处理
* @author lyon.yao
*
*/
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 MethodCacheInterceptor() {
super();
}
/* (non-Javadoc)
* 检测cache对象是否为空
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
@Override
public void afterPropertiesSet() throws Exception {
Assert.notNull(cache, "cache is null,please set a new cache");
}
/* (non-Javadoc)
* 过滤service/dao 方法如果缓存中存在直接返回 否则从数据库中查找结果返回并放入缓存
* @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
*/
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Object result=null;
String targetName = invocation.getThis().getClass().getName();
String methodName = invocation.getMethod().getName();
Object[] arguments = invocation.getArguments();
String cacheKey = getCacheKey(targetName, methodName, arguments);
Element element = cache.get(cacheKey);
if (element == null) {
logger.debug("Hold up method , Get method result and create cache........!");
result = invocation.proceed();
element = new Element(cacheKey, (Serializable) result);
cache.put(element);
}
return element.getValue();
}
/**
* 获得 cache key 的方法,cache key 是 Cache 中一个 Element 的唯一标识
* cache key 包括 包名+类名+方法名,如 com.co.cache.service.UserServiceImpl.getAllUser
* @param targetName
* @param methodName
* @param arguments
* @return
*/
private String getCacheKey(String targetName,String methodName,Object[] arguments) {
StringBuffer key = new StringBuffer();
key.append(targetName).append(".").append(methodName);
if ((arguments != null) && (arguments.length != 0)) {
for (int i = 0; i < arguments.length; i++) {
key.append(".").append(arguments[i]);
}
}
return key.toString();
}
}
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.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
/**
* ehCache 查询缓存处理
* @author lyon.yao
*
*/
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 MethodCacheInterceptor() {
super();
}
/* (non-Javadoc)
* 检测cache对象是否为空
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
@Override
public void afterPropertiesSet() throws Exception {
Assert.notNull(cache, "cache is null,please set a new cache");
}
/* (non-Javadoc)
* 过滤service/dao 方法如果缓存中存在直接返回 否则从数据库中查找结果返回并放入缓存
* @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
*/
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Object result=null;
String targetName = invocation.getThis().getClass().getName();
String methodName = invocation.getMethod().getName();
Object[] arguments = invocation.getArguments();
String cacheKey = getCacheKey(targetName, methodName, arguments);
Element element = cache.get(cacheKey);
if (element == null) {
logger.debug("Hold up method , Get method result and create cache........!");
result = invocation.proceed();
element = new Element(cacheKey, (Serializable) result);
cache.put(element);
}
return element.getValue();
}
/**
* 获得 cache key 的方法,cache key 是 Cache 中一个 Element 的唯一标识
* cache key 包括 包名+类名+方法名,如 com.co.cache.service.UserServiceImpl.getAllUser
* @param targetName
* @param methodName
* @param arguments
* @return
*/
private String getCacheKey(String targetName,String methodName,Object[] arguments) {
StringBuffer key = new StringBuffer();
key.append(targetName).append(".").append(methodName);
if ((arguments != null) && (arguments.length != 0)) {
for (int i = 0; i < arguments.length; i++) {
key.append(".").append(arguments[i]);
}
}
return key.toString();
}
}
代码2 写道
package com.my.cache.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;
/**
* 功能:进行插入、修改、删除对cache的清理
* @author lyon.yao
*
*/
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();
}
/* (non-Javadoc)
* 检测cache对象是否为空
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
@Override
public void afterPropertiesSet() throws Exception {
Assert.notNull(cache, "cache is null,please set a new cache");
}
/* (non-Javadoc)
* 刷新cache
* @see org.springframework.aop.AfterReturningAdvice#afterReturning(java.lang.Object, java.lang.reflect.Method, java.lang.Object[], java.lang.Object)
*/
@Override
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);
}
}
}
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;
/**
* 功能:进行插入、修改、删除对cache的清理
* @author lyon.yao
*
*/
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();
}
/* (non-Javadoc)
* 检测cache对象是否为空
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
@Override
public void afterPropertiesSet() throws Exception {
Assert.notNull(cache, "cache is null,please set a new cache");
}
/* (non-Javadoc)
* 刷新cache
* @see org.springframework.aop.AfterReturningAdvice#afterReturning(java.lang.Object, java.lang.reflect.Method, java.lang.Object[], java.lang.Object)
*/
@Override
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);
}
}
}
ehcache.xml 写道
<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="500"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="1200"
overflowToDisk="true" />
<cache name="DEFAULT_CACHE"
maxElementsInMemory="5000"
eternal="false"
timeToIdleSeconds="500"
timeToLiveSeconds="500"
overflowToDisk="true"
/>
</ehcache>
<ehcache>
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="500"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="1200"
overflowToDisk="true" />
<cache name="DEFAULT_CACHE"
maxElementsInMemory="5000"
eternal="false"
timeToIdleSeconds="500"
timeToLiveSeconds="500"
overflowToDisk="true"
/>
</ehcache>
写道
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!-- 缓存管理 -->
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" >
<property name="configLocation">
<value>classpath:ehcache.xml</value>
</property>
</bean>
<!-- 信息缓存 -->
<bean id="ehCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheName">
<value>DEFAULT_CACHE</value>
</property>
<property name="cacheManager" ref="cacheManager" />
</bean>
<!-- find/create cache 拦截器 -->
<bean id="methodCacheInterceptor"
class="com.my.cache.ehcache.MethodCacheInterceptor">
<property name="cache">
<ref local="ehCache" />
</property>
</bean>
<!-- flush cache 拦截器 -->
<bean id="methodCacheAfterAdvice"
class="com.my.cache.ehcache.MethodCacheAfterAdvice">
<property name="cache">
<ref local="ehCache" />
</property>
</bean>
<bean id="methodCachePointCut"
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice">
<ref local="methodCacheInterceptor"/>
</property>
<property name="patterns">
<list>
<value>.*find.*</value>
<value>.*get.*</value>
<value>.*list.*</value>
<value>.*query.*</value>
</list>
</property>
</bean>
<bean id="methodCachePointCutAdvice"
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice">
<ref local="methodCacheAfterAdvice"/>
</property>
<property name="patterns">
<list>
<value>.*add.*</value>
<value>.*create.*</value>
<value>.*update.*</value>
<value>.*delete.*</value>
<value>.*remove.*</value>
</list>
</property>
</bean>
</beans>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!-- 缓存管理 -->
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" >
<property name="configLocation">
<value>classpath:ehcache.xml</value>
</property>
</bean>
<!-- 信息缓存 -->
<bean id="ehCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheName">
<value>DEFAULT_CACHE</value>
</property>
<property name="cacheManager" ref="cacheManager" />
</bean>
<!-- find/create cache 拦截器 -->
<bean id="methodCacheInterceptor"
class="com.my.cache.ehcache.MethodCacheInterceptor">
<property name="cache">
<ref local="ehCache" />
</property>
</bean>
<!-- flush cache 拦截器 -->
<bean id="methodCacheAfterAdvice"
class="com.my.cache.ehcache.MethodCacheAfterAdvice">
<property name="cache">
<ref local="ehCache" />
</property>
</bean>
<bean id="methodCachePointCut"
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice">
<ref local="methodCacheInterceptor"/>
</property>
<property name="patterns">
<list>
<value>.*find.*</value>
<value>.*get.*</value>
<value>.*list.*</value>
<value>.*query.*</value>
</list>
</property>
</bean>
<bean id="methodCachePointCutAdvice"
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice">
<ref local="methodCacheAfterAdvice"/>
</property>
<property name="patterns">
<list>
<value>.*add.*</value>
<value>.*create.*</value>
<value>.*update.*</value>
<value>.*delete.*</value>
<value>.*remove.*</value>
</list>
</property>
</bean>
</beans>
applicationContext-sevice.xml 写道
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<import resource="cacheContext.xml"/>
<bean id="testServiceTarget" class="com.co.cache.test.TestServiceImpl"/>
<bean id="testService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref local="testServiceTarget"/>
</property>
<property name="interceptorNames">
<list>
<value>methodCachePointCut</value>
<value>methodCachePointCutAdvice</value>
</list>
</property>
</bean>
</beans>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<import resource="cacheContext.xml"/>
<bean id="testServiceTarget" class="com.co.cache.test.TestServiceImpl"/>
<bean id="testService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref local="testServiceTarget"/>
</property>
<property name="interceptorNames">
<list>
<value>methodCachePointCut</value>
<value>methodCachePointCutAdvice</value>
</list>
</property>
</bean>
</beans>