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

Java 6 脚本引擎 API (JSR-223) 實戰:動態執行 JavaScript 與 Java 互操作

     編輯:Java 相關知識

背景與價值

JDK 6 引入 javax.script (JSR-223),提供統一的腳本引擎框架。核心優勢:

  • 熱部署邏輯:業務規則、驗證腳本、模板渲染外置為 .js/.groovy 文件,修改即時生效,無需重新編譯部署。
  • 多語言互操作:Java 對象直接傳入腳本引擎,腳本可調用 Java 方法、訪問屬性、實現接口。
  • 領域特定語言 (DSL):為非技術人員提供可讀寫的配置腳本。

核心 API 速覽

完整示例: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 組件
    }
}

關鍵技術細節

  1. 作用域隔離:ENGINE_SCOPE 僅在當前引擎實例可見;GLOBAL_SCOPE 跨引擎共享 (慎用)。
  2. 類型轉換:JS 數組 ↔ Java List、JS 對象 ↔ Java Map、JS 函數 ↔ java.util.function.Function (Nashorn+)。
  3. 安全沙箱:生產環境需配置 ScriptEngineFactory.getParameter("THREADING")、限制 java.lang.Runtime 訪問、設置 CPU/內存配額。
  4. 效能考量:腳本解析編譯有開銷,熱點腳本應緩存 CompiledScript (若引擎支援 Compilable)。

引擎演進時間軸

接口/類角色
ScriptEngineManager引擎工廠,按擴展名/MIME/名稱獲取引擎
ScriptEngine腳本執行上下文,核心方法 eval()
Invocable子接口,支援調用腳本中定義的函數/方法
Bindings / ScriptContext變量作用域管理 (ENGINE_SCOPE / GLOBAL_SCOPE)
JDK 版本默認 JS 引擎特點
6 ~ 7Mozilla Rhino純 Java 實現,解釋執行,較慢
8 ~ 14Nashorn基於 invokedynamic,JIT 編譯,性能大幅提升
15+移除內建引擎需額外引入 org.graalvm.js:js-scriptengine (GraalJS)

適用場景與避坑指南

  • ✅ 適用:業務規則引擎、報表模板、用戶自定義計算公式、配置熱加載。
  • ❌ 避免:高頻核心路徑 (毫秒級延遲敏感)、大數據量處理、多線程高併發共享狀態 (腳本引擎通常非線程安全)。
  • 🔒 安全:嚴禁執行不可信用戶提交的腳本,除非嚴格沙箱隔離。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved