首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 腳本引擎實戰:在 Java 中動態執行 JavaScript 代碼

     編輯:Java 相關知識

前言:為什麼在 Java 中運行 JavaScript?

Java 6 引入 JSR-223 (javax.script) 標準化腳本引擎 API,使 Java 應用能夠動態加載、編譯、執行 JavaScript、Groovy 等腳本語言。這對於規則引擎、動態配置、用戶自定義邏輯擴展等場景極具價值。

核心 API 速覽

  • ScriptEngineManager:引擎管理器,負責發現和創建引擎實例。
  • ScriptEngine:腳本引擎接口,提供 eval() 執行腳本。
  • Invocable:可調用接口,允許調用腳本中定義的具體函數/方法。
  • Bindings / ScriptContext:作用域綁定,用於在 Java 與腳本間共享變量/對象。

完整示例:Java 與 JS 雙向交互

以下代碼演示:將 Java 對象 (JFrame, List) 暴露給 JS,執行 JS 文件,調用 JS 函數,獲取返回值,並反向調用 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)
        ScriptEngine engine = new ScriptEngineManager().getEngineByExtension("js");
        System.out.println("是否支持 Invocable: " + (engine instanceof Invocable));

        // 2. 準備共享對象
        JFrame frame = new JFrame("Script Demo");
        List<String> list = new ArrayList<>();

        // 3. 綁定到引擎作用域
        Bindings bindings = engine.createBindings();
        bindings.put("jf", frame);
        bindings.put("list", list);
        engine.setBindings(bindings, ScriptContext.ENGINE_SCOPE);

        // 4. 執行外部 JS 文件
        Object result = engine.eval(new FileReader("script.js"));
        System.out.println("腳本執行返回值: " + result); // 通常為 null

        // 5. 調用腳本中定義的函數
        if (engine instanceof Invocable) {
            Invocable invocable = (Invocable) engine;

            // 調用無參函數
            invocable.invokeFunction("testJS"); // 輸出: Hello world!

            // 調用有返回值函數
            List<String> names = (List<String>) invocable.invokeFunction("getNames");
            System.out.println("JS 返回列表: " + names); // [doSth, getNames]

            // 調用操作 Java 對象的函數
            invocable.invokeFunction("doSth"); // 顯示 JFrame 窗口
        }
    }
}

配套 JS 文件 (script.js)

function doSth() {
    jf.setSize(500, 300);
    jf.setVisible(true);
    jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

function getNames() {
    list.add("doSth");
    list.add("getNames");
    return list;
}

function testJS() {
    print('Hello from JavaScript!');
}

關鍵技術點解析

1. 作用域與綁定

ENGINE_SCOPE 使綁定對象在整個引擎生命周期內可見。還有 GLOBAL_SCOPE 跨引擎共享。

2. Java 對象在 JS 中的訪問

JS 可直接調用 Java 對象的公共方法、訪問屬性(如 jf.setSize())、甚至實現 Java 接口。集合操作 (list.add()) 亦無縫互通。

3. 異常處理

eval() 和 invokeFunction() 拋出 ScriptException、NoSuchMethodException,生產環境務必捕獲處理。

4. 性能考量

  • 引擎創建開銷大,應複用引擎實例。
  • 頻繁調用熱點函數可考慮 CompiledScript 預編譯。
  • Nashorn (Java 8+) 性能優於 Rhino,支持 invokedynamic。

應用場景

  • 業務規則引擎:非技術人員維護規則腳本。
  • 動態報表/模板:JS 生成 HTML/JSON。
  • 插件擴展系統:用戶編寫腳本擴展功能。
  • 測試腳本化:數據驅動測試邏輯外部化。

總結

Java 腳本引擎 API 為 JVM 語言互操作提供了標準橋樑。通過 Invocable 和 Bindings,實現了 Java 與 JavaScript 的深度雙向交互。合理使用可大幅提升系統靈活性,但需注意安全性(沙箱)、性能(複用/編譯)與維護性(腳本管理)平衡。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved