写点什么

XRuby:享用JVM上的Ruby

2007 年 10 月 11 日

XRuby 是什么?它是一个开源编译器。与其它编译器一样,它完成的工作是将一种格式的语言转换成另一种。与大多数编译器不同的是,它是将 Ruby 的代码(.rb)转换成 Java 的字节码(.class)。

图 1:将 Ruby 编译为字节码

又一个 Ruby 实现?

Ruby 编译器?那岂不又是一个 Ruby 的实现。自从 Ruby 越来越受到人们的关注,各种 Ruby 实现也逐渐出现在人们的视野之中。除了 Ruby 之父松本行弘(Matz)开发的版本(Matz Reference Implementation,简称 MRI)之外,JRuby、Rubinius、IronRuby、Ruby.NET、Cardinal 等不同 Ruby 实现的名头也是一天比一天响亮。同为 Ruby 实现,XRuby 有哪些不同之处呢?

XRuby 是一个将 Ruby 代码编译为 Java 字节码的编译器,这说明

  • XRuby 的目标平台是 Java 虚拟机(Java Virtual Machine,简称 JVM)
  • XRuby 是一个编译器

运行在 JVM 上让 XRuby 有别于用 C 完成的 MRI,.NET 平台上的 IronRuby 和 Ruby.NET 和 Parrot 上的 Cardinal,而编译器的特点又让 XRuby 和 JRuby 有所差别。

JVM 上的 Ruby

无可否认,经过多年发展,Java 已经成为软件开发世界的主流语言之一,选择 Java 平台还因为:

  • Java 是一个经过验证的平台
  • Java 在许多领域内都有了成熟的解决方案
  • Java 已经有了大量稳定的基础结构
  • 有众多熟悉 Java 的人才
  • Java 社区非常开放

从程序设计语言的发展来看,一种新兴的程序设计语言都会存在与主流程序设计语言的接口,比如 C/C++ 对汇编语言的接口,比如 Java 语言对于 C/C++ 的接口。通过这样的接口,利用主流语言已有的资源,帮助新语言得到更好的接受。用 C 开发的 MRI 让 Ruby 已经拥有了和 C/C++ 的接口,XRuby 为 Ruby 提供了一种通往 Java 世界的选择。拥有 Ruby 和 Java 的接口,意味着我们可以将 Ruby 的开发效率和 Java 的丰富资源结合起来:在 Ruby 的代码中使用 Java 的类库;将 Ruby 应用部署到 Java EE 的服务器上……

为什么要将 Ruby 应用部署到 Java EE 服务器上呢?Java EE 技术经过多年的发展已经走向成熟,并在业界得到了广泛的应用,Java EE 的服务器逐渐稳定,在很多领域中都有了成熟的解决方案。更重要的是,将 Ruby 应用部署到 Java EE 服务器上,意味着之前众多企业在 Java EE 服务器方面的投资将会得到重用,这会极大的减少基础设施建设方面的浪费。

解释和编译

如果我们想将程序设计语言编写的源代码运行起来,通常情况下,我们有两条路可以走:解释和编译,这也是我们让 Ruby 运行于 JVM 平台的两种选择。

解释,这是 MRI 最初的选择。因为有 MRI 作为参考,所以,这也是一种相对来说比较容易移植的选择。这种做法需要有一种专门的执行引擎。如下图所示,源码经过 MRI 解析之后,产生了一棵抽象语法树(Abstract Syntax Tree,简称 AST)。利用这棵树产生我们需要的结果,这是执行引擎的工作。这种做法的好处就是可以把执行逻辑独立处理,无须为每个平台编写不同的代码,所以,这种做法的可移植性很好,它也就成了不少程序设计语言最初的选择。不过,随之而来的问题就是这会降低执行速度,毕竟,这个软件执行引擎的性能无法与硬件相比。所以,“编译”会让程序拥有更佳的性能。

图 2:解释

采用编译的方式,我们可以将代码编译成可以由硬件直接执行的二进制代码。对于 JVM 这个“虚拟”的机器而言,它的二进制代码就是字节码。因为不同硬件和不同操作系统的二进制格式是不同的,所以,如果希望语言得到广泛应用,那便需要针对不同平台实现平台相关的编译器后端,理论上说,这不是一件不能完成的任务,但实际上,这意味着巨大的工作量。JVM 的存在降低了这个难度,因为主流软硬件平台上基本都有自己的 JVM 实现,所以,代码可以运行在 JVM 上便意味可以运行在大多数平台上。当然,因为 JVM 本身是虚拟机,也是一种软件实现,所以,性能上也会有一些损失。不过,随着 JVM 技术上的不断进步,性能损失越来越小。另外,从 Java 平台的广泛应用也证明了,这样的损失在实践中是可以接受的。不过,相对于解释的方式有 MRI 这种成熟实现作为参考,编译显然需要更多的探索。

