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想在以后增加很多改进,并希望得到社区的帮助:
该框架的另一个重要组件是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。
Abel Avram从2008年起,在InfoQ参与了很多编辑工作,喜欢撰写移动、HTML、.NET、云计算和企业级架构等主题相关的新闻报道。如果您有兴趣提交新闻或者有价值的文章,可以通过邮件abel [at] infoq.com联系他。
查看英文原文:DukeScript: A New Attempt to Run Java Everywhere