杰瑞科技汇

Java如何直接执行JavaScript代码?

Java 与 JavaScript 的交互

Java 执行 JavaScript 的本质是:Java 代码创建并控制一个 JavaScript 执行引擎(也称为 ScriptEngine),然后将 JavaScript 代码交给这个引擎去执行,最后引擎可以将执行结果返回给 Java 代码。

Java如何直接执行JavaScript代码?-图1
(图片来源网络,侵删)

使用 Java 内置的 Nashorn (Java 8+ 推荐)

Java 8 开始,Oracle 引入了 Nashorn,这是一个更现代、更快的 JavaScript 引擎,它完全实现了 ECMAScript 5.1 规范,并支持部分 ES6 特性,在 Java 11 中,Nashorn 被标记为“废弃”,但在 Java 8 中它仍然是官方支持的、性能最好的选择。

Nashorn 的基本使用

Nashorn 实现了 JSR-223 (Scripting for the Java Platform) 标准,因此你可以使用标准的 javax.script API 来调用它。

示例代码:

import javax.script.*;
public class NashornExample {
    public static void main(String[] args) throws ScriptException {
        // 1. 获取 Nashorn 脚本引擎
        ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
        // 2. 执行简单的 JavaScript 代码
        engine.eval("var msg = 'Hello from Nashorn!';");
        // 3. 执行并打印结果
        engine.eval("print(msg);"); // 输出: Hello from Nashorn!
        // 4. 执行更复杂的代码
        engine.eval("function add(a, b) { return a + b; }");
        // 5. 将 Java 变量传递给 JavaScript
        int a = 10;
        int b = 20;
        engine.eval("var sum = add(" + a + ", " + b + ");");
        // 6. 将 JavaScript 变量获取到 Java 中
        Object result = engine.eval("sum;");
        System.out.println("The sum is: " + result); // 输出: The sum is: 30
    }
}

Java 与 Nashorn 的深度交互

Nashorn 最强大的功能是 Java 和 JavaScript 之间的无缝互操作

Java如何直接执行JavaScript代码?-图2
(图片来源网络,侵删)

示例:在 JavaScript 中调用 Java 方法

import javax.script.*;
import java.util.*;
public class NashornJavaInterop {
    public static void main(String[] args) throws ScriptException {
        ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
        // 1. 让 Nashorn 可以使用 Java 的类
        engine.eval("var ArrayList = Java.type('java.util.ArrayList');");
        engine.eval("var list = new ArrayList();");
        // 2. 在 JavaScript 中调用 Java 对象的方法
        engine.eval("list.add('Item 1');");
        engine.eval("list.add(2);"); // JavaScript 的数字会自动转为 Java 的 Integer
        engine.eval("list.add(new java.util.Date());");
        // 3. 从 Java 访问 JavaScript 创建的对象
        @SuppressWarnings("unchecked")
        List<Object> myList = (List<Object>) engine.get("list");
        System.out.println("Java sees the list as: " + myList);
        // 输出: Java sees the list as: [Item 1, 2, Tue Oct 26 10:30:00 CST 2025]
        // 4. 在 JavaScript 中调用 Java 的静态方法
        engine.eval("var System = Java.type('java.lang.System');");
        engine.eval("System.out.println('Printing from JS via Java System!');");
    }
}

使用 Java 11+ 的 GraalVM (现代推荐)

Java 11 开始,Oracle 官方不再内置 Nashorn,未来的趋势是使用 GraalVM,GraalVM 是一个高性能的多语言虚拟机,它提供了一个新的 JavaScript 引擎 Graal.js,性能远超 Nashorn,并且支持更多现代 JavaScript 特性。

如何使用 GraalVM

要使用 Graal.js,你需要将相关的依赖项添加到你的项目中。

Maven 依赖:

Java如何直接执行JavaScript代码?-图3
(图片来源网络,侵删)
<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 依赖:

implementation 'org.graalvm.js:js:23.1.0'
implementation 'org.graalvm.js:js-scriptengine:23.1.0'

GraalVM 的基本使用

GraalVM 也完全兼容 JSR-223,API 基本上和 Nashorn 一样。

示例代码:

import javax.script.*;
import org.graalvm.js.scriptengine.GraalJSScriptEngine;
public class GraalVMExample {
    public static void main(String[] args) throws ScriptException {
        // 1. 获取 Graal.js 脚本引擎
        ScriptEngine engine = new ScriptEngineManager().getEngineByName("graal.js");
        // 2. 执行代码
        engine.eval("console.log('Hello from GraalVM!');");
        // 3. 定义函数并调用
        engine.eval("function greet(name) { return 'Hello, ' + name + '!'; }");
        Object result = engine.eval("greet('GraalVM User');");
        System.out.println(result); // 输出: Hello, GraalVM User!
    }
}