图 3:编译

除了执行性能之外,将 Ruby 代码编译为 Java 的字节码还可以为我们带来另外的好处,那就是保护源代码。解释的方式让很多人不放心的一点就在于,产品发布意味着将源代码也发布出去。对于需要保护知识产权的公司和个人而言,这是他们所不愿意看到的。通过编译的方式,我们将源代码转成了字节码,这样,源代码可以得到有效保护。破解字节码理论上也是有可能的,不过,这是另外的故事了。

XRuby 从起步开始走的就是编译的道路,而 JVM 上的另外一种 Ruby 实现——JRuby 则是从解释起步的。相比于解释,编译方式在性能方面有着很大的优势,所以,从解释方式起步的 JRuby 最终也走上编译的道路。

初涉 XRuby

让我们从一段简单的 Ruby 代码出发,更具体了解一下 XRuby。

class MyClass
def say_hello_three_times
3.times { puts “hello”}
end
end MyClass.new.say_hello_three_times

(simple.rb)

这里,我们定义了名为 MyClass 的类,其中有一个 say_hello_three_times,它的工作就是输出三次“hello”。即便你并不了解 Ruby 语言,相信这段代码看上去,也不是那么难以理解,只是语法上不尽相同而已。稍微需要解释一下的就是:

3.times { puts “hello”}

同许多面向对象程序设计语言相比,在 Ruby 中,面向对象做得更加彻底,所以,即便像“3”这样的数字也是一个对象,所以,我们可以调用它的方法。再有,就是后面括号里的东西。在 Ruby 中,这是一种语法结构,称为 block。从这段代码来说,block 中的代码会在执行 3.times 的过程中调用。当然,这里展现的只是非常简单的用法,事实上,block 的存在使得 Ruby 代码具有了更强的表现力。这不是一篇 Ruby 语言的介绍,如果你对 Ruby 语言更感兴趣,那本著名的《Programming Ruby》是个不错的选择。

将这段代码保存在一个名为 simple.rb,然后,用 XRuby 对它进行编译。

java -jar xruby-0.3.1.jar -c simple.rb

编译之后,会得到一个名为 simple.jar 的文件,运行这个 JAR 文件,就可以得到运行的结果

java -jar simple.jar

屏幕输出为:

hello
hello
hello

当然,我们也可以像使用其它 Ruby 实现一样,直接运行这段代码,而无需生成中间的 JAR 文件。

java -jar xruby-0.3.1.jar simple.rb

我们会得到同样的结果:

hello
hello
hello

作为一个 Ruby 用户,如果你对 XRuby 有兴趣,你所需要做的只是把 XRuby 安装到你的系统,像其它 Ruby 实现一样去使用,因为从用户的角度而言,XRuby 和它们没有区别。如果你对 Ruby 语言的实现感兴趣,也许你需要了解 XRuby 的一些内部实现。

XRuby 的架构

图 4:XRuby 架构图

上图展示了 XRuby 的架构,主要包括两个部分:编译器和运行时。编译器部分将 Ruby 代码编译生成字节码,运行时部分则实现了对 Ruby 语言的支持。下面具体看一下各个部分。

图 5:编译器

Ruby 代码经过 Parser 的解析,会形成一棵抽象语法树,Tree Parser 处理这棵树,形成 Code DOM。Code Generator 部分利用 Code DOM 生成对应的字节码。这里的 Code DOM 是对 XRuby 内部对 Ruby 语言建立的一个模型,通过这个模型进行代码生成。这个模型将 XRuby 的编译器前端很好的独立出来,这样,在保持前端不变的情况下,我们可以用它为不同的平台去做代码生成,这也 XRuby 之所以为“X”的一个原因。

图 6:运行时

从这张架构图中,我们可以看到,XRuby 的运行时包括动态语言的支持、内建库(Builtin)和 Java 支持几个部分。

Ruby 是一种动态语言,而 JVM 本身是为 Java 这样的静态语言提供的平台,很难直接在二者之间做直接的映射。动态语言支持的部分就是为了在 JVM 平台上支持动态语言特性而存在的。也是因为这个部分的存在,我们即便采用编译的方式,依然使用 Ruby 的动态语言特性,比如,在程序运行期间为类增加或删除方法等等。

