Ehcache快取結合Spring AOP實現介面資料快取
阿新 • • 發佈:2019-02-17
下載安裝
JAVA程式碼塊
首先我們要想好要實現什麼樣的功能,我們需要攔截service層的增刪改查介面然後以不同的動作對快取進行不同的操作:查詢、獲取、列表等資料從快取獲取,刪除、修改等資料刪除已有快取
只新增快取和讀取快取
建立JAVA類MethodPutCacheInterceptor(快取攔截器)該類只對針對get、load、list、search介面做快取和讀取資料
public class MethodPutCacheInterceptor {
private Cache ehCache;
//通過spring注入方式例項化ehcache
public void setCache(Cache cache) {
this.ehCache = cache;
}
//建構函式
public MethodPutCacheInterceptor() {
super();
}
//spring AOP 方法被呼叫時被攔截
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
//獲取類名
String targetName = pjp.getTarget().getClass().getName();
//獲取方法名
String methodName = pjp.getSignature().getName();
//獲取引數
Object[] atguments = pjp.getArgs();
Object result;
//獲取cache key值
String cacheKey = getCacheKey(targetName, methodName, atguments);
//通過key獲取快取value
Element element = ehCache.get(cacheKey);
if (element == null) {
logger.info("從DB讀取資料!");
//執行連線點裡面的方法
result = pjp.proceed();
//將連線點方法返回的資料新增到快取裡
element = new Element(cacheKey, (Serializable) result);
ehCache.put(element);
} else {
logger.info("從快取讀取資料!");
}
//最終返回快取資料
return element.getObjectValue();
}
//spring aop 錯誤返回
public void doThrowing(JoinPoint jp, Throwable ex) {
System.out.println("method " + jp.getTarget().getClass().getName() + "." + jp.getSignature().getName() + " throw exception");
System.out.println(ex.getMessage());
}
/**
* 獲得cache key的方法,cache key是Cache中一個Element的唯一識
* cache key包括 包名+類名+方法名
* @param targetName 類名
* @param methodName 方法名
* @param arguments 引數名
* @return String
*/
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 (Object object : arguments) {
sb.append(".").append(object);
}
}
return sb.toString();
}
}
- 建立JAVA類MethodRemoveCacheInterceptor(快取攔截器)該類只對針對delete、remove、update介面做快取資料清除
public class MethodRemoveCacheInterceptor{
private Cache ehCache;
//通過spring注入方式例項化ehcache
public void setCache(Cache cache) {
this.ehCache = cache;
}
//建構函式
public MethodPutCacheInterceptor() {
super();
}
public void doAfter(JoinPoint jp) {
//獲取類名
String targetName = jp.getTarget().getClass().getName();
//獲取快取key集合
List list = ehCache.getKeys();
for (Object key : list) {
String cacheKey = String.valueOf(key);
//判斷key中是否含有該類名
if (cacheKey.startsWith(targetName)) {
//存在則刪除該快取
ehCache.remove(cacheKey);
}
}
}
public void doThrowing(JoinPoint jp, Throwable ex) {
//獲取錯誤資訊
System.out.println("method " +jp.getTarget().getClass().getName() + "." + jp.getSignature().getName() + " throw exception");
System.out.println(ex.getMessage());
}
}
applicationContext.xml配置
<!--注入EhCacheManagerFactoryBean-->
<bean id="defaultCacheManager"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<!--獲取ehcache.xml檔案-->
<property name="configLocation">
<value>classpath:cache/ehcache.xml</value>
</property>
</bean>
<!--注入EhCacheFactoryBean-->
<bean id="ehCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<!--指定父類cacheManager的bean-->
<property name="cacheManager" ref="defaultCacheManager" />
<!--指定ehcache.xml快取名為userCache的快取配置,沒找到則預設為defaultCache-->
<property name="cacheName">
<value>userCache</value>
</property>
</bean>
<!--將EhCacheFactoryBean注入到類MethodPutCacheInterceptor中cache物件中-->
<bean id="methodPutCacheInterceptor" class="dome.core.tools.ehcache.MethodPutCacheInterceptor">
<property name="cache" ref="ehCache" />
</bean>
<!--Spring AOP 實現配置-->
<!--實現service層中get、list、find介面攔截-->
<aop:config>
<aop:aspect id="MethodPutCacheInterceptor" ref="methodPutCacheInterceptor">
<aop:pointcut id="methodPutCacheService"
expression="execution(* dome.core.*.service.*.get*(..)) or
execution(* dome.core.*.service.*.list*(..)) or
execution(* dome.core.*.service.*.find*(..)))"></aop:pointcut>
<aop:around pointcut-ref="methodPutCacheService" method="doAround" />
<aop:after-throwing pointcut-ref="methodPutCacheService" method="doThrowing" throwing="ex" />
</aop:aspect>
</aop:config>
<!--實現service層中delete、remove、update介面攔截-->
<bean id="methodRemoveCacheInterceptor" class="dome.core.tools.ehcache.MethodRemoveCacheInterceptor">
<property name="cache" ref="ehCache" />
</bean>
<aop:config>
<aop:aspect id="MethodRemoveCacheInterceptor" ref="methodRemoveCacheInterceptor">
<aop:pointcut id="methodRemoveCacheService"
expression="execution(* dome.core.*.service.*.delete*(..)) or
execution(* dome.core.*.service.*.remove*(..)) or
execution(* dome.core.*.service.*.update*(..)))"></aop:pointcut>
<aop:after pointcut-ref="methodRemoveCacheService" method="doAfter" />
<aop:after-throwing pointcut-ref="methodRemoveCacheService" method="doThrowing" throwing="ex" />
</aop:aspect>
</aop:config>
ehcache.xml配置
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true"
monitoring="autodetect" dynamicConfig="true">
<diskStore path="java.io.tmpdir" />
<defaultCache
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="false" />
<cache name="userCache"
maxElementsInMemory="10000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="300000"
timeToLiveSeconds="600000"
memoryStoreEvictionPolicy="LFU">
</cache>
</ehcache>
每當程式呼叫service層介面時,就會判斷介面名是否以get、list、find開頭,如果是則進入spring aop攔截中判斷該方法是否在快取中,如果存在則直接從快取獲取返回值,如果不存在則直接執行連線點方法(業務類或者dao層)然後將返回值放入快取並返回快取中的資料。
如果呼叫serivce層delete、update、remove開頭的介面,則進入攔截器判斷是否存在該快取,如果存在則刪除快取。