大模型“四虎”出山,亮相 4 月 QCon 北京。 了解详情
写点什么

使用 Java Web Start 部署 JRuby 应用

  • 2008-04-02
  • 本文字数:4025 字

    阅读完需:约 13 分钟

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

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

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

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

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

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

Java 集成

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

class MainWindow < javax.swing.JFrame<br></br>include_package 'javax.swing'<br id="vdnl"></br>include_package 'java.awt' ...做为另外一种选择,你还可以使用 include_class 功能包含指定的类,这样就不会因你没有使用某些类,而污染了名称空间。

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

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

list_panel = JPanel.new<br></br>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_CLOSEJava 和 Ruby 的另一个区别是对于常量的访问,像之前代码片断中的 EXIT_ON_CLOSE。记住,当你将 Java 代码转化为 Ruby 时,要将所有的. 访问符替换为::。

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

button.addActionListener(new ActionListener() {<br></br>  public void actionPerformed(ActionEvent e) {<br id="v1-q"></br>  ... <br></br> } <br></br>});如果你想附加很多监听器时这很容易搞乱你的代码。在 JRuby 中,以下两行代码就能解决问题(如果你不使用 event 变量,你甚至可以忽略掉它):

button.add_action_listener do |event| <br></br> ... <br id="d8d9"></br>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<br></br>keytool -selfcert -alias myself -keystore myKeystore从现在开始,每次你修改 Jars 时,必须要更新签名,否则在运行时你就会得到一个 SecurityException。

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

<br></br><jnlp><p><information><p><vendor>Mirko Stocker</vendor></p></information><resources><br></br><jar href="http://misto.ch/rob/rob.jar"><br></br><jar href="http://misto.ch/rob/jruby.jar"><br id="hx8y"></br><j2se version="1.5+"><br></br><property name="jruby.objectspace.enabled" value="true"><br></br></property><br></br><application-desc main-class="ruby.rob"><br id="o7ei"></br><security><br></br><all-permissions><br></br></all-permissions><br></br></security> </application-desc></j2se></jar></jar></resources></p></jnlp>如果你忽略了 AOT 段或者仅仅想使用单个 jar 的方式,那么你就必须修改 jnlp 文件并包含 -e 参数,那么你的 application-desc 看起来应该像这样:

[...]<p><application-desc><p><argument>-r</argument><argument>rob</argument></p></application-desc>[...]</p><br></br>最后一步是将 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

2008-04-02 04:173634
用户头像

发布了 88 篇内容, 共 265.5 次阅读, 收获喜欢 8 次。

关注

评论

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

「学习笔记」《02 | 第一个程序:教你输出彩色的文字》之二

Nydia

学习

不忘过去,不畏将来

小天同学

5月日更 汶川地震 不忘过去

最近又有出什么新电影,要不要停泊片刻,与好友相约一起来去看呢?

叶小鍵

声网、新东方、伴鱼英语的音视频技术解读

Jessie

音视频 视频消音

【LeetCode】停在原地的方案数Java题解

Albert

算法 LeetCode 5月日更

无常中的僵硬与柔软

zhoo299

随笔杂谈 教育 生命 5月日更

VMWare中Ubuntu网络配置

进击的梦清

Linux 运维 vmware 网络配置

SpringBoot技术专题—来看看异步处理返回方案

洛神灬殇

Java WebAsyncTask 5月日更 AsyncContext DeferredResult

Fluid 进入 CNCF Sandbox,加速大数据和 AI 应用拥抱云原生

阿里巴巴云原生

人工智能 容器 云原生 调度 弹性计算

找Matlab代码,看这一篇就够了

攻城先森

matlab 工具分享 5月日更

一文带你读懂PyQt:用Python做出与C++一样的GUI界面应用程序

老猿Python

python str模块

若尘

Python编程 str 5月日更

Dubbo 本地调用

青年IT男

dubbo

深度剖析 | 关于数据锁定和读取一致性问题

VoltDB

数据库 数据分析 5G

华为中国生态大会2021举行在即,GaussDB将重磅发布5大解决方案

华为云开发者联盟

数据库 opengauss 华为云 GaussDB 云数据库

Golang 工作区和 GOPATH

escray

学习 极客时间 Go 语言 5月日更

精选面试题教你应对高级iOS开发面试官(提供底层进阶规划蓝图)

程序员 移动开发 ios开发

怎样做好服务提供方

程序员架构进阶

架构设计原则 服务化 28天写作 5月日更

ThreadLocal不好用?那是你没用对!

王磊

Java 后端 多线程 ThreadLocal 5月日更

给Java小白,整理一套能上手的简单编程算法题!!!

小傅哥

Java 程序员 数据结构 算法 小傅哥

华为云官网负责人明哥:我们是如何做到门面不倒,8个月挑战业界翘楚?

华为云开发者联盟

JavaScript node.js Serverless 云原生 大前端

百信银行基于 Apache Hudi 实时数据湖演进方案

Apache Flink

大数据 flink

cri-o 技术探秘2

xumc

作为最好用的可观测平台,如何监控 Grafana

耳东@Erdong

Grafana Prometheus 5月日更

追寻软件定义的梦想汽车

车骑

自动驾驶 智能汽车 软件定义汽车 汽车制造

Arthas-技术专题-使用指南

洛神灬殇

Arthas 5月日更

音视频在智能手表上的应用

anyRTC开发者

音视频 WebRTC IoT RTC

kotlin基础

ES_her0

5月日更

如何让消息队列达到最大吞吐量?

万俊峰Kevin

微服务 消息队列 Queue Go 语言

Nginx性能分析之gpreftools

运维研习社

nginx 性能分析 5月日更

Python自动打印文件

IT蜗壳-Tango

IT蜗壳教学 5月日更

使用Java Web Start部署JRuby应用_Java_Mirko Stocker_InfoQ精选文章