我们知道,除了语言本身外,程序库是一种程序设计语言可以成功的另一种强大的推动力。同样,Ruby 的优秀,除了它优雅的语法外,与它有强大的内建库密不可分。所以,XRuby 当然也少不了对于内建库的支持。

正如前面提到的,XRuby 为 Ruby 提供了一条通往 Java 的道路,Java 支持部分就是完成这样的工作。有了这个部分,你就可以在 Ruby 脚本使用 Java 的类库,这样,丰富的 Java 资源可以在 Ruby 世界中得到重用。

如果这里的讨论引起你对 XRuby 更多的兴趣,或许你希望更多的了解 XRuby,那最好的方式是参与到 XRuby 的开发中来。

管窥 XRuby

进入 XRuby 开发最好的起点莫过于内建库,下面是一个简单的内建库中 Array#length 实现的例子:

@RubyLevelClass(name=“Array”)
public class RubyArray … {

@RubyLevelMethod(name=“length”)
public RubyFixnum length() {
return ObjectFactory.createFixnum(this.array_.size());
}

}

XRuby 提供了一个名为 @RubyLevelClass 的 Annotation,它将 Java 层次的类绑定到 Ruby 层次的类上。这里可以看到, RubyArray 是一个定义在 Java 层次的类,通过 @RubyLevelClass,它被绑定为 Ruby 层次的 Array 这个类上。同样, @RubyLevelMethod 完成的是将 Java 层次的方法绑定到 Ruby 层次上的工作。在上面的例子中,我们用这个 Annotation 将 Java 的 length 方法绑定到了 Ruby 的 length 方法上。这样,在 Ruby 代码中调用 Array 类的 length 方法最终会调用到 RubyArray 的 length 方法上来。

当然,这是一个极为简单的例子,不过,它至少可以说明,XRuby 的开发并不像许多人想象的那么复杂。实际上,大多数 XRuby 的参与者都是从内建库起步的,随着对 XRuby 了解的增多,再逐渐的参与到其它部分的开发之中,比如动态语言支持和编译器部分等等。

参与 XRuby

事实上,XRuby 欢迎任何形式的贡献,也鼓励大家进行任何尝试,这也是 XRuby 不断前进的动力。在这里,大家总会有冒出一些新的想法把事情做得更好。你可以选择不同的方式参与 XRuby:

  • 使用 XRuby
  • 报告 Bug
  • 提交补丁
  • 加入邮件列表分享你的想法
  • 成为 XRuby 的项目一员
  • ……

参与 XRuby 这样一个开源编译器项目会有很多乐趣:

  • XRuby 是一个编译器,对于那些不满于工作在黑盒上的程序员来说,编译器和操作系统等底层知识具有难以抗拒的吸引力,了解这些知识本身可以为我们带来更好的理解代码如何运行,写起代码来也会更加的得心应手。 编译器技术背后的思想不仅限于编译器技术本身,了解这些技术之后,你会发现它会在许多的问题上为你带来新的思路。
  • XRuby 是一个 Ruby 语言的实现,这意味着我们可以更多的了解 Ruby 这种优雅的程序设计语言。了解得越多,我们便可以越多的发现它的优点,这会让我们更加喜欢这种程序设计语言。
  • 不仅仅是运用 Ruby,我们更要了解 Ruby 语言的实现,甚至是更为通用的是动态语言实现机制。对于语言实现的了解,将有助于我们写出更为高效的程序,对于动态语言尤其如此,不少看上去功能类似的做法,实际上却存在很大的差异。
  • XRuby 的目标运行平台是 JVM,所以,我们会得到与 JVM 打交道的机会,了解 JVM 可以帮助我们更好的理解 Java 代码的运行机制,写出更好的 Java 代码。
  • XRuby 是一个开源项目,所以,参与 XRuby 让我们有机会为开源做出自己的贡献,与天南海北的人协同开发,体会开源开发模式为我们带来的种种乐趣。
  • 最重要的是,XRuby 还是一个年轻的项目,这意味着参与其中的人将会获得更多的机会,和它共同成长。

Ruby 之父松本行弘经常将乐趣挂在嘴边,因为编程本来就该是一件充满乐趣的事。如果你对 XRuby 有兴趣,那不妨加入我们,和我们一起体验这份开发的乐趣,共同享用 JVM 上的 Ruby!

