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)@Documentedpublic @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;@Aspectpublic 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" ><property name="cache"><!-- <ref local="methodCache" /> --><ref bean="methodCache"/></property></bean><bean id="cacheManager"/></property><property name="cacheName"><value>DEFAULT_CACHE</value></property></bean><bean id="sev" name="code"><?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();*/ }}?