代码改变世界

继续探索动态代理

2005-09-02 23:30  FantasySoft  阅读(1004)  评论(0编辑  收藏  举报
        在昨天的Post中,三言两语把动态代理(Dynamic Proxy)大致介绍了一下并给出了一个例子,我想大家应该和我一样对Dynamic Proxy有一定认识了吧。然而Dynamic Proxy这个宝藏的底蕴是深厚的,三言两语又怎能发掘到精华呢?于是,偶带着很多疑问,对Dynamic Proxy来一次更全面的探索。
        在Dynamic Proxy中,最有意思的应该是Proxy创建的过程了。我们可以通过调用Proxy.newProxyInstance这个方法来创建一个Proxy的实例,然而这个Proxy的实例却可以被Cast成所绑定的interface的型别。为什么Proxy的实例可以成功地被Cast呢?在没有去考究之前,先让偶天马行空一番。Proxy中包含了一个特别的Inner Class,它的定义是这样的 public Class InProxy implements *。 而这个星号在Proxy创建的时候被具体的interface list所替代,这样InProxy的定义才完整,才能够基于这样的定义创建InProxy的实例。这跟Python中动态创建Class的模板有着几分相似啊!天马行空完了,不管对不对,玩玩想象力倒也不错。为了找到正确的答案,我于是打开Proxy这个Class的source code看个究竟。   

        从代码中,我们可以发现newProxyInstance方法等价于三个方法的调用:
   newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)  
== Class proxyClass =
 Proxy.getProxyClass(loader, interfaces);
    Constructor cons 
= proxyClass.getConstructor(new Class[] { InvocationHandler.class }
);
    cons.newInstance(
new Object[] { h }
);

在三个方法调用中,后面两个是类Class中十分常见的方法,并没有什么特别的,关注的重点落在了getProxy方法。在getProxy方法中,第一步是检查参数interfaces的是否invalid,如果这一组interface都是valid,将创建一个字符串以存储这些interface的名称。使用字符串而非Collection来存储interface的名称是出于性能以及弱引用(不是很明白这里为什么需要用到弱引用)的考虑;第二步是在一个WeakHashMap中以ClassLoader作为Key去查找另外一个Map,而这个Map则缓存着已经创建的Proxy Class,如果在这个Map中找到了需要的Proxy Class则返回,否则通过ProxyGenerator.generateProxyClass方法以及一个名为defineClass0的native方法创建Proxy Class,而这两个方法我都无从寻找它们的source code。Oh,my God!
        Anyway,这一阵瞎摸索还是让我知道了,Proxy Class之所以能够被Cast成所绑定的interface的型别,靠的就是这两个方法了。尽管没有办法到这两个方法的内部看个究竟多少让我有些失落,但是,这样把source code阅读了一番,倒给我提出了更多的问题。噢,又有好玩的东西可以去发掘了,so great!