TeaVM 简介

在本文中,我们探讨了 TeaVM 如何促进 Java 字节码转换为 JavaScript,从而使 Java 应用程序能够直接在 Web 浏览器中运行。我们介绍了一些关键功能,例如如何从 JavaScript 调用 Java 方法、执行基于 Java 的 DOM 操作以及实现简单的 Web 应用程序而无需编写大量 JavaScript 代码。通过一个实用的计算器示例,我们展示了使用 TeaVM 连接 Java 和 Web 开发的便利性。

TeaVM是一个将 Java 字节码转换为 JavaScript 的强大工具,使 Java 应用程序能够直接在浏览器中运行。这使我们能够在针对 Web 环境的同时维护基于 Java 的代码库。

在本教程中,我们将探讨如何使用 TeaVM 与 DOM 交互以及从 JavaScript 调用 Java 方法的能力来弥合 Java 和 JavaScript 之间的差距。

TeaVM 的主要用途
当我们拥有复杂的基于 Java 的逻辑时,为 Web 重写相同的功能是不切实际的。TeaVM 允许我们通过高效地将 Java 代码编译为 JavaScript 来避免冗余,从而优化最终脚本的大小和性能。

无论如何,请记住,我们的 Java 代码必须符合Java 类库 (JCL) 模拟的范围。例如,不支持 Swing 和 JavaFX。

单页应用程序(SPA)
TeaVM 是使用 Java 和 CSS 从头开始​​创建单页应用程序 (SPA) 的正确解决方案,可最大限度地减少编写 JavaScript 和 HTML 代码的需要。这是因为 TeaVM 具有以下特定于 Web 的功能:

直接从 JavaScript 调用 Java 方法,正如我们将在接下来的示例中看到的那样

  • 使用@JSBody注释创建在 JavaScript 中实现的本机 Java 方法
  • 使用JSO 库通过 Java 操作 Web 元素
然而,TeaVM 并不能完全取代 JavaScript 或 HTML,尤其是在布局和某些浏览器特定逻辑方面。此外,TeaVM 不处理 CSS,我们必须手动编写或通过外部框架进行管理。

现有网站
TeaVM 还非常适合将用 Java 编写的功能添加到使用传统 CMS(如 WordPress 或 Joomla)开发的现有网站。例如,我们可以为我们的 CMS 创建一个 PHP 插件,通过 REST API 向 TeaVM 公开功能,并在我们网站的页面上包含由 TeaVM 编译的 JavaScript。

此类脚本利用我们的 REST API,可以将 JSON 转换为 Java 对象,反之亦然,并执行我们用 Java 编写的业务逻辑。它还可以修改 DOM 以创建用户界面或集成到现有用户界面中。

当客户端业务逻辑非常复杂以至于我们对 Java 代码比 JavaScript 更为熟悉、熟练和熟练时,这种用例是有意义的。

其他情况
此外,TeaVM 正在积极开发对 WebAssembly 的支持,新版本正在开发中,该版本将允许以最少的更改将我们的 JavaScript 目标应用程序移植到 WebAssembly。不过,此功能仍处于试验阶段,尚未准备就绪。

TeaVM 还可以将 Java 转换为 C。我们可以将此功能用作GraalVM原生镜像的超轻量级子集。即使此功能稳定且随时可用,我们也不会深入介绍它,因为它超出了 TeaVM 的主要用途。

Maven 设置和 TeaVM 配置
首先,TeaVM 目前的 0.10.x 版本支持最高 JDK 21 的 Java 字节码,并且至少需要 Java 11才能运行其 Java-to-JavaScript 编译器。当然,这些要求在以后的版本中可能会发生变化。

我们将使用 Maven,并通过在 Java 类中以编程方式配置 TeaVM,使pom.xml保持最小。这种方法允许我们根据通过 Maven 的-Dexec.args选项传递给main(…)方法的参数动态更改配置。这有助于从同一项目为不同目的生成不同的 JavaScript 输出,同时共享相同的代码库。

如果我们更喜欢其他方法,或者不使用 Maven,官方TeaVM 入门指南提供了进一步的说明。

pom.xml
检查Maven 存储库中 TeaVM 的最新版本后,让我们添加依赖项:

<dependency>
    <groupId>org.teavm</groupId>
    <artifactId>teavm-core</artifactId>
    <version>0.10.2</version>
</dependency>
<dependency>
    <groupId>org.teavm</groupId>
    <artifactId>teavm-classlib</artifactId>
    <version>0.10.2</version>
</dependency>
<dependency>
    <groupId>org.teavm</groupId>
    <artifactId>teavm-tooling</artifactId>
    <version>0.10.2</version>
</dependency>

添加这三个依赖项会自动添加其他 TeaVM 传递依赖项。teavm-core包括teavm-interop、teavm-metaprogramming-api、重定位的 ASM 库(用于字节码操作)、 HPPC 和 Rhino(JavaScript 引擎)等库。 此外,teavm-classlib引入了teavm-jso、commons-io、jzlib和joda-time。teavm-tooling依赖项还包括commons-io的重定位版本。

这些传递依赖项提供了基本功能,无需手动添加它们。

TeaVMRunner.java
此类配置TeaVM,我们需要使用Maven的-Dexec.mainClass选项指定它:

public class TeaVMRunner {
    public static void main(String[] args) throws Exception {
        TeaVMTool tool = new TeaVMTool();
        tool.setTargetDirectory(new File("target/teavm"));
        tool.setTargetFileName(
"calculator.js");
        tool.setMainClass(
"com.baeldung.teavm.Calculator");
        tool.setTargetType(TeaVMTargetType.JAVASCRIPT);
        tool.setOptimizationLevel(TeaVMOptimizationLevel.ADVANCED);
        tool.setDebugInformationGenerated(false);
        tool.setIncremental(false);
        tool.setObfuscated(true);
        tool.generate();
    }
}

让我们仔细看看:
  • setTargetDirectory(…) → TeaVM 将放置生成文件的输出目录
  • setTargetFileName(…) → 生成的 JavaScript 文件的名称
  • setMainClass(…) → 应用程序主类的完全限定名称
  • setTargetType(…) → JavaScript、WebAssembly 或 C
  • setOptimizationLevel(…) → ADVANCED级别生成最小的 JavaScript 文件,甚至比FULL级别还要小
  • setDebugInformationGenerated(…) → 仅适用于为 TeaVM Eclipse 插件创建调试信息文件
  • setIncremental(…) → 如果启用,编译速度会更快,但会减少优化,因此不建议用于生产
  • setObfuscated(…) → 启用后,它会将生成的 JavaScript 的大小减少两到三倍,因此在大多数情况下应该是首选
官方指南的工具部分还记录了其他选项,例如用于生成源地图的选项。

需要注意的最重要的一点是,使用setMainClass(…)会创建一个具有全局范围的 JavaScript main()函数,该函数执行 Java main(String[])的翻译版本。我们稍后会看到一个例子。

HTML 页面
虽然简单,但这是一个如何包含 TeaVM 生成的 Javascript 文件的完整示例。我们省略了元标记,以针对移动设备、索引和与 TeaVM 无关的其他要求进行优化:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>TeaVM Example</title>
    <script type=
"text/javascript" src="calculator.js"></script>
    <script type=
"text/javascript">
        document.addEventListener('DOMContentLoaded', function() {
           
// Call JS functions here
        });
    </script>
</head>
<body>
<h1>TeaVM Example</h1>
<div id=
"calculator-container"></div>
</body>
</html>

从这样的简单示例开始,我们可以根据需要修改 DOM 来创建任何布局,甚至可以借助 CSS。