JDK的动态代理

来源:互联网 发布:python爬虫培训 编辑:程序博客网 时间:2024/06/05 02:35

    动态代理是Spring AOP的核心原理。以前一直停留在使用的表层认识上,这一阵子抽空研究了下。

    先说下静态代理,静态代理每次只为一个类服务。而且需要为每个类编写代理类代码。动态代理的优势则在于,不用为每个代理类编写代码,而是自动根据Class的文件格式去拼装代理类的字节码。

    DEMO

    接口

package reflect;/** * Created by cdlvsheng on 2016/4/11. */public interface Calculator {int add(int a, int  b);}


    实现类

package reflect;/** * Created by cdlvsheng on 2016/4/10. */public class CalculatorImpl implements Calculator{@Overridepublic int add(int a, int b) {int result = a + b;System.out.println(String.format("%d + %d = %d", a, b, result));return result;}}

    创建代理类及实现InvocationHandler接口

package reflect;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;/** * Created by cdlvsheng on 2016/4/11. */public class MyHandler implements InvocationHandler {private Object target;/** * 绑定委托对象并返回一个代理类 * * @param target * @return */public Object bind(Object target) {this.target = target;return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("invoke start");Object o = method.invoke(target, args);System.out.println("invoke end");return o;}}

    客户端调用

package reflect;/** * Created by cdlvsheng on 2016/4/11. */public class ProxyTest {public static void main(String[] args) {MyHandler  ih = new MyHandler();Calculator c  = (Calculator) ih.bind(new CalculatorImpl());c.add(3, 5);}}

    输出

invoke start3 + 5 = 8invoke end

    动态代理类的生成依赖Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)方法。这个方法的第一个参数是加载新的代理类字节码的类加载器,第二个参数是代理类实现的接口。所有代理类的接口方法都将由InvocationHandler的invoke方法替代。Proxy的这个方法会调用ProxyGenerator.generateProxyClass()生成代理类的字节码byte[]数组。通过在VM的启动参数里添加如下参数,我们生成的字节数组的具体内容。

-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true

    加上这个参数之后重新运行main后,我们发现项目的文件路径下多了一个$Proxy0.class类。通过反编译工具查看下这个类的内容。

//// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)//import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.lang.reflect.UndeclaredThrowableException;import reflect.Calculator;public final class $Proxy0 extends Proxy implements Calculator {    private static Method m1;    private static Method m0;    private static Method m3;    private static Method m2;    public $Proxy0(InvocationHandler var1) throws  {        super(var1);    }    public final boolean equals(Object var1) throws  {        try {            return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();        } catch (RuntimeException | Error var3) {            throw var3;        } catch (Throwable var4) {            throw new UndeclaredThrowableException(var4);        }    }    public final int hashCode() throws  {        try {            return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();        } catch (RuntimeException | Error var2) {            throw var2;        } catch (Throwable var3) {            throw new UndeclaredThrowableException(var3);        }    }    public final int add(int var1, int var2) throws  {        try {            return ((Integer)super.h.invoke(this, m3, new Object[]{Integer.valueOf(var1), Integer.valueOf(var2)})).intValue();        } catch (RuntimeException | Error var4) {            throw var4;        } catch (Throwable var5) {            throw new UndeclaredThrowableException(var5);        }    }    public final String toString() throws  {        try {            return (String)super.h.invoke(this, m2, (Object[])null);        } catch (RuntimeException | Error var2) {            throw var2;        } catch (Throwable var3) {            throw new UndeclaredThrowableException(var3);        }    }    static {        try {            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);            m3 = Class.forName("reflect.Calculator").getMethod("add", new Class[]{Integer.TYPE, Integer.TYPE});            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);        } catch (NoSuchMethodException var2) {            throw new NoSuchMethodError(var2.getMessage());        } catch (ClassNotFoundException var3) {            throw new NoClassDefFoundError(var3.getMessage());        }    }}

    可以看处动态生成的这个$Proxy0类的add方法,其实是调用了InvocationHandler类的invoke方法。它不仅实现了Calculator类的add方法,同时实现了Object类的所有非native非static类型的方法。

    这个是JDK提供的动态代理功能,它的一大劣势便是必须要求代理类实现接口。然而cglib的动态代理功能弥补了这一缺点。

1 0