杰瑞科技汇

Java如何调用JavaScript方法?

Java 与 JavaScript 的“桥梁”

无论使用哪种方法,其核心都是一个 “脚本引擎”,这是一个由 Java 实现的程序,能够解析和执行 JavaScript 代码,Java 通过 javax.script API(也称为 Nashorn)或新的 GraalVM 来提供这个引擎。

Java如何调用JavaScript方法?-图1
(图片来源网络,侵删)

使用 GraalVM (推荐,现代且高性能)

GraalVM 是 Oracle 推出的一项革命性技术,它是一个高性能的通用虚拟机,支持多种语言(包括 JavaScript、Python、Ruby 等),它的 JavaScript 引擎 GraalJS 是 Nashorn 的继任者,性能更好,功能更全,并且是 Java 21+ 的默认 JavaScript 引擎

准备工作

你需要将 GraalVM 的 JavaScript 依赖项添加到你的项目中。

Maven (pom.xml):

<dependency>
    <groupId>org.graalvm.js</groupId>
    <artifactId>js</artifactId>
    <version>23.1.0</version> <!-- 请使用最新的版本 -->
</dependency>
<dependency>
    <groupId>org.graalvm.js</groupId>
    <artifactId>js-scriptengine</artifactId>
    <version>23.1.0</version>
</dependency>

Gradle (build.gradle):

Java如何调用JavaScript方法?-图2
(图片来源网络,侵删)
implementation 'org.graalvm.js:js:23.1.0' // 请使用最新的版本
implementation 'org.graalvm.js:js-scriptengine:23.1.0'

基本调用示例

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class GraalVMExample {
    public static void main(String[] args) {
        // 1. 脚本引擎管理器
        ScriptEngineManager engineManager = new ScriptEngineManager();
        // 2. 获取 GraalJS 引擎 (会自动查找 classpath 中的 GraalVM)
        ScriptEngine engine = engineManager.getEngineByName("graal.js");
        // 或者直接使用 "js" (推荐)
        // ScriptEngine engine = engineManager.getEngineByName("js");
        if (engine == null) {
            System.err.println("GraalJS 引擎未找到,请确保已添加依赖。");
            return;
        }
        try {
            // 3. 执行简单的 JavaScript 表达式
            System.out.println("--- 执行简单表达式 ---");
            Object result = engine.eval("10 + 15");
            System.out.println("10 + 15 = " + result); // 输出: 25
            // 4. 执行多行 JavaScript 代码
            System.out.println("\n--- 执行多行代码 ---");
            engine.eval("var message = 'Hello from JavaScript!';");
            engine.eval("function greet(name) { return 'Hello, ' + name + '!'; }");
            // 5. 调用 JavaScript 函数并传递参数
            Object greeting = engine.eval("greet('Java World');");
            System.out.println(greeting); // 输出: Hello, Java World!
            // 6. 从 Java 向 JavaScript 传递变量
            System.out.println("\n--- 传递变量 ---");
            String javaVar = "GraalVM";
            engine.eval("var receivedVar = '" + javaVar + "';");
            Object received = engine.eval("console.log('Received in JS: ' + receivedVar); receivedVar;");
            System.out.println("从 JS 返回的变量: " + received);
            // 7. 从 JavaScript 向 Java 传递对象 (更高级的用法)
            System.out.println("\n--- 传递复杂对象 ---");
            engine.eval("var user = { name: 'Alice', age: 30 };");
            // eval 返回的是 JavaScript 对象,GraalVM 会自动将其转换为对应的 Java 对象
            Object userObj = engine.eval("user;");
            System.out.println("从 JS 获取的 Java 对象: " + userObj.getClass().getName());
            System.out.println("用户名: " + ((java.util.Map) userObj).get("name"));
            System.out.println("年龄: " + ((java.util.Map) userObj).get("age"));
        } catch (ScriptException e) {
            e.printStackTrace();
        }
    }
}

GraalVM 的优势

  • 高性能:JIT 编译使其性能远超 Nashorn。
  • 全 ES6+ 支持:支持最新的 JavaScript 语法。
  • 与 Java 21+ 深度集成:是 Java 21 及以后版本默认的 JavaScript 引擎。
  • Polyglot(多语言):同一个虚拟机中可以无缝切换执行 JavaScript、Python 等语言。

使用 Nashorn (传统方法,Java 8-17)

Nashorn 是 Java 8 引入的默认 JavaScript 引擎,用于取代旧的 Rhino,它在 Java 8 到 Java 17 中是标准,GraalVM 出现后,Nashorn 已被标记为“废弃”(deprecated)。

准备工作

  • Java 8+ 环境:Nashorn 是 JDK 自带的,无需额外依赖。
  • 如果你使用 Java 11+,Nashorn 默认是模块化的,可能需要添加 --add-modules=java.scripting 来启用。

