GraalJS

GraalJS 是一个基于 GraalVM 的快速 JavaScript 语言实现。它符合 ECMAScript 标准,提供与 Java 和其他 Graal 语言的互操作性,以及常用的工具。如果在 GraalVM JDK 上运行,它默认情况下使用 Graal JIT 编译器,提供最佳性能。您也可以将 GraalJS 与 Oracle JDK 或 OpenJDK 结合使用。

对于希望从 Nashorn 或 Rhino 迁移 到支持新的 ECMAScript 标准和功能的 JavaScript 引擎的项目来说,GraalJS 是一个合适的替代品。您可以轻松地将 GraalJS 添加到您的 Java 应用程序中,如下所示。

在 JVM 上使用 GraalJS 入门 #

要将 JavaScript 嵌入到 Java 宿主应用程序中,请通过将其添加为项目依赖项来启用 GraalJS。所有必要的工件可以直接从 Maven Central 下载。所有与嵌入器相关的工件都可以在 Maven 依赖项组 org.graalvm.polyglot 中找到。

以下是 JavaScript 嵌入的 Maven 配置

<dependency>
    <groupId>org.graalvm.polyglot</groupId>
    <artifactId>polyglot</artifactId>
    <version>${graaljs.version}</version>
</dependency>
<dependency>
    <groupId>org.graalvm.polyglot</groupId>
    <artifactId>js</artifactId>
    <version>${graaljs.version}</version>
    <type>pom</type>
</dependency>

这将启用 GraalJS,它基于 Oracle GraalVM,并根据 GraalVM 免费条款和条件 (GFTC) 授权。如果您想使用基于 GraalVM Community Edition 构建的 GraalJS,请使用artifactId js-community 而不是 js

