spring Aop 之方法缓存

    因为公司人手原因,最近在为项目搭建架构,在异常,缓存,日志,方面都打算用Aop来做,在原来的项目中对在对异常,日志方面可能都是Log log=Logfactory.getLog();这样既麻烦,又紧耦合在一起。所以打算用Aop试试。下面是对一些缓存对象的Aop处理。主要是根据方法签名来做key值。

    定义一个注解

  

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

 

    定义一个业务处理类

 

public class Sev {
	@MethodCache(second=3)
	public Map getSort(int type,int parentid){
		System.out.println("no cache----");
		Map m =new HashMap();
		return m;
	}
	
	@MethodCache(second=3)
	public void getSort(){
		System.out.println("no cache----");
	}
}

 

   定义一个Aop

 

import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Date;

import net.sf.ehcache.Cache;
import net.sf.ehcache.Element;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class MethodCacheAspectJ {
	
	private Cache cache;
	
	/**
	 * 设置缓存名
	 */
	public void setCache(Cache cache) {
		this.cache = cache;
	} 
	
	@Pointcut("@annotation(com.zhang.shine.cache.MethodCache)")
	public void methodCachePointcut(){	
	}
	
	@Around("methodCachePointcut()")
	public Object methodCacheHold(ProceedingJoinPoint joinPoint) throws Throwable{
		System.out.println("aop start ");
		String targetName = joinPoint.getTarget().getClass().getName();
		String methodName = joinPoint.getSignature().getName();
		Object[] arguments = joinPoint.getArgs();
		Object result = null;
		String cacheKey = getCacheKey(targetName, methodName, arguments);
		System.out.println("key--"+cacheKey);
		Element element = cache.get(cacheKey);
		if (element == null) {
			try{
				result = joinPoint.proceed();
			}catch(Exception 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){
				}
			}
		}
		System.out.println("aop end ");
		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();
	}
}

 

    Spring配置文件

   

<bean id = "methodCacheAspectJ" class="com.zhang.shine.cache.MethodCacheAspectJ" >
		<property name="cache">
			<!-- <ref local="methodCache" /> -->
			<ref bean="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>
<bean id="sev" class="com.zhang.shine.cache.Sev"></bean>

 

    ehcache.xml

  

 

<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
    <diskStore path="/home/workspace/gzshine/trunk/ehcache"/>
	
	<defaultCache 
		maxElementsInMemory="50000" 
		eternal="false" 
		overflowToDisk="false" 
		timeToIdleSeconds="7200"
		timeToLiveSeconds="7200" 
		diskPersistent="false" 
		diskExpiryThreadIntervalSeconds="120"/>
		
	<cache name="DEFAULT_CACHE"
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="3600"
        timeToLiveSeconds="3600"
        overflowToDisk="true"
        />
</ehcache> 

 

   测试类

 

package test;



import net.sf.cglib.core.DebuggingClassWriter;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.zhang.shine.cache.CallImpl;
import com.zhang.shine.cache.MyImpl;
import com.zhang.shine.cache.Sev;
import sun.misc.*;
/**
 * 1.产生代理类$Proxy0类

执行了Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)

将产生$Proxy0类,它继承Proxy对象,并根据第二个参数,实现了被代理类的所有接口,自然就可以生成接口要实现的所有方法了(这时候会重写hashcode,toString和equals三个方法),但是还没有具体的实现体;

2.   将代理类$Proxy0类加载到JVM中

这时候是根据Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)它的第一个参数----就是被代理类的类加载器,把当前的代理类加载到JVM中

3.   创建代理类$Proxy0类的对象

调用的$Proxy0类的$Proxy0(InvocationHandler)构造函数,生成$Proxy0类的对象

参数就是Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)它的第三个参数

这个参数就是我们自己实现的InvocationHandler对象,我们知道InvocationHandler对象中组合加入了代理类代理的接口类的实现类;所以,$Proxy0对象调用所有要实现的接口的方法,都会调用InvocationHandler对象的invoke()方法实现;

4.   生成代理类的class byte

动态代理生成的都是二进制class字节码

 * @author zhang_zengmin
 *
 */
public class TestAOP {
	public static void main(String[] args) throws Exception{
   //cglib 代理对象class文件输出目录 如果是jdk动态代理就不输出
    /**
     * cglib头部信息
       public class Sev$$EnhancerByCGLIB$$bb4c2585 extends Sev
       implements SpringProxy, Advised, Factory
     */
	System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,  "c://class" );
	
	
		
      ApplicationContext ap =new ClassPathXmlApplicationContext("ApplicationContent.xml");
      Sev s = (Sev)ap.getBean("sev");
      //Sev s = new Sev();
      s.getSort(1, 2);
      //Thread.sleep(3010);
      s.getSort(1, 3);
     // s.getSort();
      System.out.println(s.getClass());
      
      MyImpl my=(MyImpl)ap.getBean("my");

       my.pao();
        //动态代理获取字节码  头部信息
       //public final class $Proxy0 extends Proxy implements Manager {

       /*byte[] proxyClassFile =	ProxyGenerator.generateProxyClass(
   		    proxyName, interfaces);*/
       
      /**
       * 接口默认Jdk代理
       */
     // ICall call = (ICall)ap.getBean("call");
      
     // call.cll();
       
     // Thread.sleep(60000);
     
     /* Enhancer enhancer = new Enhancer();//通过类Enhancer创建代理对象   
           enhancer.setSuperclass(Sev.class);//传入创建代理对象的类   
      
      
      ClassReader cr = new ClassReader(enhancer.getClass().getName());
      
      
       byte[] a = cr.b; 
       File f =new File("c://Sev.class");
       FileOutputStream  fout = new FileOutputStream(f);
       fout.write(a);
       fout.flush();
       fout.close();*/
       

     
     
	}
}

 

你可能感兴趣的:(spring aop)