参考信息

作者简介

郑晔,ThoughtWorks 中国公司咨询师,开源项目 XRuby 核心成员,目前正致力于让 Ruby 更好地运行于 JVM 平台。他的 Blog 为: http://dreamhead.blogbus.com/

2007 年 10 月 11 日 03:16957
用户头像

发布了 22 篇内容, 共 11.8 次阅读, 收获喜欢 37 次。

关注

评论

发布
暂无评论
发现更多内容

LeetCode题解:剑指 Offer 22. 链表中倒数第k个节点,双指针,JavaScript,详细注释

Lee Chen

算法 LeetCode 前端进阶训练营

手把手教你本地 k8s 集群搭建云原生 Tekton CICD 流水线

比伯

Java 大数据 编程 架构 计算机

为什么我就面试阿里P6,好不容易过2面,3面来个架构师来吊打我?

小Q

Java 学习 程序员 架构 面试

【涂鸦物联网足迹】涂鸦云平台接口列表

IoT云工坊

人工智能 接口 物联网 API 智能家居

AliP9整理出微服务笔记:Spring微服务不止架构和设计

周老师

Java 编程 程序员 架构 面试

亲测三遍!8步搭建一个属于自己的网站

华为云开发者社区

MySQL Linux 开发者 网站 华为云

阿里P8架构师“墙裂”推荐:Java程序员必读的架构进阶热门书籍,值得学习!

Java成神之路

Java 程序员 架构 面试 编程语言

C++多元组tuple使用方法?你熟悉吗?快来看看吧

良知犹存

c++

Flutter Bloc模式

码爷

flutter ios 程序员

轻松云上揽胜中华,靠的就是这份聪明的“地图”!

华为云开发者社区

MySQL 数据库 postgresql AI 地图

Teambition 网盘 VS 阿里云盘:阿里这个浓眉大眼的也开始玩赛马了?

郭旭东

阿里云 阿里云网盘

微众银行大数据平台建设方案

康月牙Rita

大数据 开源 金融 平台 微众银行

企业级软件的核心价值

Philips

敏捷开发 企业应用

一位Java大牛结合自己的业务和平台多年来在Netty实践中积累的经验总结《Netty进阶之路:跟着案例学Netty》。

Java成神之路

Java 程序员 架构 面试 编程语言

DeFi质押挖矿系统开发技术

薇電13242772558

区块链 defi

《迅雷链精品课》第三课:区块链主流框架分析

迅雷链

区块链 区块链方案 区块链+ 区块链应用

云图说|多模态AI开发套件HiLens Kit:超强算力彰显云上实力

华为云开发者社区

人工智能 开发者 物联网 机器人 华为云

阿里大牛说:你凭什么搞不懂SpringBoot,Cloud,Nginx与Docker

小Q

Java 学习 编程 架构 面试

【Mycat】作为Mycat核心开发者,怎能不来一波Mycat系列文章?

冰河

分布式事务 分布式数据库 系统架构 分布式存储 mycat

【Swift实现代码】iOS架构模式之MVP

码爷

ios swift 架构

java-File对象

Isuodut

作为一名Java程序员,技术栈的广度深度都不够还想要高薪?请先把这些技术掌握再说。

Java成神之路

Java 程序员 架构 面试 编程语言

多线程并发主题-ThreadLocalRandom类

Geek_896619

Java 并发编程 线程

握草!美团P8整理的280页超详细Docker实战文档简直太香了,让你对如日中天的Docker有更深入的了解。

Java架构之路

Java 程序员 架构 面试 编程语言

IMC总决赛精彩对战应接不暇,英特尔酷睿极致性能燃爆比赛现场!

intel001

高交会科技盛宴:“科技改变生活,创新驱动发展”

13530558032

mongodb 源码实现系列 - 网络传输层模块实现四

杨亚洲(专注mongodb及高性能中间件)

MySQL 数据库 mongodb 高性能 分布式数据库mongodb

美国区块链政策大盘点

CECBC区块链专委会

区块链 政策 货币

Github标星67.9k的微服务架构以及架构设计模式笔记我真的爱了

Java架构之路

Java 程序员 架构 面试 编程语言

“双11”购物狂欢节,所有女生走进了谁的直播间?

BonreeAPM

APM AIOPS 拨测 直播 用户体验

什么?还不懂c++vector的用法,你凭什么勇气来的!

良知犹存

c++

XRuby:享用JVM上的Ruby-InfoQ