GWT 工具包:使用 Java 构建强大的 JavaScript 前端

已发表: 2022-03-11

GWT Web Toolkit,以前称为 Google Web Toolkit,是一组开发工具,用于使用 Java 编程语言构建和优化基于浏览器的复杂应用程序。

GWT 之所以不是“另一个编写 Web 应用程序的 Java 工具”,是因为该工具包的核心是将 Java 转换为 JavaScript(以及 HTML 和 CSS)的编译器,使开发人员能够编写前端 Web 应用程序同时利用 Java 的所有优势。

GWT 将 Java 变成漂亮的 JavaScript、HTML 和 CSS 代码。

甚至可以轻松混合使用 Java 和 JavaScript,因为 GWT 包含用于与 Web 平台交互的强大互操作性架构。 就像 Java 原生接口 (JNI) 允许 Java 虚拟机 (JVM) 调用特定于平台的例程(例如,访问特定的硬件功能,或使用来自其他语言的外部库),GWT 允许我们编写大部分Java 中的应用程序,然后,如果需要使用特定的 Web API,或者利用现有的 JavaScript 库,“进入原生”并跳转到 JavaScript。

GWT 作为 Google 产品诞生,但在 2011 年底毕业并开源,现在在 Apache 许可(第 2 版)下以GWT Open Source Project的名义发布。 它由一个指导委员会管理,该委员会的代表来自多家公司,包括 Google、RedHat、ArcBees、Vaadin 和 Sencha,以及来自社区的独立开发人员。

GWT 的过去和未来

Google Web Toolkit 于 2006 年首次发布。它的创建是为了帮助 Google 工程师开发基于浏览器的复杂应用程序,例如 AdWords、Google Wallet 和 Google Flights,最近,它被用于谷歌表格和收件箱应用程序。

早在 2006 年,浏览器(和 JavaScript 解释器)还远未标准化。 前端代码很慢、有缺陷并且难以可靠地使用。 几乎完全缺乏用于 Web 开发的高质量库和框架。 例如,jQuery 直到今年才出现。 因此,为了能够开发大型 Web 应用程序,Google 的工程师决定利用现有的工具和能力。 Java 是最适合他们需求的语言,它广为人知并完美集成到 IDE 中,例如 Eclipse,因此 Google Web Toolkit 开始了它的生命。

目标或多或少是隐藏浏览器之间的差异,并将编写高效 JavaScript 所需的技巧封装在 Java 编译器中,让开发人员摆脱浏览器技术的束缚。

当然,在过去的十年里,网络发生了变化。 浏览器变得更快,并在实现标准上趋同,并且开发了许多很棒的前端框架和库,包括 jQuery、Angular、Polymer 和 React。 所以你可能自然会问的第一个问题是,“GWT 还有用吗?”

一句话:的。

在现代 Web 开发的背景下,针对浏览器是不可避免的,JavaScript 已成为前端应用程序的通用语言。 但当然,不同的工具和语言更适合不同的任务。 GWT 以及一些类似的项目旨在针对浏览器而不限制开发人员使用 JavaScript。

在不久的将来,万维网联盟的 WebAssembly 小组将促进像 GWT 这样的“编译到网络”工具的开发和使用。 不仅有巨大的空间用于编译为 JavaScript 的工具,而且这种方法可以满足从将部分计算卸载到浏览器、重用现有代码和库、在后端和前端之间共享代码等环境的实际需求,利用现有的能力和工作流程,并利用不同语言的特性(例如,GWT 的静态类型)。

GWT 项目预计将很快发布 2.8 版本,3.0 版本正在开发中,在工作中有很大的改进:

  • 重塑与 JavaScript 的互操作性
  • 改进的(几乎完全重写的)编译器
  • 最先进的 Java 支持(例如 lambdas)

实际上,GWT 3.0 的大部分功能已经在公共 Git 存储库中可用。 只需在此处查看主干并按照此处的文档编译 GWT。

GWT 社区

自 GWT 于 2011 年开源以来,社区在项目的发展中发挥了关键作用。

所有开发都在 gwt.googlesource.com 上托管的 Git 存储库上进行,所有代码审查都在 gwt-review.googlesource.com 上完成。 在这些页面上,任何对工具包的开发感兴趣的人都可以做出贡献并查看社区正在做什么。 在过去几年中,来自非 Google 员工的新补丁的比例从 2012 年的 5% 左右上升到去年的 25% 左右,这证实了参与度的增长。

今年,社区聚集在美国和欧洲举行了几次大型会议。 由 Vaadin 组织的 GWT.create 于 1 月在德国慕尼黑和加利福尼亚州山景城举行,共有来自数十个国家的 600 多名参与者参加。 11 月 11 日,我们将在意大利佛罗伦萨举行第二届 GWTcon,这是一个社区驱动的 GWT 会议,我正在帮助组织。

GWTcon 2015 意大利佛罗伦萨

GWT 适合什么?

Vaadin 发布的关于 GWT 工具包的年度调查讨论了 GWT 的开发演变、开发人员对工具包的看法、好与坏等。 该调查还让我们了解 Toolkit 的用途、用户社区的变化以及开发人员对 Toolkit 未来的期望。

可以在这里找到 2015 年GWT 的未来报告,它清楚地表明 GWT 在构建大型 Web 应用程序方面非常受欢迎。 例如,在第 14 页,它指出,“大多数应用程序都是数据量很大的业务应用程序,每天要使用数小时。”

正如预期的那样,很容易得出结论,GWT 的自然环境是大型 Web 应用程序领域,其中代码的可维护性很重要,大型团队从 Java 语言的结构中受益。

GWT 非常适合构建强大的大型 Web 应用程序。

另一方面,查看 GWT 生成的代码的基准(例如,在去年 GWT.create 会议的主题演讲中,第 7、8 和 11 页)很容易看出,在性能和代码大小,编译后的 JavaScript 非常棒。 如果使用得当,所获得的性能可与最好的手写 JavaScript 相媲美。 因此,使用 GWT 将 Java 库移植到 Web 实际上是可行的。

这阐明了 GWT 的另一个理想方案。 Java 生态系统充满了高质量的库,在 JavaScript 中没有现成的对应物。 GWT 编译器可用于为 Web 调整此类库。 换句话说,GWT 允许我们混合 Java 和 JavaScript 中可用的库,并在浏览器中运行它们。

这种方法可以在 PicShare 的开发中看到,我们展示了如何使用 GWT 将几个通常不考虑用于 Web 的 Java 库(例如 NyARToolkit)移植到浏览器,并结合 Web API,包括 WebRTC 和 WebGL,以实现获得一个完全基于网络的增强现实工具。 我很自豪能够在去年 1 月的 2015 GWT.create 会议上展示 PicShare。

具有 Java 应用程序功能的 JavaScript 前端? 是的,您也可以拥有这一切,使用 GWT!
鸣叫

幕后:将 Java 转换为 JavaScript

GWT Toolkit 是一组中等复杂的工具,但任何人都可以立即开始使用它,这要归功于与 Eclipse 的令人惊讶的易于使用的集成。

对于具有 Java 开发项目背景的任何人来说,使用 GWT 创建一个简单的应用程序都相对容易。 但要了解“真正发生的事情”,有必要分析工具包的主要组件:

  • Java 到 JavaScript 转换器
  • 模拟 Java 运行时环境
  • 互操作层

GWT 的优化编译器

对编译器如何工作的深入描述很早就变得技术性很强,我们不需要深入挖掘,但一些一般概念值得一看。

首先要了解的是,GWT 通过源代码级别的翻译将 Java 编译成 JavaScript。 也就是说,Java 源代码被翻译( transpiled是技术术语)为 JavaScript。 这与使用 JavaScript 编写的执行 Java 字节码的某种 Java 虚拟机形成对比。 (这实际上是可能的,并且是 Doppio 使用的方法,但这不是 GWT 的工作方式。)

相反,Java 代码被分解成抽象语法树 (AST),表示代码的语法元素。 然后将其映射到等效的(和优化的)Javascript AST,最终转换回实际的 JavaScript 代码。

GWT 使用抽象语法树将 Java 源代码转换为 JavaScript 源代码。

权衡转译的优缺点远不是本文的目标,但让我观察一下,通过这种方法,GWT 可以直接利用 JavaScript 解释器的垃圾收集服务,以及浏览器原生的任何其他功能。

当然,也有一些棘手的部分。 例如,JavaScript 只有一种数值类型,它不能包含 Java 的 64 位long整数类型,因此long类型需要编译器进行一些特殊处理。 此外,Java 静态类型在 JavaScript 中没有直接意义,因此必须特别注意保持转换后的类型转换操作等价。

另一方面,转译的一个容易理解的优势是 GWT 可以在 Java 级别JavaScript 级别执行优化(针对大小和性能)。 生成的标准 JavaScript 代码甚至可以在您的部署管道中进一步处理。 例如,现在已集成到标准 GWT 发行版中的一种常见做法是使用高度专业化的 JavaScript-to-JavaScript Closure Compiler(Google 众神的另一个礼物)优化转译器的 JavaScript 输出。

我所知道的对 GWT 编译器最深入的描述可以在这个幻灯片中找到,以及它来自的原始谈话。 在这里,您可以找到有关编译过程的其他酷特性的详细信息,例如 GWT 进行代码拆分、生成多个单独的脚本文件以供浏览器独立加载的能力。

模拟的 JRE

如果不补充 Java 运行时环境 (JRE) 的实现,Java 到 JavaScript 的编译器将只不过是一种新事物,它提供了几乎所有 Java 应用程序所依赖的核心库。 粗略地说,在没有集合或字符串方法的情况下使用 Java 工作会令人沮丧,当然,移植这些库是一项艰巨的工作。 GWT 用所谓的仿真 JRE 填补了这个漏洞。

