1. 程式人生 > >使用自定義annotation接口進行aspectj動態緩存

使用自定義annotation接口進行aspectj動態緩存

執行方法 rip [] method inter interface ber == 語言

由於系統需求需 要對各個接口進行key-value緩存(以參數為key,返回的對象為value),

當然對於這種情況首先考慮到的是使用aop,前段時間看過 aspectj的一些介紹,

借此機會正好加以應用和體會一下,aspectj是AOP最早成熟的java實現,

它稍微擴展了一下java語言,增加了一些 keyword等,具體的aspectj的基本語法見這裏,進行緩存的框架使用較成熟的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下的配置

<!-- ##############  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

@Target({ElementType.METHOD,ElementType.TYPE})  
 @Retention(RetentionPolicy.RUNTIME)  
 @Documented  
 public @interface MethodCache {  
     int second() default 0;   
 }  

<bean id = "methodCacheAspectJ">是一個aspectj進行Pointcuts和Advice的類需註入methodCache

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

使用自定義annotation接口進行aspectj動態緩存