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代码  收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <ehcache>  
  3.     <diskStore path="/home/workspace/gzshine/trunk/ehcache"/>  
  4.     <cache name="DEFAULT_CACHE"  
  5.         maxElementsInMemory="10000"  
  6.         eternal="false"  
  7.         timeToIdleSeconds="3600"  
  8.         timeToLiveSeconds="3600"  
  9.         overflowToDisk="true"  
  10.         />  
  11. </ehcache>   


这个的DEFAULT_CACHE是默认配置,最大的缓存数为10000,时间为一个小时

接下来的是spring下的配置

Xml代码  收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.     xmlns:aop="http://www.springframework.org/schema/aop"  
  5.     xmlns:tx="http://www.springframework.org/schema/tx"  
  6.     xmlns:context="http://www.springframework.org/schema/context"  
  7.     xsi:schemaLocation="  
  8.        http://www.springframework.org/schema/beans  
  9.        http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
  10.        http://www.springframework.org/schema/tx  
  11.        http://www.springframework.org/schema/tx/spring-tx-2.5.xsd  
  12.        http://www.springframework.org/schema/aop  
  13.        http://www.springframework.org/schema/aop/spring-aop-2.5.xsd  
  14.        http://www.springframework.org/schema/context  
  15.        http://www.springframework.org/schema/context/spring-context-2.5.xsd">  
  16.   
  17. <!-- ##############  aspectj 4 ehcache   ############# -->  
  18.       
  19.     <aop:aspectj-autoproxy proxy-target-class="true"/>  
  20.     <bean id = "methodCacheAspectJ" class="com.***.shine.aspectj.MethodCacheAspectJ" >  
  21.         <property name="cache">  
  22.             <ref local="methodCache" />  
  23.         </property>  
  24.     </bean>  
  25.       
  26.     <bean id="cacheManager"  
  27.         class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">  
  28.         <property name="configLocation">  
  29.             <value>classpath:ehcache.xml</value>  
  30.         </property>  
  31.     </bean>  
  32.       
  33.     <!-- 定义ehCache的工厂,并设置所使用的Cache name -->  
  34.       
  35.     <bean id="methodCache"  
  36.         class="org.springframework.cache.ehcache.EhCacheFactoryBean">  
  37.         <property name="cacheManager">  
  38.             <ref local="cacheManager" />  
  39.         </property>  
  40.         <property name="cacheName">  
  41.             <value>DEFAULT_CACHE</value>  
  42.         </property>  
  43.     </bean>  



<aop:aspectj-autoproxy proxy-target-class="true"/>
是为aspectj在所有class下开启自动动态代理
<bean id="cacheManager">指定刚刚的ehcache配置文件


接下来编写一个自定义的annotation

Java代码  收藏代码
  1. package com.***.shine.cache;  
  2.   
  3. import java.lang.annotation.Documented;  
  4. import java.lang.annotation.ElementType;  
  5. import java.lang.annotation.Retention;  
  6. import java.lang.annotation.RetentionPolicy;  
  7. import java.lang.annotation.Target;  
  8.   
  9. @Target({ElementType.METHOD,ElementType.TYPE})  
  10. @Retention(RetentionPolicy.RUNTIME)  
  11. @Documented  
  12. public @interface MethodCache {  
  13.     int second() default 0;   
  14. }  



<bean id = "methodCacheAspectJ">是一个aspectj进行Pointcuts和Advice的类需注入methodCache

Java代码  收藏代码
  1. package com.***.shine.aspectj;  
  2.   
  3. @Aspect  
  4. public class MethodCacheAspectJ {  
  5.     Log logger = LogFactory.getLog(MethodCacheAspectJ.class);  
  6.       
  7.     private Cache cache;  
  8.       
  9.     /** 
  10.      * 设置缓存名 
  11.      */  
  12.     public void setCache(Cache cache) {  
  13.         this.cache = cache;  
  14.     }   
  15.       
  16.     @Pointcut("@annotation(com.***.shine.cache.MethodCache)")  
  17.     public void methodCachePointcut(){    
  18.     }  
  19.       
  20.     @Around("methodCachePointcut()")  
  21.     public Object methodCacheHold(ProceedingJoinPoint joinPoint) throws Throwable{  
  22.         String targetName = joinPoint.getTarget().getClass().getName();  
  23.         String methodName = joinPoint.getSignature().getName();  
  24.         Object[] arguments = joinPoint.getArgs();  
  25.         Object result = null;  
  26.         String cacheKey = getCacheKey(targetName, methodName, arguments);  
  27.         Element element = cache.get(cacheKey);  
  28.         if (element == null) {  
  29.             try{  
  30.                 result = joinPoint.proceed();  
  31.             }catch(Exception e){  
  32.                 logger.info(e);  
  33.             }  
  34.             if(result!=null){  
  35.                 try{  
  36.                     element = new Element(cacheKey, (Serializable) result);  
  37.                     Class targetClass = Class.forName(targetName);  
  38.                     Method[] method = targetClass.getMethods();  
  39.                     int second = 0;  
  40.                     for(Method m:method){  
  41.                         if (m.getName().equals(methodName)) {  
  42.                             Class[] tmpCs = m.getParameterTypes();  
  43.                             if(tmpCs.length==arguments.length){  
  44.                                 MethodCache methodCache = m.getAnnotation(MethodCache.class);  
  45.                                 second = methodCache.second();  
  46.                                 break;  
  47.                             }  
  48.                         }  
  49.                     }  
  50.                     if(second>0){ // annotation没有设second值则使用ehcache.xml中自定义值  
  51.                         element.setTimeToIdle(second);  
  52.                         element.setTimeToLive(second);  
  53.                     }  
  54.                     cache.put(element);  
  55.                 }catch(Exception e){  
  56.                     logger.info("!!!!!!!!!"+cacheKey+"!!!!!!!!!未能执行方法缓存"+e);  
  57.                 }  
  58.             }  
  59.         }  
  60.         return element.getValue();  
  61.     }  
  62.   
  63.      private String getCacheKey(String targetName, String methodName,  
  64.             Object[] arguments) {  
  65.         StringBuffer sb = new StringBuffer();  
  66.         sb.append(targetName).append(".").append(methodName);  
  67.         if ((arguments != null) && (arguments.length != 0)) {  
  68.             for (int i = 0; i < arguments.length; i++) {  
  69.                 if (arguments[i] instanceof Date) {  
  70.                     sb.append(".").append(  
  71.                             DateUtil.datetoString((Date) arguments[i]));  
  72.                 } else {  
  73.                     sb.append(".").append(arguments[i]);  
  74.                 }  
  75.             }  
  76.         }  
  77.         return sb.toString();  
  78.     }  
  79. }  



@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);
如果非零则重新设置缓存时间

Java代码  收藏代码
  1. @MethodCache(second=300)  
  2. public List<Sort> getSort(int type,int parentid){  
  3.     System.out.println("!!!!!!!!!!!!!没缓存到");  
  4.     Row row = new Row();  
  5.     row.put("type", type);  
  6.     row.put("parentid", parentid);  
  7.     return (List<Sort>)gz_Template.queryForList("sort.getSort", row);  
  8. }  



最后需要将@MethodCache要缓存方法的实现类

posted on 2011-10-08 12:00  苏桓(osbert)  阅读(191)  评论(0)    收藏  举报

导航