利用spring的拦截器自定义缓存的实现

Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态、数据库驱动网站的速度。本文利用Memcached 的实例和spring的拦截器实现缓存自定义的实现。利用拦截器读取自定义的缓存标签,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如果需要前后通知的话,一般会实现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标签

	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标签

	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();
	}

根据参数生成key

	//使用拦截到方法的参数生成参数
	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();
	}

根据属性生成key

	private String getKeyWithProperties(Object o, String props[]) 
			throws Exception {
		StringBuilder key = new StringBuilder();
		boolean first = true;
		for (String prop: props) {
			//把bean的属性转为获取方法的名字
			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;
		}
	}

参数的设置

	//使用参数设置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);
		}
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值