Java 6 引入 `javax.script` (JSR 223),打通 Java 生態與腳本語言(JavaScript/Rhino、JRuby、Groovy 等)。不必將整個應用遷移至動態語言,只需在關鍵環節嵌入腳本,即可兼得開發效率與平台穩健。本文揭示 5 大進階用法。
JDK `bin/` 目錄下的 `jrunscript` 可直接執行 `.js` 檔案或進入 REPL 互動模式。解決 Windows 批次檔與 Unix Shell 腳本雙維護痛點:
// periodic.js
while (true) {
echo("Hello, world!");
}
C:\> jrunscript periodic.js
Hello, world!
Hello, world!
...
無 DOM 環境,但擁有完整 Java 類庫存取權。
Rhino 提供 `Packages` 前綴存取非 `java.*` 套件:
// 方式一:Runtime.exec
var p = java.lang.Runtime.getRuntime().exec("jmap", ["-histo", arguments[0]]);
p.waitFor();
// 方式二:直接呼叫工具主類(避免流處理)
var args = ["-histo", arguments[0]];
Packages.sun.tools.jmap.JMap.main(args);
`arguments` 為腳本參數陣列(命令列傳入)。
ScriptEngine engine = new ScriptEngineManager().getEngineByName("javascript");
for (String arg : args) {
FileReader fr = new FileReader(arg);
engine.eval(fr); // 或 eval(String)
}
腳本來源可為檔案、資料庫、用戶輸入、動態生成字串。
Bindings bindings = new SimpleBindings();
bindings.put("author", new Person("Ted", "Neward", 39));
bindings.put("title", "5 Things You Didn't Know");
engine.eval(fr, bindings);
腳本中直接存取:
println("author.firstName = " + author.firstName); // JavaBeans 屬性自動映射
if (engine instanceof Compilable) {
Compilable compEngine = (Compilable) engine;
CompiledScript cs = compEngine.compile(fr); // 編譯為位元碼
cs.eval(bindings); // 重複執行不同綁定
} else {
engine.eval(fr, bindings);
}
關鍵點:`CompiledScript` 實例應長期快取(如 ServletContext),腳本變更時重新編譯。避免重複解析驗證開銷,大幅提升高頻腳本執行效能。
`jrunscript` + `javax.script` 讓 Java 應用輕量級嵌入腳本能力,適用於規則引擎、動態配置、測試腳本、擴充點等場景。Rhino (JavaScript) 內建於 JDK,零依賴即可上手;需更強語言特性時可整合 JRuby/Groovy 等 JSR 223 相容引擎。