基本调用示例

代码与 GraalVM 的示例几乎完全相同,因为它们都遵循 javax.script API。

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class NashornExample {
    public static void main(String[] args) {
        // 1. 脚本引擎管理器
        ScriptEngineManager engineManager = new ScriptEngineManager();
        // 2. 获取 Nashorn 引擎
        // 注意:Nashorn 的名称是 "nashorn"
        ScriptEngine engine = engineManager.getEngineByName("nashorn");
        if (engine == null) {
            System.err.println("Nashorn 引擎未找到。");
            return;
        }
        try {
            // 3. 执行代码 (与 GraalVM 示例相同)
            System.out.println("--- 执行简单表达式 ---");
            Object result = engine.eval("10 + 15");
            System.out.println("10 + 15 = " + result);
            System.out.println("\n--- 执行多行代码 ---");
            engine.eval("var message = 'Hello from Nashorn!';");
            engine.eval("function greet(name) { return 'Hello, ' + name + '!'; }");
            Object greeting = engine.eval("greet('Java World');");
            System.out.println(greeting);
        } catch (ScriptException e) {
            e.printStackTrace();
        }
    }
}

Nashorn 的局限性

  • 性能不如 GraalVM
  • ES6+ 支持不完整:不支持 let/const、箭头函数、类等现代特性。
  • 已废弃:官方建议迁移到 GraalVM。

使用 Rhino (旧版方法)

Rhino 是 Nashorn 之前的 JavaScript 引擎,由 Mozilla 开发,它非常稳定,但已经不再被积极维护,并且从 Java 11 开始,它不再是 JDK 的一部分。

准备工作

你需要手动添加 Rhino 的依赖。

Java如何调用JavaScript方法?-图3
(图片来源网络,侵删)

Maven (pom.xml):

<dependency>
    <groupId>org.mozilla</groupId>
    <artifactId>rhino</artifactId>
    <version>1.7.14</version> <!-- 使用一个较新的稳定版本 -->
</dependency>

基本调用示例

Rhino 的 API 与 javax.script 略有不同,但核心思想一致。

import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
public class RhinoExample {
    public static void main(String[] args) {
        // 1. 创建一个 Rhino 上下文
        Context context = Context.enter();
        try {
            // 2. 初始化作用域 (类似于 JavaScript 的全局对象)
            Scriptable scope = context.initStandardObjects();
            // 3. 执行脚本
            System.out.println("--- 执行简单表达式 ---");
            Object result = context.evaluateString(scope, "10 + 15", "<cmd>", 1, null);
            System.out.println("10 + 15 = " + result);
            System.out.println("\n--- 执行多行代码 ---");
            context.evaluateString(scope, "var message = 'Hello from Rhino!';", "<cmd>", 1, null);
            context.evaluateString(scope, "function greet(name) { return 'Hello, ' + name + '!'; }", "<cmd>", 1, null);
            Object greeting = context.evaluateString(scope, "greet('Java World');", "<cmd>", 1, null);
            System.out.println(greeting);
            // 4. 在作用域中设置 Java 变量
            System.out.println("\n--- 传递变量 ---");
            String javaVar = "Rhino";
            ScriptableObject.putProperty(scope, "javaVar", javaVar);
            context.evaluateString(scope, "console.log('Received in JS: ' + javaVar);", "<cmd>", 1, null);
        } finally {
            // 5. 退出上下文
            Context.exit();
        }
    }
}

Rhino 的特点

  • 非常稳定:历史悠久,经过充分测试。
  • API 不同:不使用 javax.script,有自己的 API,代码更“底层”。
  • 过时:除非有特殊的历史遗留项目需求,否则不推荐使用。

总结与选择

特性 GraalVM (推荐) Nashorn (传统) Rhino (旧版)
状态 现代、活跃 已废弃 (Java 8-17) 过时、不推荐
性能 非常高 较好 一般
JS 版本支持 ES6+ 全支持 ES5/部分 ES6 ES5
Java 版本 任何版本,Java 21+ 默认 Java 8 - Java 17 Java 7 及以前
依赖 需要手动添加 jsjs-scriptengine JDK 自带 (Java 8-17) 需要手动添加 rhino
API javax.script javax.script Rhino 自定义 API
推荐场景 所有新项目,追求性能和现代 JS 语法 维护旧项目 (Java 8-17) 维护非常老的遗留项目

最终建议:

  • 对于任何新的 Java 项目,请毫不犹豫地选择 GraalVM,它是未来,性能最好,功能最全。
  • 如果你正在维护一个使用 Java 8 到 Java 17 的项目,并且无法升级,Nashorn 是你的选择。
  • 除非你有一个无法迁移的古老系统,否则请避免使用 Rhino
分享:
扫描分享到社交APP
上一篇
下一篇