GraalVM 同样支持 Java 和 JavaScript 之间的深度互操作,语法与 Nashorn 类似,但更加强大和灵活。


使用第三方库 (Rhino)

Rhino 是 Mozilla 开源的 JavaScript 引擎,在 Nashorn 出现之前,Rhino 是 Java 世界中执行 JavaScript 的标准,它仍然被广泛使用,尤其是在需要兼容旧版 Java (Java 6, 7) 的项目中。

Rhino 的基本使用

Rhino 也有自己的 API,不完全兼容 JSR-223,所以用法略有不同。

Maven 依赖:

<dependency>
    <groupId>org.mozilla</groupId>
    <artifactId>rhino</artifactId>
    <version>1.7.14</version>
</dependency>

示例代码:

import org.mozilla.javascript.*;
public class RhinoExample {
    public static void main(String[] args) {
        // 1. 创建一个上下文
        Context cx = Context.enter();
        try {
            // 2. 初始化作用域
            Scriptable scope = cx.initStandardObjects();
            // 3. 执行字符串形式的 JavaScript 代码
            cx.evaluateString(scope, "var msg = 'Hello from Rhino!';", "script", 1, null);
            cx.evaluateString(scope, "print(msg);", "script", 1, null);
            // 4. 执行文件中的 JavaScript 代码 (需要 Rhino 1.6R+)
            // cx.evaluateReader(scope, new FileReader("path/to/your/script.js"), "script.js", 1, null);
            // 5. 调用 JavaScript 函数并获取结果
            Object result = cx.evaluateString(scope, "function add(a, b) { return a + b; } add(5, 7);", "script", 1, null);
            // Rhino 的结果需要转换为 Java 类型
            if (result instanceof Number) {
                int sum = ((Number) result).intValue();
                System.out.println("The sum is: " + sum); // 输出: The sum is: 12
            }
        } finally {
            // 6. 退出上下文
            Context.exit();
        }
    }
}

通过 Process 执行 Node.js (不推荐用于简单场景)

如果你的项目环境已经安装了 Node.js,你也可以通过 Java 的 ProcessBuilder 来启动一个 Node.js 进程,让它执行你的 JavaScript 文件,然后通过标准输入输出进行通信。

缺点:

  • 性能差: 每次执行都要创建一个新的进程,开销巨大。
  • 复杂: 需要处理进程间通信、数据序列化/反序列化。
  • 依赖: 需要目标环境安装 Node.js。

适用场景:

  • 当你需要执行的 JavaScript 代码非常复杂,依赖于 Node.js 特有的生态系统(如 NPM 包)时。
  • 你无法在 Java 项目中添加 JavaScript 引擎依赖。

总结与选择建议

方案 优点 缺点 推荐场景
Nashorn - Java 8 内置,无需额外依赖
- 性能较好
- 完全支持 JSR-223 标准
- Java 11+ 已废弃
- ECMAScript 版本较老 (ES5.1)
仍在使用 Java 8 的项目,这是最简单、最快捷的方案。
GraalVM - 性能极高,远超 Nashorn
- 支持现代 JavaScript (ES6+)
- 是 Java 的未来方向
- 支持多种语言互操作
- 需要手动添加依赖 新项目,或需要高性能、现代 JS 特性的项目,这是长期来看的最佳选择
Rhino - 历史悠久,非常稳定
- 兼容旧版 Java (Java 6, 7)
- 性能不如 Nashorn 和 GraalVM
- API 较旧,不完全兼容 JSR-223
维护旧版 Java 项目的遗留代码。
Node.js 进程 - 可利用整个 Node.js 生态系统
- 极其灵活
- 性能开销大
- 实现复杂,需要处理进程通信
- 依赖外部环境
当 JavaScript 代码严重依赖 Node.js 特定库,且无法移植到 Java 引擎时。

最终建议

  1. 如果你使用 Java 8:直接使用 Nashorn,它开箱即用,足够强大。
  2. 如果你使用 Java 11 或更高版本:强烈推荐使用 GraalVM,请务必添加相应的 Maven/Gradle 依赖,这是目前最先进、性能最好的方案。
  3. 如果你在维护一个非常老的 Java 项目:你可能别无选择,只能使用 Rhino
  4. 尽量避免使用“通过 Node.js 进程执行” 的方案,除非你有非常特殊的、无法绕过的需求。
分享:
扫描分享到社交APP
上一篇
下一篇