• 2007-07-08

    生成方法的Wrapper

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://dreamhead.blogbus.com/logs/6520681.html

    在《管窥Ruby——方法定义》中,我们曾经讨论过在Java中实现方法定义时,因为Java语言的限制,我们不得不为方法加上了一个Wrapper,让它可以满足接口定义的需要。事实上,XRuby一直就是这么做的,通常Wrapper放在com.xruby.runtime.builtin这个包中,而诸如Array、Hash、String之类的具体实现放在com.xruby.runtime.value这个包中。初涉XRuby的人,常常会被这两个包搞得晕头转向。到底方法的具体实现应该放在哪里,大多是根据感觉来定义的。

    在那篇blog中,我还讨论了JRuby的实现,不过,那里面的讨论并不是特别的完善。事实上,除了利用reflection,其中还有一种方式,通过代码生成动态产生这个Wrapper。我将这个实现借鉴到了XRuby中。通过采用这种生成Wrapper的方式,我们就可以在实际编写的代码中,忽略掉Wrapper部分的实现,而将原来令人混淆的builtin和value包统一起来。

    下面是Array的clear方法原来的实现:
    class Array_clear extends RubyNoArgMethod {
        protected RubyValue run(RubyValue receiver, RubyBlock block) {
            RubyArray value = (RubyArray) receiver;
            return value.clear();
        }
    }

    在这里,其实只要将receiver转型,然后调用它的方法就好。实际上,生成的代码只是做这样简单的工作就好,当然,根据具体的方法还会略有些差别。关于如何使用ASM进行代码生成,我在几篇blog中都进行了介绍,这里就不介绍生成代码的实现了。下面是在代码中如何使用这个方法。
    MethodFactory factory = MethodFactory.createMethodFactory(RubyArray.class);
    c.defineMethod("clear", factory.getMethod("clear", 0));

    在这个方法的实现过程中,还有一些比较有趣的点。首先,并不是每次都需要调用getMethod都要动态生成一个类,因为一个类一旦已经加载,就没有必要再次进行加载,即便强行加载,class loader也是会抱怨的。所以,在创建类之前,我们需要尝试加载一下这个,如果加载成功,便省去了再次生成的麻烦。

    再有,每次都去创建这个Wapper实际上也没有什么必要,一次生成之后,保存起来就可以了。如果我们把它放在class path中,那么我们尝试加载就会成功,所以,刚才提到的尝试加载还有这样一层含义。

    作为builtin实现,我们还是希望这些生成类是可以放在我们最终发布的jar文件中,所以,我们通常的做法,是在打包之前,先用XRuby做一次最简单的执行,让所有的Wrapper生成出来,这样,打包的时候就可以将它们都加入其中。

    具体的做法可以参考XRuby中MethodFactory和build.xml。





    引用地址:

发表评论

您将收到博主的回复邮件
记住我