JDK 6 引入 javax.script 套件 (JSR 223),將腳本引擎標準化嵌入 JVM。預設內建 Mozilla Rhino 實作 JavaScript,任意 JSR 223 相容引擎 (Groovy, JRuby, Jython 等) 均可即插即用。
ScriptEngineManager:引擎發現與管理入口ScriptEngine:腳本執行上下文,核心方法 eval(), put(), get()Invocable:介面,支援呼叫腳本函式、實現 Java 介面Compilable:介面,支援腳本預編譯提升效能import javax.script.*;
public class ScriptingDemo {
public static void main(String[] args) throws Exception {
ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine engine = mgr.getEngineByName("JavaScript"); // 或 "js"
// 1. 基礎執行
engine.eval("print('Hello, Scripting')");
// 2. 暴露 Java 物件為全域變數
File f = new File("test.txt");
engine.put("file", f);
engine.eval("println('Total Space: ' + file.getTotalSpace())");
// 3. 呼叫腳本函式
engine.eval("function hello(name) { return 'Hello, ' + name; }");
Invocable inv = (Invocable) engine;
Object result = inv.invokeFunction("hello", "Scripting");
System.out.println("Result: " + result);
// 4. 腳本實現 Java 介面
engine.eval("var runner = { run: function() { println('Script run()'); } };");
Runnable r = inv.getInterface(engine.get("runner"), Runnable.class);
new Thread(r).start();
// 5. 腳本使用 JDK 類別 (Swing 範例)
String swingScript = "function showFrame(title) {" +
"var JFrame = Packages.javax.swing.JFrame;" +
"var f = new JFrame(title);" +
"f.setSize(400,300); f.setVisible(true); }";
engine.eval(swingScript);
inv.invokeFunction("showFrame", "Scripting Swing");
}
}
腳本中透過 Packages.java.lang.System 存取 Java 套件,java.lang 可簡寫為 java.lang (Rhino 特有)。
ScriptEngine 非執行緒安全,多執行緒環境需每執行緒建立實例或同步控制。
Compilable 的引擎可預編譯:CompiledScript cs = ((Compilable)engine).compile(script); cs.eval();$ jrunscript
js> println("Hello")
Hello
js> 9*8
72.0
js> new javax.swing.JFrame("Test").setVisible(true)
適用於快速驗證腳本邏輯、互動式探索 Java API、批次執行 .js 檔案。
實作 ScriptEngineFactory 與 ScriptEngine (建議繼承 AbstractScriptEngine),打包為 JAR,在 META-INF/services/javax.script.ScriptEngineFactory 註冊實現類名稱,即可被 ScriptEngineManager 自動發現。
JSR 223 將 JVM 變為多語言運行平台,Java 應用獲得動態性、擴展性與多語言互操作能力。善用腳本外部化業務邏輯,能顯著降低系統耦合度與部署成本。