利用spring的攔截器自定義緩存的實(shí)現(xiàn)實(shí)例代碼
本文研究的主要是利用spring的攔截器自定義緩存的實(shí)現(xiàn),具體實(shí)現(xiàn)代碼如下所示。
Memcached 是一個(gè)高性能的分布式內(nèi)存對象緩存系統(tǒng),用于動態(tài)Web應(yīng)用以減輕數(shù)據(jù)庫負(fù)載。它通過在內(nèi)存中緩存數(shù)據(jù)和對象來減少讀取數(shù)據(jù)庫的次數(shù),從而提高動態(tài)、數(shù)據(jù)庫驅(qū)動網(wǎng)站的速度。本文利用Memcached 的實(shí)例和spring的攔截器實(shí)現(xiàn)緩存自定義的實(shí)現(xiàn)。利用攔截器讀取自定義的緩存標(biāo)簽,key值的生成策略。
自定義的Cacheable
package com.jeex.sci;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Cacheable {
String namespace();
String key() default "";
int[] keyArgs() default {
}
;
String[] keyProperties() default {
}
;
String keyGenerator() default "";
int expires() default 1800;
}
自定義的CacheEvict
package com.jeex.sci;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface CacheEvict {
String namespace();
String key() default "";
int[] keyArgs() default {
}
;
String[] keyProperties() default {
}
;
String keyGenerator() default "";
}
spring如果需要前后通知的話,一般會實(shí)現(xiàn)MethodInterceptor public Object invoke(MethodInvocation invocation) throws Throwable
public Object invoke(MethodInvocation invoction) throws Throwable {
Method method = invoction.getMethod();
Cacheable c = method.getAnnotation(Cacheable.class);
if (c != null) {
return handleCacheable(invoction, method, c);
}
CacheEvict ce = method.getAnnotation(CacheEvict.class);
if (ce != null) {
return handleCacheEvict(invoction, ce);
}
return invoction.proceed();
}
處理cacheable標(biāo)簽
private Object handleCacheable(MethodInvocation invoction, Method method,
Cacheable c) throws Throwable {
String key = getKey(invoction, KeyInfo.fromCacheable(c));
if (key.equals("")) {
if (log.isDebugEnabled()){
log.warn("Empty cache key, the method is " + method);
}
return invoction.proceed();
}
long nsTag = (long) memcachedGet(c.namespace());
if (nsTag == null) {
nsTag = long.valueOf(System.currentTimeMillis());
memcachedSet(c.namespace(), 24*3600, long.valueOf(nsTag));
}
key = makeMemcachedKey(c.namespace(), nsTag, key);
Object o = null;
o = memcachedGet(key);
if (o != null) {
if (log.isDebugEnabled()) {
log.debug("CACHE HIT: Cache Key = " + key);
}
} else {
if (log.isDebugEnabled()) {
log.debug("CACHE MISS: Cache Key = " + key);
}
o = invoction.proceed();
memcachedSet(key, c.expires(), o);
}
return o;
}
處理cacheEvit標(biāo)簽
private Object handleCacheEvict(MethodInvocation invoction,
CacheEvict ce) throws Throwable {
String key = getKey(invoction, KeyInfo.fromCacheEvict(ce));
if (key.equals("")) {
if (log.isDebugEnabled()) {
log.debug("Evicting " + ce.namespace());
}
memcachedDelete(ce.namespace());
} else {
Long nsTag = (Long) memcachedGet(ce.namespace());
if (nsTag != null) {
key = makeMemcachedKey(ce.namespace(), nsTag, key);
if (log.isDebugEnabled()) {
log.debug("Evicting " + key);
}
memcachedDelete(key);
}
}
return invoction.proceed();
}
根據(jù)參數(shù)生成key
//使用攔截到方法的參數(shù)生成參數(shù)
private String getKeyWithArgs(Object[] args, int[] argIndex) {
StringBuilder key = new StringBuilder();
boolean first = true;
for (int index: argIndex) {
if (index < 0 || index >= args.length) {
throw new IllegalArgumentException("Index out of bound");
}
if (!first) {
key.append(':');
} else {
first = false;
}
key = key.append(args[index]);
}
return key.toString();
}
根據(jù)屬性生成key
private String getKeyWithProperties(Object o, String props[])
throws Exception {
StringBuilder key = new StringBuilder();
boolean first = true;
for (String prop: props) {
//把bean的屬性轉(zhuǎn)為獲取方法的名字
String methodName = "get"
+ prop.substring(0, 1).toUpperCase()
+ prop.substring(1);
Method m = o.getClass().getMethod(methodName);
Object r = m.invoke(o, (Object[]) null);
if (!first) {
key.append(':');
} else {
first = false;
}
key = key.append(r);
}
return key.toString();
}
利用自定義的生成器生成key
//使用生成器生成key
private String getKeyWithGenerator(MethodInvocation invoction, String keyGenerator)
throws Exception {
Class<?> ckg = Class.forName(keyGenerator);
CacheKeyGenerator ikg = (CacheKeyGenerator)ckg.newInstance();
return ikg.generate(invoction.getArguments());
}
保存key信息的幫助類
private static class KeyInfo {
String key;
int[] keyArgs;
String keyProperties[];
String keyGenerator;
static KeyInfo fromCacheable(Cacheable c) {
KeyInfo ki = new KeyInfo();
ki.key = c.key();
ki.keyArgs = c.keyArgs();
ki.keyGenerator = c.keyGenerator();
ki.keyProperties = c.keyProperties();
return ki;
}
static KeyInfo fromCacheEvict(CacheEvict ce) {
KeyInfo ki = new KeyInfo();
ki.key = ce.key();
ki.keyArgs = ce.keyArgs();
ki.keyGenerator = ce.keyGenerator();
ki.keyProperties = ce.keyProperties();
return ki;
}
String key() {
return key;
}
int[] keyArgs() {
return keyArgs;
}
String[] keyProperties() {
return keyProperties;
}
String keyGenerator() {
return keyGenerator;
}
}
參數(shù)的設(shè)置
//使用參數(shù)設(shè)置key
@Cacheable(namespace="BlackList", keyArgs={0, 1})
public int anotherMethond(int a, int b) {
return 100;
}
測試類:
package com.jeex.sci.test;
import net.spy.memcached.MemcachedClient;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class TestMain {
public static void main(String args[]) throws InterruptedException{
ApplicationContext ctx = new FileSystemXmlApplicationContext("/src/test/resources/beans.xml");
MemcachedClient mc = (MemcachedClient) ctx.getBean("memcachedClient");
BlackListDaoImpl dao = (BlackListDaoImpl)ctx.getBean("blackListDaoImpl");
while (true) {
System.out.println("################################GETTING START######################");
mc.flush();
BlackListQuery query = new BlackListQuery(1, "222.231.23.13");
dao.searchBlackListCount(query);
dao.searchBlackListCount2(query);
BlackListQuery query2 = new BlackListQuery(1, "123.231.23.14");
dao.anotherMethond(333, 444);
dao.searchBlackListCount2(query2);
dao.searchBlackListCount3(query2);
dao.evict(query);
dao.searchBlackListCount2(query);
dao.evictAll();
dao.searchBlackListCount3(query2);
Thread.sleep(300);
}
}
}
總結(jié)
以上就是本文關(guān)于利用spring的攔截器自定義緩存的實(shí)現(xiàn)實(shí)例代碼的全部內(nèi)容,希望對大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站其他相關(guān)專題,如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!
相關(guān)文章
Java基于Lock的生產(chǎn)者消費(fèi)者模型示例
這篇文章主要介紹了Java基于Lock的生產(chǎn)者消費(fèi)者模型,結(jié)合實(shí)例形式分析了java基于鎖機(jī)制的生產(chǎn)者消費(fèi)者模型相關(guān)實(shí)現(xiàn)與使用技巧,需要的朋友可以參考下2018-08-08
MyBatis配置的應(yīng)用與對比jdbc的優(yōu)勢
這篇文章主要介紹了MyBatis配置的使用與相對于jdbc的優(yōu)勢,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07
Spring?Boot?實(shí)現(xiàn)?WebSocket?的代碼示例
WebSocket?協(xié)議是獨(dú)立的基于?TCP?協(xié)議。它與?HTTP?的唯一關(guān)系是,它的握手會被?HTTP?服務(wù)器解釋為?Upgrade?請求,接下來通過本文給大家介紹Spring?Boot?實(shí)現(xiàn)?WebSocket?示例詳解,需要的朋友可以參考下2022-04-04
SpringCloud如何實(shí)現(xiàn)Zuul集群(負(fù)載均衡)
這篇文章主要介紹了SpringCloud如何實(shí)現(xiàn)Zuul集群(負(fù)載均衡)的操作,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07
springMVC+jersey實(shí)現(xiàn)跨服務(wù)器文件上傳
這篇文章主要介紹了springMVC+jersey實(shí)現(xiàn)跨服務(wù)器文件上傳,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-08-08
springboot多個(gè)service互相調(diào)用的事務(wù)處理方式
這篇文章主要介紹了springboot多個(gè)service互相調(diào)用的事務(wù)處理方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02
SpringBoot讀取yml文件中配置數(shù)組的2種方法
這篇文章主要介紹了SpringBoot讀取yml文件中配置數(shù)組的2種方法,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12