分步骤创建 Maven 项目,将 JavaScript 嵌入到 Java 中,并运行它。此示例应用程序已通过 GraalVM for JDK 23 和 GraalVM Polyglot API 版本 24.1.0 进行测试。有关如何安装 GraalVM,请参阅 下载页面

  1. 在您最喜欢的 IDE 中或从您的终端使用以下结构,创建一个名为“helloworld”的新 Maven Java 项目
     ├── pom.xml
     └── src
         ├── main
         │   └── java
         │       └── com
         │           └── example
         │               └── App.java
    

    例如,您可以运行以下命令来使用快速入门原型创建一个新的 Maven 项目

     mvn archetype:generate -DgroupId=com.example -DartifactId=helloworld -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.5 -DinteractiveMode=false
    
  2. App.java 中的内容替换为以下代码
     package com.example;
    
     import org.graalvm.polyglot.*;
     import org.graalvm.polyglot.proxy.*;
    
     public class App {
    
         static String JS_CODE = "(function myFun(param){console.log('Hello ' + param + ' from JS');})";
    
         public static void main(String[] args) {
             String who = args.length == 0 ? "World" : args[0];
             System.out.println("Hello " + who + " from Java");
             try (Context context = Context.create()) {
                 Value value = context.eval("js", JS_CODE);
                 value.execute(who);
             }
         }
     }
    

    此示例应用程序使用 Polyglot API 并将 JavaScript 函数作为 Java 值返回。

  3. 将以下依赖项添加到 pom.xml 中,以包含 JavaScript 引擎 (GraalJS)
     <dependencies>
         <dependency>
             <groupId>org.graalvm.polyglot</groupId>
             <artifactId>polyglot</artifactId>
             <version>${graaljs.version}</version>
         </dependency>
         <dependency>
             <groupId>org.graalvm.polyglot</groupId>
             <artifactId>js</artifactId>
             <version>${graaljs.version}</version>
             <type>pom</type>
         </dependency>
     </dependencies>
    

    通过将 graaljs.version 属性添加到 <properties> 部分,设置 GraalJS 和 GraalVM Polyglot API 版本。或者,您可以直接用版本字符串替换 ${graaljs.version}。在本例中,使用 24.1.0

     <properties>
         <graaljs.version>24.1.0</graaljs.version>
     </properties>
    
  4. 将用于将项目编译成 JAR 文件和将所有运行时依赖项复制到目录中的 Maven 插件添加到您的 pom.xml 文件
     <build>
         <plugins>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-compiler-plugin</artifactId>
                 <version>3.13.0</version>
                 <configuration>
                     <fork>true</fork>
                 </configuration>
             </plugin>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-jar-plugin</artifactId>
                 <version>3.4.2</version>
                 <configuration>
                     <archive>
                         <manifest>
                             <mainClass>com.example.App</mainClass>
                         </manifest>
                     </archive>
                 </configuration>
             </plugin>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-dependency-plugin</artifactId>
                 <version>3.8.0</version>
                 <executions>
                     <execution>
                         <id>copy-dependencies</id>
                         <phase>package</phase>
                         <goals>
                             <goal>copy-dependencies</goal>
                         </goals>
                         <configuration>
                             <outputDirectory>${project.build.directory}/modules</outputDirectory>
                             <includeScope>runtime</includeScope>
                             <includeTypes>jar</includeTypes>
                         </configuration>
                     </execution>
                 </executions>
             </plugin>
         </plugins>
     </build>
    
  5. (可选)将 module-info.java 添加到您的应用程序。如果您想在模块路径上运行应用程序,请在 src/main/java 中创建一个 module-info.java 文件,其中包含以下内容
     module com.example {
         requires org.graalvm.polyglot;
     }
    
  6. 编译并打包项目
     mvn clean package
    
  7. 使用 GraalVM 或另一个兼容的 JDK 运行应用程序。如果您在项目中包含了 module-info.java(步骤 5),您现在可以在模块路径上运行应用程序,使用以下命令之一
    java --module-path target/modules:target/helloworld-1.0-SNAPSHOT.jar --module com.example/com.example.App "GraalVM"
    java -p target/modules:target/helloworld-1.0-SNAPSHOT.jar -m com.example/com.example.App "GraalVM"
    

    否则,您可以使用模块路径上的依赖项和类路径上的应用程序运行

    java --module-path target/modules --add-modules=org.graalvm.polyglot -cp target/helloworld-1.0-SNAPSHOT.jar com.example.App "GraalVM"
    java --module-path target/modules --add-modules=org.graalvm.polyglot -jar target/helloworld-1.0-SNAPSHOT.jar "GraalVM"
    

    或者,您也可以在类路径上运行所有内容(在这种情况下,您需要使用 * 或指定所有 JAR 文件)

    java -cp "target/modules/*:target/helloworld-1.0-SNAPSHOT.jar" com.example.App "GraalVM"
    # or using shell expansion:
    java -cp "$(find target/modules -name '*.jar' | tr '\n' :)target/helloworld-1.0-SNAPSHOT.jar" com.example.App "GraalVM"
    java -cp "$(printf %s: target/modules/*.jar)target/helloworld-1.0-SNAPSHOT.jar" com.example.App "GraalVM"
    

    注意:我们不建议将所有依赖项捆绑到单个“胖”JAR 中(例如,使用 Maven Assembly 插件),因为它会导致问题,并阻止使用 GraalVM Native Image 进行提前编译。相反,我们建议使用所有 org.graalvm.* 依赖项的原始、独立 JAR 文件,最好是在模块路径上。在 嵌入语言指南 中了解更多信息。

源代码单元可以用字符串表示,如示例所示,也可以用文件、从 URL 读取以及 其他方式 表示。通过包装函数定义 (()),您将立即返回函数

Value f = context.eval("js", "(function f(x, y) { return x + y; })");
Value result = f.execute(19, 23);

您还可以从 JavaScript 中查找 Java 类型并实例化它们,如下所示

try (Context context = Context.newBuilder()
                           .allowHostAccess(HostAccess.newBuilder(HostAccess.ALL).build())
                           .allowHostClassLookup(className -> true)
                       .build()) {
    java.math.BigDecimal v = context.eval("js",
            "var BigDecimal = Java.type('java.math.BigDecimal');" +
            "BigDecimal.valueOf(10).pow(20)")
        .asHostObject();
    assert v.toString().equals("100000000000000000000");
}

Polyglot API 提供了许多其他方法来从 Java 访问访客语言代码,例如,通过直接访问 JavaScript 对象、数字、字符串和数组。在 Java 互操作性指南 中了解有关 JavaScript 到 Java 互操作性的更多信息,并找到更多示例。

GraalJS 也作为独立发行版提供,您可以从 GitHub 下载。了解更多信息,请访问 此处

我们为 GraalJS 用户提供以下文档

迁移指南

了解有关从旧环境迁移的更多信息

与我们联系