写点什么

使用 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:173557
用户头像

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

关注

评论

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

FFmpeg应用篇

Changing Lin

3月日更

如何激励员工?—— 马斯洛需求理论

石云升

激励 28天写作 职场经验 管理经验 3月日更

你真了解开源许可证吗?

郭旭东

开源

面试官:说说JavaScript中的事件模型

我家有萌🐱

JavaScript 面试 大前端 js

工作三年,小胖不知道 MySQL 日志是干嘛的。真的菜

一个优秀的废人

MySQL mysql事务 MySQL日志

跨越数据的“叹息墙”:华为下一代数据湖与HPDA时代

脑极体

高性能公链能为 DeFi 带来什么?

CECBC

区块链

Java学习之路 -- Java怎么学?

秦怀杂货店

Java 编程 基础 书籍

软件架构中的模块与组件

Simon

架构实战营

零信任提升组织的数字安全性

龙归科技

网络 数字时代 零信任

聊聊集群、分布式和微服务之间的异同点

架构精进之路

分布式 微服务 集群 3月日更

《MySQL》系列 - select 查询语句到底是怎么执行的?

一个优秀的废人

MySQL 数据库 原理 sql查询

Java反射简析

Langer

Java java反射

记一次生产环境大面积404问题!

冰河

nginx 网关

OKR实践中的痛点(4):再谈老板的KR我的O

大叔杨

OKR 敏捷 绩效 敏捷绩效

百度飞桨中国行南京站开启!共研AI赋能产业新模式

百度大脑

百度 AI 飞桨

满满干货|支付宝美女面试官的贴心锦囊

Lily

如何快速掌握 Kubernetes 网络

倪朋飞

学习方法 Kubernetes 云原生

一位入职蚂蚁金服,年薪180万的大佬扔给我的笔记,看完发现差距不止一点点!

Java架构追梦

Java 阿里巴巴 架构 面试

普元CTO焦烈焱:成长之路务必重视工程能力

EAWorld

程序员

Java + opencv实现视频人脸检测

张音乐

OpenCV 人脸识别 视频

EGG NETWORK阿凡提超级公链  EFT流量通证信息完全公开源

币圈那点事

Hudi on Flink 快速上手指南

Apache Flink

flink

微服务时代组件化和服务化的抉择

vivo互联网技术

微服务 组件化 服务化 服务调用

“数字足迹”怕暴露,数字人民币如何守护你我隐私安全?

CECBC

数字货币

JVM-技术专题-Class文件加载虚拟机

洛神灬殇

JVM Class字节码

2021突击银四必备:BAT900道Java面试清单!免费开放

比伯

Java 编程 架构 面试 计算机

中国唯一入选 Forrester 领导者象限,阿里云 Serverless 全球领先

Serverless Devs

阿里云 Serverless 云原生

常用的视频剪辑软件介绍,自媒体必备工具!

奈奈的杂社

推动产业数字化 提升服务实体经济质效

CECBC

科技

Java + opencv 实现图片人脸检测

张音乐

Java AI OpenCV ffmpeg 人脸识别

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