速读原著-DukeScript:随处运行 Java 的新尝试

  • 2020 年 2 月 14 日
  • 筆記

DukeScript:随处运行 Java 的新尝试

Jaroslav Tulach 是NetBeans 的创始人和最初的架构师,Anton (Toni) Epple 则是一位Java 咨询师和培训师,最近他们凭借 DukeScript 获得了 2014 年的 Duke 选择奖。DukeScript 这门技术希望能将 Java 带到一切客户端、移动终端或桌面,而不需要借助插件。DukeScript 这个名字有些误导性,其实它并不是一门新的脚本语言,相反它只是尝试“将 Java 放到 JavaScript 之中”,进而实现Java 最初的愿景——“一次编写,到处运行”。

DukeScript 是这样一门技术,它支持使用 Java 和 HTML5 创建跨平台的移动和桌面应用。不同于其他将 Java 应用于服务器端的解决方案,DukeScript 将 Java 应用到了客户端,而且不依赖Oracle 过去用于运行 Applet 的插件。该技术可以运行于 Android、iOS、桌面浏览器以及任何HTML5/JavaScript 环境中。

Epple 向 InfoQ 解释了DukeScript 及相关技术是如何工作的:

一个DukeScript 应用的基本架构其实非常简单,包括 3 个组件:一个是Java 虚拟机,一个是 HTML 渲染组件,再就是 DukeScript。DukeScript 将 JVM 和 HTML 组件粘合到一起, 作为运行在虚拟机中的业务逻辑和用 HTML/JavaScript 编写的 UI 之间的桥梁。 DukeScript 应用运行在JVM 中,使用HTML 渲染器显示页面。当页面加载时,DukeScript 会在内部通过Knockout.js,将该页面的动态元素绑定到数据模型。它与典型的Knockout.js 应用的差别在于,数据模型由 Java 对象组成,用户可以在 Java 代码中操控这些对象。利用这种方式,业务逻辑可以完全用Java 编写,与 UI 清晰地分离开来。 在我们支持的每一个平台上,都要找到一个 JVM 和一个 WebView 组件,并将其衔接到一起。显而易见,真正的困难在于通信,因为每个平台都略有不同。

该技术支持多种场景。在桌面上,可以脱离浏览器,此时 DukeScript 用到了 JavaFX,Epple 介绍说:

在桌面上,我们有 Hotspot VM 和 JavaFX WebView,而且后者可以直接与 Java 交互。这也很方便调试应用。当运行在 HotSpot 上时,我们可以使用断点、表达式求值以及 IDE 提供的所有其他优秀功能来调试应用。在 WebView 中,NetBeans 可以检查 DOM 树,显示CSS,我们可以在应用运行时动态更新页面的 HTML。

Epple 补充说,在两大主流移动平台上,DukeScript 的工作方式类似,不过使用的虚拟机和WebView 不同:

在 Android 上,有 Dalvik 作为虚拟机,android.webkit.WebView 用于渲染 HTML 和执行JavaScript。在 iOS 上,有 RoboVM(一款通过 LLVM 流水线生成机器代码的 AOT 编译器)和 NSObject.UIResponder.UiView.UIWebView。通过连接这些基本组件,我们可以在这些不同的平台上运行同样的应用。

在桌面浏览器上,Java 代码需要翻译为相应的 JavaScript 片段。这可以通过 Bck2Brwsr(Tulach 编写的一款 JVM)提前编译或即时编译。据 Epple 介绍,对于 JIT 场景,当 Web 页面加载时,Bck2Brwsr 会被加载进来,再由它来加载应用中的 Java 主类并实例化,之后是实例化 Java 数据模型,并实现与HTML 组件的绑定。当Java 代码执行时,Bck2Brwsr 将其翻译为JavaScript,并在浏览器的引擎中运行。Bck2Brwsr 并不是必须的,可以用其他虚拟机替代,比如可以使用TeaVM。

在 Windows Phone 上,可以使用与 Android 和 iOS 类似的解决方案,以 Bck2Brwsr 作为所选的 JVM,但是目前尚未测试,或许还需要更多工作。

据 Tulach 介绍,Bck2Brwsr 目前有些不足:它没有使用反射,而且“该项目的目标并非来执行现有的任何 Java 库”。它面向的是新的、需要特殊设计的受限环境。Tulach 想在以后增加很多改进,并希望得到社区的帮助:

  • 使用Closure 编译器来生成更紧凑的代码;
  • 每个独立的库——ObfuscatePerLibrary;
  • 通过 sammy.js 或 crossroads.js 访问多页面;
  • 方法和字段支持不同的修饰符;
  • 对反射的更多支持(例如,在允许的情况下不要抛出 SecurityException);
  • 没有 private 的方法/字段/构造器/类的访问;
  • 可能没有字段的访问;
  • 可能需要构造器的访问;
  • Java 的调试器(JavaScript 的也可以);
  • 性能基准测试 Sci2000;
  • 研究生成对 asm.js 而言友好的代码;
  • 为所有 HTML5 元素动态生成Java 包装器(Honza)。

该框架的另一个重要组件是 HTML APIs via Java 1.0 API(HTML/Java),这是一组用于和HTML 页面交互的Java API,最初是为NetBeans 开发的。默认情况下,该API 可以通过JavaFX WebView 在桌面浏览器上与 HTML 交互。该 API 已经与 Knockout 做了集成,后者会提供与数据模型的绑定,所以不需要直接操作 DOM。Tulach 提到,该 API 也可以配合 Controls.js 使用, 还可以添加对其他框架的支持(比如 Angular.js 等)。

HTML/Java API 可以用于从Java 中直接调用JavaScript,而反向的调用可以借助 JavaScriptBody 注解实现。下列代码片段就是一个例子:

@JavaScriptBody(args = {"x", "y"}, body = "return x + y;")    private static native int sum(int x, int y);

为简化针对浏览器编写的 Java 代码,并避免“冗长的 JavaBeans 模式”,Tulach 使用了 Model 注解,如下面的例子所示:

@Model(className="Person", properties={  @Property(name = "firstName", type=String.class), @Property(name = "lastName", type=String.class)  @Property(name = "addresses", type=Address.class, array = true)    })

通过HTTP 或WebSocket,HTML/Java API 使用JSON 与服务器通信,这里用到了另一个注解— —@OnReceive。关于这一点,Tulach 写到:

它会再生成一些样板化代码,因此与服务器的数据交互就只是几行代码的事了。事实上,如果比较原始的 JavaScript 示例代码的大小,就会发现这正是新的 HTML/Java API 所擅长的。用于异步REST 或 WebSocket 通信的Java 代码要比对应的JavaScript 代码短。

HTML/Java API 在设计时力求做到尽可能简单,不依赖其他库,而且可以在不同的JVM 上执行, 包括HotSpot 和Bck2Brwsr。

Epple 还扩展了 HTML/Java 库,添加了一个 HTML5 Canvas API,以及一个基于 JavaFX Canvas API 的游戏引擎。

DukeScript 的网站列出了一些例子,其中包括一个简单的 HTML-Java 在线编辑器,这个编辑器还有一个Angular.js To-Do Demo。