Emulated JRE 绝不是对 Java JRE 的完全重新实现,而是一种对客户端有用(和可用)的类和方法的选择。 Java JRE 中但在 Emulated JRE 中找不到的功能分为三类:

  • 不能移植到客户端的东西。 例如, java.lang.Threadjava.io.File不能在具有相同 Java 语义的浏览器中实现。 浏览器页面是单线程的,不能直接访问文件系统。

  • 可以实现但在代码大小、性能或依赖性方面“成本过高”的东西,因此社区不希望在 GWT 中拥有这些东西。 例如,包含在此类别中的是 Java 反射 ( java.lang.reflect ),它需要转译器保留每种类型的类信息,这会导致编译后的 JavaScript 的大小膨胀。

  • 没有人感兴趣的事情,因此没有实施。

如果 Emulated JRE 不符合您的需要(例如,您需要一些未提供的类),GWT 允许您编写自己的实现。 这种强大的机制,通过标签<super-source>可用,使得在调整使用未模拟的部分 JRE 的新外部库时可以规避问题。

提供 JRE 某些部分的完整实现可能过于复杂,甚至不可能,因此对于特定任务,您自己的实现可能不会严格遵循 Java JRE 的语义,即使它们适用于您的特定情况。 实际上,如果您正在考虑将您的类归还给项目,请记住对于仿真 JRE 来说至关重要的是,每个包含的类都遵循与原始 Java JRE 完全相同的语义。 这确保了任何人都可以将 Java 代码重新编译为 JavaScript,并相信他们会得到预期的结果。 在将代码返回给社区之前,请始终确保您的代码经过彻底测试。

互操作层

要成为生产真实世界 Web 应用程序的有效工具,GWT 必须允许开发人员轻松地与底层平台交互。 也就是浏览器和DOM。

从一开始,GWT 就是为了通过 JavaScript 原生接口 (JSNI) 支持这种交互而构建的,这使得访问浏览器内的 API 变得轻而易举。 例如,使用 GWT 编译器独有的语法特性,您可以编写以下 Java 代码:

 public static native void nativeMethod(T1 a1, T2 a2, ...) /*-{ //place your JavaScript code here }-*/;

并且您可以自由地在 JavaScript 中实现方法的主体。 您甚至可以将 JavaScript 对象包装在 JavaScriptObject (JSO) 中,并使其在您的 Java 代码中可访问。

这个层发挥作用的一个例子可以在 UI 组合的上下文中找到。 主流 Java 一直使用标准的 Widgets 工具包来构建 UI 元素,利用 Java Native Interface 来访问底层操作系统的窗口和输入系统。 GWT 的互操作层做同样的事情,因此传统的 Widget 可以在浏览器中无缝工作。 唯一的区别是,在这种情况下,底层系统是浏览器和 DOM。

然而,本机前端框架近年来迅速改进,如今与 GWT 的 Widgets 相比具有显着优势。 随着这些框架变得越来越复杂,在 JSNI 中实现它们的尝试暴露了互操作层架构中的缺陷。 从 2.7 版开始,GWT 引入了 JsInterop,这是一种基于 Java 注释的新方法,它允许您快速轻松地将 GWT 类与 JavaScript 集成。 不再需要编写 JSNI 方法或 JSO 类。 相反,您可以简单地使用@JSType@JSProperty类的注解,让您可以像使用 Java 一样使用原生 JavaScript 类。

JsInterop 的完整规范仍在进行中,最新的更新只能通过从 GWT 存储库编译源来试用。 但很明显,这是允许 GWT 跟上不断发展的 Web 平台的新方向。

一个利用 JsInterop 的正在进行的项目是最近发布的 gwt-polymer-elements,它使来自 Polymer 的所有 Iron 和 Paper 元素都可用于 GWT。 这个库的有趣之处在于开发人员不需要手动生成 Java API。 项目使用 gwt-api-generator 通过解析 Polymer 库和 JSDoc 注解直接生成大部分接口。 这使得保持绑定更新变得容易。

最后的话

随着过去两年对编译器、互操作层以及生成代码的性能和大小的改进,很明显 GWT 不仅仅是“另一个 Web 开发工具”,而且有望成为主要的参考工具包开发大型、复杂的 Web 应用程序,甚至可以成为制作更简单的应用程序的绝佳选择。

作为一名开发人员和顾问,我每天都会在工作中使用 GWT,但我更喜欢 GWT,因为它让我突破了浏览器功能的极限,并展示了现代 Web 应用程序可以与桌面应用程序一样强大。

GWT 项目的社区非常活跃,基于 GWT 的新库、项目和应用程序不断被提出。 在佛罗伦萨,社区驱动的 GWTcon2015 将于 11 月 11 日举行会议。 如果您在该地区,我希望您能来会见一些核心开发人员,并了解所有参与这个令人惊叹的工具包发展的机会。