于吉吉的技术博客

建造高性能门户网

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  65 随笔 :: 6 文章 :: 149 评论 :: 0 Trackbacks
由于系统需求需 要对各个接口进行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);  
 } 


----------------------------------------

陈于喆
Mail: chenyz@corp.netease.com

posted on 2010-08-23 10:35 陈于喆 阅读(8508) 评论(0)  编辑  收藏 所属分类: spring

只有注册用户登录后才能发表评论。


网站导航: