BT

如何利用碎片时间提升技术认知与能力? 点击获取答案

使用Java Web Start部署JRuby应用

| 作者 Mirko Stocker 关注 1 他的粉丝 ,译者 张龙 关注 14 他的粉丝 发布于 2008年4月3日. 估计阅读时间: 14 分钟 | CNUTCon 了解国内外一线大厂50+智能运维最新实践案例。

你通常需要一个命令来进入Ruby和Java的联合世界:

include Java 

这使你可以实例化Java类,调用其方法,甚至继承它们,就好象它们仅仅是普通的Ruby对象一样。但这其中有一些微妙的差异,这篇文章将向你展示如何管理它们以便能以最快的速度设计出新的应用并部署到你的客户那里。

这篇文章基于一个简单的应用,该应用使用JRuby和Swing实现了一个简单的ObjectSpace浏览器。Ruby的ObjectSpace特性提供了一种方式来访问系统中所有对象。例如,我们可以这样打印所有使用中的字符串:

ObjectSpace.each_object(String) do |string|
 puts string
end  

当该程序在我的irb会话中运行时,大约会产生28000个字符串。通过使用Swing和JRuby,我们可以把不同的类显示在一个非常棒的图形界面上,包括它们的实例以及可用的方法。你甚至可以在最右边的面板中点击它们来调用无参的方法:

Ruby Object Browser

JRuby的ObjectSpace支持在默认情况下是被禁用的,这是由于它在运行时所产生的性能问题,当然还有其他原因。

我要指出它在实现中的一些有趣的细节,并就如何开始使用JRuby中的Java集成特性给出一些提示。

Java集成

一旦你将Java集成到脚本中,你就可以继承现有的Java类。我们只需要通过指定Java类的完整限定名就可以做到这一点。在这个例子应用中,主窗口继承了JFrame。该类中还包含进了javax.swing和java.awt包,所以你不必每次都使用类的全名。

class MainWindow < javax.swing.JFrame
include_package 'javax.swing'
include_package 'java.awt' ...

做为另外一种选择,你还可以使用include_class功能包含指定的类,这样就不会因你没有使用某些类,而污染了名称空间。

调用父类的构造方法就和普通的Ruby代码一样,这意味着我们可以在initialize方法的第一行通过调用super("JRuby Object Browser")来设定窗口的标题。

因为类包含了整个javax.swing包,所以实例化Java类就变得非常直接:

list_panel = JPanel.new
list_panel.layout = GridLayout.new(0, 3)  

如果你仔细看看第二行,你可能会觉得我们直接访问了JPanel的layout属性,但事实并非如此。JRuby为Java对象增加了一些便捷的方法,所以上面的语句也可以用我们熟知的方式编写:

list_panel.setLayout(GridLayout.new(0, 3))  

不再使用getters和setters,看起来你可以直接访问属性。JRuby还向Java对象增加了更多的“语法糖”,这使得整个感觉更像Ruby了:对于任何方法调用,你可以使用snake_case符号而不是为任何方法调用而实际定义的camel case名。由此产生出调用setLayout方法的第三种方式

list_panel.set_layout(GridLayout.new(0, 3)) 

从类中调用setter方法时要小心,Ruby可能会认为你想创建一个局部变量,所以你必须以self作为接收者来显式地调用它:

self.default_close_operation = WindowConstants::EXIT_ON_CLOSE 

Java和Ruby的另一个区别是对于常量的访问,像之前代码片断中的EXIT_ON_CLOSE。记住,当你将Java代码转化为Ruby时,要将所有的.访问符替换为::。 

到目前为止,JRuby对于Swing开发所带来的变化看起来好像也没什么,但是我们尚未涉及到一个非常重要的方面:监听器。在Java中,将一个监听器与事件关联起来通常需要在一个匿名类中实现一个接口:

button.addActionListener(new ActionListener() {
 public void actionPerformed(ActionEvent e) {
 ...
}
});

如果你想附加很多监听器时这很容易搞乱你的代码。在JRuby中,以下两行代码就能解决问题(如果你不使用event变量,你甚至可以忽略掉它):

button.add_action_listener do |event|   
...
end  

这些是你使用JRuby开发Swing时需要掌握的基础。尽管JRuby使得用Swing开发GUI变得更方便,但是你还是需要手写很多代码,当需要复杂布局时更是如此。如果你希望能更简单地创建Swing UI时,请参考使用JRuby GUI APIs的三种方式

部署JRuby应用变得更简单 

Ruby应用和库通常是通过RubyGems分发的,但是为了利用其优势,你需要安装好Ruby和RubyGems,而这对于一般的用户来说却并不实际。对于传统的(MRI / C-Ruby)程序,该问题已经通过RubyScript2Exe[1]的方式得到了解决,这是通过将脚本和一个Ruby解释器绑定到一个可运行在多个平台上的包里面来实现的。JRuby的用户也不必为此感到沮丧,相反,他们手头上已经有了一个更加强大的工具来快速部署应用:Java Web Start。

使用Java Web Start

