annotation和Spring的动态缓存文章
由于系统需求需要对各个接口进行key-value缓存(以参数为key,返回的对象为value),当然对于这种情况首先考虑到的是使用aop,前段时间看过aspectj的一些介绍,借此机会正好加以应用和体会一下,aspectj是AOP最早成熟的java实现,它稍微扩展了一下java语言,增加了一些keyword等,具体的aspectj的基本语法见[ur=http://today.java.net/pub/a/today/2003/12/26/ch3AspectJSyntaxBasics.html]这里[/url],进行缓存的框架使用较成熟的ehcache.
下面开始进行配置
首先是ehcache的配置文件
- <?xml version="1.0" encoding="UTF-8"?>
- <ehcache>
- <diskStore path="/home/workspace/gzshine/trunk/ehcache"/>
- <cache name="DEFAULT_CACHE"
- maxElementsInMemory="10000"
- eternal="false"
- timeToIdleSeconds="3600"
- timeToLiveSeconds="3600"
- overflowToDisk="true"
- />
- </ehcache>
这个的DEFAULT_CACHE是默认配置,最大的缓存数为10000,时间为一个小时
接下来的是spring下的配置
- <?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:aop="http://www.springframework.org/schema/aop"
- 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-2.5.xsd
- http://www.springframework.org/schema/tx
- http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
- http://www.springframework.org/schema/aop
- http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-2.5.xsd">
- <!-- ############## aspectj 4 ehcache ############# -->
- <aop:aspectj-autoproxy proxy-target-class="true"/>
- <bean id = "methodCacheAspectJ" class="com.***.shine.aspectj.MethodCacheAspectJ" >
- <property name="cache">
- <ref local="methodCache" />
- </property>
- </bean>
- <bean id="cacheManager"
- class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
- <property name="configLocation">
- <value>classpath:ehcache.xml</value>
- </property>
- </bean>
- <!-- 定义ehCache的工厂,并设置所使用的Cache name -->
- <bean id="methodCache"
- class="org.springframework.cache.ehcache.EhCacheFactoryBean">
- <property name="cacheManager">
- <ref local="cacheManager" />
- </property>
- <property name="cacheName">
- <value>DEFAULT_CACHE</value>
- </property>
- </bean>
<aop:aspectj-autoproxy proxy-target-class="true"/>
是为aspectj在所有class下开启自动动态代理
<bean id="cacheManager">指定刚刚的ehcache配置文件
接下来编写一个自定义的annotation
- package com.***.shine.cache;
- import java.lang.annotation.Documented;
- import java.lang.annotation.ElementType;
- import java.lang.annotation.Retention;
- import java.lang.annotation.RetentionPolicy;
- import java.lang.annotation.Target;
- @Target({ElementType.METHOD,ElementType.TYPE})
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- public @interface MethodCache {
- int second() default 0;
- }
<bean id = "methodCacheAspectJ">是一个aspectj进行Pointcuts和Advice的类需注入methodCache
- package com.***.shine.aspectj;
- @Aspect
- public class MethodCacheAspectJ {
- Log logger = LogFactory.getLog(MethodCacheAspectJ.class);
- private Cache cache;
- /**
- * 设置缓存名
- */
- public void setCache(Cache cache) {
- this.cache = cache;
- }
- @Pointcut("@annotation(com.***.shine.cache.MethodCache)")
- public void methodCachePointcut(){
- }
- @Around("methodCachePointcut()")
- public Object methodCacheHold(ProceedingJoinPoint joinPoint) throws Throwable{
- String targetName = joinPoint.getTarget().getClass().getName();
- String methodName = joinPoint.getSignature().getName();
- Object[] arguments = joinPoint.getArgs();
- Object result = null;
- String cacheKey = getCacheKey(targetName, methodName, arguments);
- Element element = cache.get(cacheKey);
- if (element == null) {
- try{
- result = joinPoint.proceed();
- }catch(Exception e){
- logger.info(e);
- }
- if(result!=null){
- try{
- element = new Element(cacheKey, (Serializable) result);
- Class targetClass = Class.forName(targetName);
- Method[] method = targetClass.getMethods();
- int second = 0;
- for(Method m:method){
- if (m.getName().equals(methodName)) {
- Class[] tmpCs = m.getParameterTypes();
- if(tmpCs.length==arguments.length){
- MethodCache methodCache = m.getAnnotation(MethodCache.class);
- second = methodCache.second();
- break;
- }
- }
- }
- if(second>0){ // annotation没有设second值则使用ehcache.xml中自定义值
- element.setTimeToIdle(second);
- element.setTimeToLive(second);
- }
- cache.put(element);
- }catch(Exception e){
- logger.info("!!!!!!!!!"+cacheKey+"!!!!!!!!!未能执行方法缓存"+e);
- }
- }
- }
- return element.getValue();
- }
- 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 (int i = 0; i < arguments.length; i++) {
- if (arguments[i] instanceof Date) {
- sb.append(".").append(
- DateUtil.datetoString((Date) arguments[i]));
- } else {
- sb.append(".").append(arguments[i]);
- }
- }
- }
- return sb.toString();
- }
- }
@Pointcut("@annotation(com.netease.shine.cache.MethodCache)")
对有应用com.netease.shine.cache.MethodCache进行注解的方法进行横切面拦截
@Around("methodCachePointcut()")
并在Advice中处理这个Pointcut,这里的的Advice使用的是Around(环绕通知)
String cacheKey = getCacheKey(targetName, methodName, arguments);
接下来使用类型,方法名,参数为key进入缓存处理
Element element = cache.get(cacheKey);
当然如果在cache队列中取得非null对象则直接返回该对象
MethodCache methodCache = m.getAnnotation(MethodCache.class);
second = methodCache.second();
取得second的值(缓存的时间,如在@annotation中无重写只为int second() default 0)
element.setTimeToIdle(second);
element.setTimeToLive(second);
如果非零则重新设置缓存时间
- @MethodCache(second=300)
- public List<Sort> getSort(int type,int parentid){
- System.out.println("!!!!!!!!!!!!!没缓存到");
- Row row = new Row();
- row.put("type", type);
- row.put("parentid", parentid);
- return (List<Sort>)gz_Template.queryForList("sort.getSort", row);
- }
最后需要将@MethodCache要缓存方法的实现类
posted on 2011-10-08 12:00 苏桓(osbert) 阅读(191) 评论(0) 收藏 举报
浙公网安备 33010602011771号