| 接口/類 | 角色 |
| ScriptEngineManager | 引擎工廠,按擴展名/MIME/名稱獲取引擎 |
| ScriptEngine | 腳本執行上下文,核心方法 eval() |
| Invocable | 子接口,支援調用腳本中定義的函數/方法 |
| Bindings / ScriptContext | 變量作用域管理 (ENGINE_SCOPE / GLOBAL_SCOPE) |
完整示例:Java 調用 JavaScript 函數並共享對象
test.js (外部腳本文件,放在 classpath 根目錄)
function doSth() {
jf.setSize(500, 300);
jf.setVisible(true);
jf.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
}
function getNames() {
list.add("doSth");
list.add("getNames");
return list;
}
function testJS() {
print('Hello from JavaScript!');
}
Java 宿主程序
import javax.script.*;
import javax.swing.JFrame;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;
public class ScriptDemo {
public static void main(String[] args) throws Exception {
// 1. 獲取 JS 引擎 (Rhino / Nashorn / GraalJS 視 JDK 版本)
ScriptEngine engine = new ScriptEngineManager().getEngineByExtension("js");
System.out.println("引擎: " + engine.getClass().getName());
System.out.println("支援 Invocable: " + (engine instanceof Invocable));
// 2. 準備共享給腳本的 Java 對象
JFrame jf = new JFrame("Script Demo");
List list = new ArrayList<>();
// 3. 綁定變量到引擎作用域
Bindings bindings = engine.createBindings();
bindings.put("jf", jf);
bindings.put("list", list);
engine.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
// 4. 執行腳本文件 (定義函數)
Object result = engine.eval(new FileReader("test.js"));
System.out.println("eval 返回: " + result); // 通常為 null
// 5. 調用腳本函數並獲取返回值
Invocable invocable = (Invocable) engine;
List returned = (List) invocable.invokeFunction("getNames");
System.out.println("getNames 返回: " + returned);
invocable.invokeFunction("testJS"); // 無返回值
invocable.invokeFunction("doSth"); // 操作 Java Swing 組件
}
}
關鍵技術細節
- 作用域隔離:
ENGINE_SCOPE 僅在當前引擎實例可見;GLOBAL_SCOPE 跨引擎共享 (慎用)。
- 類型轉換:JS 數組 ↔ Java List、JS 對象 ↔ Java Map、JS 函數 ↔
java.util.function.Function (Nashorn+)。
- 安全沙箱:生產環境需配置
ScriptEngineFactory.getParameter("THREADING")、限制 java.lang.Runtime 訪問、設置 CPU/內存配額。
- 效能考量:腳本解析編譯有開銷,熱點腳本應緩存
CompiledScript (若引擎支援 Compilable)。
引擎演進時間軸
| JDK 版本 | 默認 JS 引擎 | 特點 |
| 6 ~ 7 | Mozilla Rhino | 純 Java 實現,解釋執行,較慢 |
| 8 ~ 14 | Nashorn | 基於 invokedynamic,JIT 編譯,性能大幅提升 |
| 15+ | 移除內建引擎 | 需額外引入 org.graalvm.js:js-scriptengine (GraalJS) |
適用場景與避坑指南
- ✅ 適用:業務規則引擎、報表模板、用戶自定義計算公式、配置熱加載。
- ❌ 避免:高頻核心路徑 (毫秒級延遲敏感)、大數據量處理、多線程高併發共享狀態 (腳本引擎通常非線程安全)。
- 🔒 安全:嚴禁執行不可信用戶提交的腳本,除非嚴格沙箱隔離。
- 上一篇文章: Java 垃圾收集算法深度解析:從核心思想到內存洩漏排查實戰
- 下一篇文章: Java Web 中 Cookie 完整操作指南:設置、讀取、刪除與跨路徑陷阱
Copyright ©
程式碼之家 All Rights Reserved