Java Web Start包含在Java运行时环境中,因此在大多数系统中都可以使用。使用Web Start部署应用相当简单,所需要的仅仅是一个包含所有文件和JNLP(Java Network Launching Protocol)描述文件的jar包。我们在ObjectSpace浏览器应用的基础上,来示范一下如何创建一个可以通过web-start进行部署的Ruby应用。

使用Web Start的前提是一个包含应用的jar包,我们首先从它开始。JRuby提供了两种不同的库:“最小的”jruby.jar和jruby-complete.jar,后者捆绑了整个Ruby标准库。如果你不使用标准库,那么你可以使用更小的jruby.jar,这样可以减少大约1M的下载量。 

让你的脚本运行的最简单的方式就是将.rb文件添加到jruby.jar。下面的命令将我们例子中的rob.rb增加到压缩包中。

jar uf jruby.jar rob.rb  

你可以通过java来启动应用,来检查上面的命令是否正确,而这需要我们的Ruby脚本。这个应用程序需要ObjectSpace,我们可以通过向Java传递jruby.objectspace.enabled=true属性来激活它。

java -Djruby.objectspace.enabled=true -jar jruby.jar -r rob  

-r选项自动寻找所需文件,然后运行我们的脚本。

提早编译 

JRuby1.1的一个令人激动的新特性就是对提前(ahead of time,即AOT)编译的支持。现在JRuby中有2048个方法采用即时编译,而提前编译能减轻这一限制。JRuby编译器jrubyc目前仍处在开发中,所以我建议使用最新的JRuby版本。将普通的Ruby文件编译为class文件就像通过脚本参数调用编译器那样简单:

jrubyc rob.rb  

这会创建一个包含rob.class文件的ruby目录。这次不再需要像我们之前那样将ruby目录打包到jruby.jar中,而只需要创建一个单独的Jar来包含应用程序。毕竟修改现存的Jar看起来并不是一个优雅的方案。我们可以使用同名的工具来创建Jar: 

jar -cfe rob.jar ruby/rob.class ruby  

这会创建一个包含我们的类的名为rob.jar的小的jar文件,并且在Manifest中指定ruby/rob.class为主类。这使得我们可以简化调用,因为我们现在可以很简单地指向类,而无需使用命令行。为了执行它,我们要确保rob.jar在classpath上: 

java -Djruby.objectspace.enabled=true -cp rob.jar:jruby.jar ruby.rob 

Web Start 

在我们继续编写JNLP文件前,我们需要对Jars进行签名。很不幸需要这么做,因为JRuby使用了反射,这样就需要更多的许可,你可以参阅JRuby Wiki来了解更多的细节。最简单的方法就是使用JDK自带的keytool来创建一个测试证书。

keytool -genkey -keystore myKeystore -alias myself
keytool -selfcert -alias myself -keystore myKeystore  

从现在开始,每次你修改Jars时,必须要更新签名,否则在运行时你就会得到一个SecurityException。

jarsigner -keystore myKeystore jruby.jar myself
jarsigner -keystore myKeystore rob.jar myself  

既然我们已经准备好Jars了,我们就来看一下JNLP文件。下面提供了对应用的一个最小配置。一些字段是规范要求的,比如title、vendor、j2se标签以及security段。jar标签代表了Jars的最终位置。它还可以使用file://形式的URL指向本地文件,在开发中这会很方便。ObjectSpace属性也需要在此设定,这可以通过property标签来完成。





Mirko Stocker











 

如果你忽略了AOT段或者仅仅想使用单个jar的方式,那么你就必须修改jnlp文件并包含-e参数,那么你的application-desc看起来应该像这样:

[...]

-r
rob

[...]

最后一步是将Jars和JNLP文件上传到指定位置。现在你应该可以在浏览器或者使用shell中的javaws工具来打开链接了。

问题解决

为了让你的浏览器能通过Web Start加载应用,我们需要使用application/x-java-jnlp-file MIME类型来发布JNLP文件。因此如果你的浏览器仅仅显示了JNLP文件的内容并且javaws没有自动加载的话,你就需要改变web服务器的配置。例如,Apache需要在mime.types中增加如下指令:

application/x-java-jnlp-file jnlp 

进一步阅读 

JRuby wiki提供了关于JRuby的很多信息

  1. http://www.erikveen.dds.nl/rubyscript2exe/

下载 code for Ruby Object Browser

查看英文原文: Deploying JRuby applications with Java Web Star


译者简介:张龙,同济大学软件工程硕士,现就职于理光软件研究所。主要从事文档工作流和办公自动化解决方案的研发工作。热衷于Java轻量级框架的研究,对敏捷方法很感兴趣。曾有若干年的J2EE培训讲师经历。参与InfoQ中文站内容建设,请邮件至china-editorial[at]infoq.com

评价本文

专业度
风格

您好,朋友!

您需要 注册一个InfoQ账号 或者 才能进行评论。在您完成注册后还需要进行一些设置。

获得来自InfoQ的更多体验。

告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

Yeh! by Aron Gao

verygood!!

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

1 讨论

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT