动态代理实现机制深层次分析与动态字节码生成总结
在上一次【https://www.cnblogs.com/webor2006/p/9847915.html】已经通过源码的方式将动态代理字节码文件生成出来了,如下:
下面来分析一下该字节码的内容,双击打开IDE就可以反编译其字节码的内容,如下:
package com.sun.proxy; import com.jvm.bytecode.Subject; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; public final class $Proxy0 extends Proxy implements Subject { private static Method m1; private static Method m2; private static Method m3; private static Method m0; 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}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } 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 void request() throws { try { super.h.invoke(this, m3, (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); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m2 = Class.forName("java.lang.Object").getMethod("toString"); m3 = Class.forName("com.jvm.bytecode.Subject").getMethod("request"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }
其中可以看到有个传一个InvocationHandler对像的构造函数,其实在生成该代理对象的源码中有用到它,咱们来看一下:
然后再通过反射来生成该代理类对象的具体实例:
其中再回到代理类的反编译代码中可以发现总共有四个方法,如下:
另外还有四个静态的成员变量及对这四个变量进行初始化的代码,如下:
然后从初始化中就可以看到通过反射,m0、m1、m2这三个方法都是来自于java.lang.Object类,而m3是来自于我们自己编写的Subject.request()方法。下面再来具体来看一下方法的实现:
很显然就是我们调用时的第三个参数,如下:
所以对于方法的执行最终都会转向我们自定义的DynamicSubject类中的invoke()方法,如下:
这其实就是动态代理的一个本质,明白了这个方法的整个调用流程,那其它代理类的方式就基本类似,如下:
其中还可以得出一个结论就是:如果调用了动态代理中的Object.equals()、Object.toString()、Object.hashCode()三个方法都会转向到我们在DynamicSubject定义的invoke()方法,但是如果调用了Object除这三个方法之外的则不会受动态代理的影响,其实这个在Proxy类的说明中就有解释,如下:
接下来咱们整体来挼一下整个动态调用的流程,彻底地来理解动态代理实现原理,从我们的调用开始:
此时就会转到我们分析代理对象的request()当中了,如下:
然后super.h是提我们传递的实现了InvocationHandler对象,也就是它:
然后执行该对象的invoke()方法,如下:
所以此时的调用流程就转到了DynamicSubject.invoke()方法了,如下:
接着来调用真正代理对象的方法了,如下:
所以其结果输出为:
然后再往下:
自此,对于动态代理从字节码角度就可以掌握得更加踏实啦~~