JDK 动态代理的实现

我们知道,JDK 动态代理可以对接口进行代理,把接口的所有方法代理到 InvocationHandler 的 invoke 方法上。
示例如下:

这样我们就可以对一个 没有实现 的接口进行调用了,实际的调用代理给了 IncovationHandler 实例的 invoke 方法。那么这个是怎么实现的呢?

我们可以使用 sun.misc.ProxyGenerator#generateProxyClass(java.lang.String, java.lang.Class<?>[]) 这个方法获取到生成的代理类的字节码数组,把字节码输出为一个 .class 文件,在 IDEA 中就可以看到源码。

然后在 main 方法里调用 writeProxyClass(userService.getClass()); 就可以了。用 IDEA 打开输出文件,可以看到:

也就是说,生成动态代理对象时,实际上是 JDK 动态编译了一个类,继承了 Proxy 类,实现了传入的接口类。然后把接口的方法(及 Object 的三个实例方法 toString, hashCode, equals)都代理给了父类 Proxy 的 InvocationHandler 实例。所以我们可以在自定义的 InvocationHandler 的 invoke 方法中进行处理。

Proxy

java.lang.reflect.Proxy#newProxyInstance

这个方法用于生成代理对象,里面比较重要的就是 Class<?> cl = getProxyClass0(loader, intfs); 这一句,拿到代理类的 Class 实例,之后 return cons.newInstance(new Object[]{h}); 即可生成代理对象。

java.lang.reflect.Proxy#getProxyClass0

这个方法实现很简单: return proxyClassCache.get(loader, interfaces); 从一个 proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory()); 缓存中获取类实例。其实真正的获取在这个地方:

java.lang.reflect.Proxy.ProxyClassFactory#apply

首先一些权限检查之类的,略过,拿到代理对象的类名,最终也落在 byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags); 这个调用上。最后通过本地方法将 byte[] 转化为 Class 对象就完成了。

ProxyGenerator

sun.misc.ProxyGenerator#generateProxyClass(java.lang.String, java.lang.Class<?>[], int)
sun.misc.ProxyGenerator#generateClassFile

这里就是动态生成字节码的地方了。
其实是根据 JVM 规范,把类信息写入了字节数组

对应下面的 Class 规范:
https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html

JDKProxy
JDKProxy


本文代码可以在这里找到:
https://github.com/YouthLin/examples/tree/master/example-jdk-proxy


“JDK 动态代理的实现”的一个回复

Loading...

发表评论

电子邮件地址不会被公开。 必填项已用*标注