Node.js 和 Java 嵌入之间的差异

GraalVM 提供了一个完全符合 ECMAScript 2024 标准的 JavaScript 运行时。因此,它可以在各种嵌入场景中运行 JavaScript 代码,包括 Oracle 数据库、任何基于 Java 的应用程序和 Node.js。

根据嵌入场景的不同,应用程序可以访问不同的内置功能。例如,使用 GraalVM 的 bin/node 可执行文件执行的 Node.js 应用程序可以访问所有 Node.js 的 API,包括内置的 Node.js 模块,例如 fshttp 等。相反,嵌入在 Java 应用程序中的 JavaScript 代码只能访问有限的功能,这些功能通过 上下文 API 指定,并且无法访问 Node.js 内置模块。

本指南描述了 Node.js 应用程序和嵌入在 Java 应用程序中的 JavaScript 之间的主要区别。

上下文创建 #

GraalVM 中的 JavaScript 代码可以使用执行上下文来执行。

在 Java 应用程序中,可以使用 Context API 创建新的上下文。可以以多种方式配置新的上下文,配置选项包括公开对 Java 类访问权限、允许访问 IO 等。可以在 API 文档 中找到上下文创建选项的列表。在这种情况下,可以通过使用 GraalVM 的 Polyglot Bindings 将 Java 类公开给 JavaScript。

在 Node.js 应用程序中,执行应用程序的 GraalVM Context 由 Node.js 运行时预先初始化,用户应用程序无法对其进行配置。在这种情况下,可以通过使用 bin/node 命令的 --vm.cp= 命令行选项将 Java 类公开给 Node.js 应用程序,如下所述。

Java 交互操作性 #

JavaScript 应用程序可以使用内置的 Java 对象与 Java 类进行交互。此对象在 jsnode 启动器中默认可用,但仅在 JVM 独立模式下(名称中包含 -jvm)才能访问 Java 类。

当使用 Polyglot API 嵌入 JavaScript 时,您必须在 Context.Builder 中显式启用主机访问(allowHostAccessallowHostClassLookup)。有关 JavaScript-Java 交互操作性的更多详细信息,请参阅 Java 交互操作性指南

多线程 #

运行 JavaScript 的 polyglot Context 采用“无共享”并行模型:两个并发 Java 线程不能同时访问任何 JavaScript 值。为了利用并行执行,必须从多个线程创建和执行多个上下文。

  1. 在 Node.js 模式下,可以使用 Node.js 的 Worker 线程 API 创建多个上下文。Worker 线程 API 确保两个并行上下文之间不会发生共享。
  2. 在 Java 中,可以从多个线程执行多个上下文。只要一个上下文没有被两个线程同时访问,并行执行就会安全地发生。

有关 GraalJS 中并行执行的更多详细信息,请参阅 这篇博文

Java 库 #

可以通过 Java 内置对象从 GraalJS 访问 Java 库。为了让 Java 库可以从 Context 访问,需要将它的 JAR 文件添加到类路径中。可以通过以下方式完成此操作。

  1. 在 Node.js 模式下,可以使用 --vm.cp 选项修改类路径。
  2. 在 Java 中,可以使用默认的 Java -cp 选项。

命令行选项 中了解更多信息。

JavaScript 包和模块 #

许多流行的 JavaScript 模块(例如在 npm 包注册表中提供的模块)既可以从 Node.js 使用,也可以从 Java 使用。

  1. 在 Node.js 模式下,JavaScript 模块由 Node.js 运行时处理。因此,GraalJS 支持 Node.js 支持的所有模块(包括 ES 模块、CommonJS 模块和原生模块)。
  2. 在 Java 模式下,GraalJS 可以执行任何不依赖于原生 Node.js 内置模块(例如 fshttp 等)的 JavaScript 模块或包。可以使用包捆绑器加载模块,也可以使用可用的内置机制加载 ES 模块。在 Java 模式下,CommonJS 模块在实验性选项下受支持。

有关 JavaScript 模块的更多详细信息,请参阅 模块

联系我们