ehcache.xml配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd">
<diskStore path="java.io.tmpdir" />
<defaultCache maxElementsInMemory="10000" eternal="false"
timeToIdleSeconds="30" timeToLiveSeconds="30" overflowToDisk="false" />
<!-- 配置自定義緩存 maxElementsInMemory:緩存中允許創建的最大對象數 eternal:緩存中對象是否爲永久的,如果是,超時設置將被忽略,對象從不過期。
timeToIdleSeconds:緩存數據的鈍化時間,也就是在一個元素消亡之前, 兩次訪問時間的最大時間間隔值,這只能在元素不是永久駐留時有效,
如果該值是 0 就意味着元素可以停頓無窮長的時間。 timeToLiveSeconds:緩存數據的生存時間,也就是一個元素從構建到消亡的最大時間間隔值,
這只能在元素不是永久駐留時有效,如果該值是0就意味着元素可以停頓無窮長的時間。 overflowToDisk:內存不足時,是否啓用磁盤緩存。 memoryStoreEvictionPolicy:緩存滿了之後的淘汰算法。 -->
<cache name="mobileCache" maxElementsInMemory="10000" eternal="false"
overflowToDisk="true" timeToIdleSeconds="1800" timeToLiveSeconds="3600"
memoryStoreEvictionPolicy="LFU" />
</ehcache>
spring配置文件applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config />
<context:component-scan base-package="com.wallet.*" />
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="wallet-web"></property>
<!-- value 對應persistence.xml中的 persistence-unit name -->
</bean>
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<span style="color:#FF9966;"><strong><!-- 配置eh緩存管理器 -->
<!--配置緩存管理器 -->
<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.easyway.MethodCache</value>
</property>
</bean>
<!-- 自定義緩存攔截器 -->
<bean id="methodCacheInterceptor" class="com.wallet.core.intercepter.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>
<!-- 下面的配置就使得在數據訪問時,cache將攔截從數據庫獲取的數據,與cache數據比較,如有就不放入cache,沒有就放入,更新到數據庫去,也是先存入cache,再更新到數據庫中去 -->
<property name="patterns">
<list>
<value>.*findAll</value>
<value>.*selectByCondis</value>
<value>.*selectAll</value>
</list>
</property>
</bean>
<!-- flush cache攔截器 -->
<bean id="methodCacheAfterAdvice" class="com.wallet.core.intercepter.MethodCacheAfterAdvice">
<property name="cache">
<ref local="methodCache" />
</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>
</list>
</property>
</bean>
<!-- 聲明一個服務 -->
<bean id="cascadeEventServiceTarget"
class="com.wallet.myWallet.service.impl.CascadeEventServiceImpl" />
<bean id="fixedExpensesAccountServiceTarget"
class="com.wallet.myWallet.service.impl.FixedExpensesAccountServiceImpl" />
<!-- 相關的服務 -->
<bean id="cascadeEventService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref local="cascadeEventServiceTarget" />
</property>
<property name="interceptorNames">
<list>
<value>methodCachePointCut</value>
</list>
</property>
</bean>
<bean id="fixedExpensesAccountService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref local="fixedExpensesAccountServiceTarget" />
</property>
<property name="interceptorNames">
<list>
<value>methodCachePointCut</value>
<value>methodCachePointCutAdvice</value>
</list>
</property>
</bean></strong></span>
<tx:annotation-driven transaction-manager="txManager" />
</beans>
spring與ehcache集成的相關配置主要在上色不分,其中主要用到了兩個攔截器一個是methodCacheInterceptor主要用於對查詢數據進行緩存;methodCacheAfterAdvice主要用於對save/update/delete的方法進行緩存。
methodCacheInterceptor
/**
* 方法攔截器,主要針對查詢方法進行緩存,
* 用戶每次查詢會現在緩存中根據cacheKey查找相應的數據,
* 有的話就只從緩存中取,沒有的話就去數據庫中查找,並將查詢結果存到緩存中
*/
public class MethodCacheInterceptor implements MethodInterceptor, InitializingBean {
private static final Logger log = Logger.getLogger(MethodCacheInterceptor.class);
private Cache cache;
public void setCache(Cache cache) {
this.cache = cache;
}
public void afterPropertiesSet() throws Exception {
log.info(cache + " A cache is required. Use setCache(Cache) to provide one.");
}
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);
Element element = null;
synchronized (this) {
element = cache.get(cacheKey);
if (element == null) {
log.info(cacheKey + "加入到緩存: " + cache.getName());
System.out.println("加入到緩存");
// 調用實際的方法
result = invocation.proceed();
element = new Element(cacheKey, (Serializable) result);
cache.put(element);
} else {
log.info(cacheKey + "使用緩存: " + cache.getName());
System.out.println("使用緩存");
}
}
return element.getValue();
}
/**
* <b>function:</b> 返回具體的方法全路徑名稱 參數
*
* @author hoojo
* @createDate 2012-7-2 下午06:12:39
* @param targetName 全路徑
* @param methodName 方法名稱
* @param arguments 參數
* @return 完整方法名稱
* @throws IllegalAccessException
* @throws InstantiationException
* @throws InvocationTargetException
* @throws IllegalArgumentException
*/
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(getArgument(arguments[i]));
}
}
return sb.toString();
}
/**
* 因爲查詢的參數是一個實體類,所以通過反射的方式獲取實體類中的屬性以及屬性值作爲cacheKey的一部分
*
* @param object
* @return
* @throws InstantiationException
* @throws InvocationTargetException
* @throws IllegalAccessException
* @throws IllegalArgumentException
* @throws NoSuchFieldException
* @throws SecurityException
*/
private String getArgument(Object object) throws Exception {
StringBuffer sb = new StringBuffer();
if(object!=null && !"".equals(object)){
System.out.println(object.getClass().getName());
Method[] methods = object.getClass().getDeclaredMethods();
for (Method m : methods) {
if (m.getName().startsWith("get")) {
String fieldName = m.getName().substring(3, m.getName().length()).toLowerCase();
Object obj1 = m.invoke(object, null);
if (obj1 != null && !"".equals(obj1)) {
sb.append(fieldName).append(obj1);
}
}
}
}
return sb.toString();
}
}
methodCacheAfterAdvice
/**
* 攔截器MethodCacheAfterAdvice,作用是在用戶進行create/update/delete操作時來刷新/remove相關cache內容,
* 這個攔截器實現了AfterReturningAdvice接口,將會在所攔截的方法執行後執行在public void afterReturning(Object arg0, Method
* arg1, Object[] arg2, Object arg3)方法中所預定的操作
*/
public class MethodCacheAfterAdvice implements AfterReturningAdvice, InitializingBean {
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);
}
}
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(cache, "Need a cache. Please use setCache(Cache) create it.");
}
}