zl198751 发表于 2013-2-3 10:31:20

Java AOP

OP有三种织入切面的方法:其一是编译期织入,这要求使用特殊的Java编译器,AspectJ是其中的代表者;其二是类装载期织入,而这要求使用特殊的类装载器,AspectJ和AspectWerkz是其中的代表者;其三为动态代理织入,在运行期为目标类添加增强生成子类的方式,Spring AOP采用动态代理织入切面。
Spring AOP使用了两种代理机制,一种是基于JDK的动态代理,另一种是基于CGLib的动态代理,之所以需要两种代理机制,很大程度上是因为JDK本身只提供基于接口的代理,不支持类的代理。


切入点一般是方法调用之前,之后或者两端。接下来分别介绍下JDK的动态代理和CGLib的动态代理。


JDK动态代理


JDK的动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler。
InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑,在并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编织在一起。
Proxy为InvocationHandler实现类动态创建一个符合某一接口的代理实例。


接口:


package test.aop.jdk;public interface Bussiness {    public void doFirst(String thing);      public void doSecond(String thing);    }

实现类:
package test.aop.jdk;public class BussinessImpl implements Bussiness{    @Override    public void doFirst(String thing) {      System.out.println("Do First Bussiness:" + thing);            }    @Override    public void doSecond(String thing) {      System.out.println("Do Second Bussiness:" + thing);    }    }

代理类:
package test.aop.jdk;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;public class BussinessHandle implements InvocationHandler{      public Object target;      public BussinessHandle(Object target) {//①target为目标的业务类      this.target = target;    }      @Override    public Object invoke(Object proxy, Method method, Object[] args)            throws Throwable {      System.out.println("add aspect before method invocation.");      Object o = method.invoke(this.target, args); //②通过反射方法调用目标业务类的业务方法      System.out.println("add aspect after method invocation.");                return o;    }}实现InvocationHandler接口,该接口定义了一个 invoke(Object proxy, Method method, Object[] args)的方法,proxy是代理实例,一般不会用到;method是代理实例上的方法,通过它可以发起对目标类的反射调用;args是通过代理类传入的方法参数,在反射调用时使用。




调用:
package test.aop.jdk;import java.lang.reflect.Proxy;public class JDKDynamicProxy {    public static void main(String[] args) {      Bussiness b = new BussinessImpl();                BussinessHandle handle = new BussinessHandle(b);                Bussiness proxy = (Bussiness) Proxy.newProxyInstance(b.getClass().getClassLoader(),               b.getClass().getInterfaces(), handle);                        proxy.doFirst("Hello World");      proxy.doSecond("Bye Bye");    }} 
CGLib动态代理


被代理的类:
package test.aop.cglib;public class BussinessImpl{    public void doFirst(String thing) {      System.out.println("Do First Bussiness:" + thing);            }    public void doSecond(String thing) {      System.out.println("Do Second Bussiness:" + thing);    }    }

代理类:
package test.aop.cglib;import java.lang.reflect.Method;import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;public class CGLibDynamicProxy implements MethodInterceptor{    private Enhancer enhancer = new Enhancer();      public Object getProxy(Class c) {      enhancer.setSuperclass(c); // ① 设置需要创建子类的类      enhancer.setCallback(this);      return enhancer.create(); // ②通过字节码技术动态创建子类实例    }      @Override    public Object intercept(Object arg0, Method arg1, Object[] arg2,            MethodProxy arg3) throws Throwable {                System.out.println("add aspect before method invocation.");      arg3.invokeSuper(arg0, arg2);      System.out.println("add aspect after method invocation.");                return null;    }    public static void main(String[] args) {      CGLibDynamicProxy proxy = new CGLibDynamicProxy();      BussinessImpl business = (BussinessImpl) proxy.getProxy(BussinessImpl.class);      business.doFirst("Hello World");      business.doSecond("Bye Bye");            }    } 
intercept(Object obj, Method method, Object[] args,MethodProxy proxy)是CGLib定义的Inerceptor接口的方法,obj表示代理后的子类,method为父类方法的反射对象,args为方法的动态入参,而proxy为代理类实例。一般使用proxy进行调用父类方法,这样更快。




JDK和CGLib的速度比较:


从jdk1.5以后包括1.5,jdk(去掉安全检查后)和cglib基本相同,cglib会快一点。
页: [1]
查看完整版本: Java AOP