Java 动态代理 理解

动态代理

这里暂时只作JDK动态代理分析。动态代理应用普遍,例如AOP。java

clipboard.png

clipboard.png
clipboard.png
clipboard.png
clipboard.png

吐槽本身一下,设计的类,接口名不是很好。。anyway,大体就是这样。根据规范,Mama类实现InvocationHandler接口,实现invoke方法。以后经过Proxy类的静态方法newProxyInstance取得一个代理类实例eat(再次鄙视本身)。当eat.eat()时,调用了Mama的invoke方法。
很好奇,源码是如何实现代理的。值得一提,JDK动态代理把equals(),toString(),hashCode()也代理了。app

源码分析

clipboard.png

clipboard.png

clipboard.png
一路debug发现,最后调用了Proxy类下内部类ProxyClassFactory的apply方法,其中包含的下列代码最终动态地建立了proxy class 文件函数

clipboard.png

这时咱们反编译看看,最后编译成功的proxy class源码分析

public final class KidProxy extends Proxy implements Eat {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;

    public KidProxy(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 void eat() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

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

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

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
            m3 = Class.forName("com.ProxyDemo.Eat").getMethod("eat", new Class[0]);
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

经过构造函数KidProxy(InvocationHandler var1)初始化类instance,这个super(var1)便是Proxy的构造函数Proxy(InvocationHandler invocationHandler)便是静态方法newProxyInstance传过去的参数。具体的调用又是在newProxyInstance方法中的最后一句this

return cons.newInstance(new Object[]{h});

可知是经过反射实例化proxy对象的,一样的在构造proxy class文件时,也是经过反射,经过其实现的interfaces的具体方法将须要实现的method写入proxy class文件的。在记载class文件时,经过static构建method。spa

static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
            m3 = Class.forName("com.ProxyDemo.Eat").getMethod("eat", new Class[0]);
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }

其中m3就是我要代理的方法。具体调用的时候,经过将方法delegate给invocationHandler实例。debug

总结

JDK动态代理
优势设计

  • 相比静态代理,不用每代理一个类就得写一个新的代理类。
    缺点代理

  • 只能代理实现了interface接口的类,由于java是单继承,代理类已是Proxy类的子类了。实现代理没有实现接口的类,还得靠ASM技术。code

相关文章
相关标签/搜索