newProxyInstance
在上一文中(没看的欢迎回去复习,要考的~),我们通过JDK实现了动态代理。为什么实现了InvocationHandler
接口就可以进行代理? 我们这一次尝试从 Main
开始去分析一下源码。可以看到Main
调用了
1 | Proxy.newProxyInstance(RobTicket.class.getClassLoader(), |
去构造一个_12306
的类,点进去看一下 newProxyInstance
到底做了什么
1 | public static Object newProxyInstance(ClassLoader loader, |
Ok, 上面我们可以看到生成一个代理类的大概步骤如下:
- 检查(非空检查、权限检查)
- 生成代理类(主要是通过
getProxyClass0
) - 获取构造器,若修饰符不为public,则修改其可执行权限(
setAccessible(true)
) - 返回通过构造器所创建的代理类对象
关于检查这一块,我们不做过多讲解,doc里有很清晰的描述(大致就是检查一下包权限和类加载器)。我们从第二步开始进行分析。
getProxyClass0
从 newProxyInstance
查看getProxyClass0
, 可以看到第一次是同一个类中进行跳转,然后调用了proxyClassCache.get(loader, interfaces)
这个方法。
1 | private static Class<?> getProxyClass0(ClassLoader loader, |
我们接着跟下去,发现代码如下:
WeakCache
1 | final class WeakCache<K, P, V> { |
这一部分是对于缓存的一些处理, 其中关于检查方面的代码依旧用了较多篇幅,逻辑部分不是很多。大致就是从缓存中获取代理,关于subKeyFactory.apply(key, parameter)
这里
1 | //Proxy |
1 | //WeakCache |
我们通过Proxy
类下的默认构造和WeakCache
这里的赋值能发现这里的subKeyFactory
是一个KeyFactory实例,而valueFactory
则是一个ProxyClassFactory实例(下面要考的,记住咯)
其中比较重要的是supplier.get()
这个地方,如果这里是Factory实例的话,get()方法会调用ProxyClassFactory
去生成一个代理类。这里先看一下Factory中的方法
1 |
|
上面是自带的注释,因为比较详尽就不多做解释了。这里我们需要重点关注valueFactory.apply(key, parameter)
这一行。create new value,这不就是咱要的东西嘛!跳转到调用的地方。有点长,不要怂,胜利就在眼前了!
ProxyClassFactory
1 | private static final class ProxyClassFactory |
ProxyGenerator
希望就在前方~ 我们再点开ProxyGenerator.generateProxyClass
这个方法,看一下具体实现:
1 | public static byte[] generateProxyClass(final String name, |
又调用了一层… 再跟进去看看gen.generateClassFile();
这个方法。前方高能预警:
1 | private byte[] generateClassFile() { |
在这里如果我们配置了System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
那么会在com.sun.proxy
下生成我们代理类的字节码文件,还是使用上一文中的JDK动态代理的代码,最终生成结果如下:
1 | // |
这里的supper.h
其实是Proxy
类里的成员变量InvocationHandler
,这玩意就是我们上一文中实现的那个接口。忘了?没关系,来复习一下:
1 | public class RobTicketInvocationHandler implements InvocationHandler { |
因为在构造啊的时候我们将这个自己实现的RobTicketInvocationHandler
作为h传进去了,所以调用的invoke其实是我们自己写的这个invoke方法,也就是说,到此为止,JDK动态代理的过程就结束了~
1 | RobTicket robTicket = (RobTicket) Proxy.newProxyInstance( |
完结撒花~~~
后记
第一次这么完整地看完一部分源码,好激动。。。
最后,欢迎关注我的公众号丫 —> 直接在公众号搜索页面搜 bestsort, bestsort的秘密基地就是我啦~
非常感谢街灯下的小草他的关于JDK动态代理的那篇文章给我阅读源码的大致脉络提供了非常大的帮助(可惜他那篇文章有一部分有错误,差点让我怀疑人生…)