Experimental feature in GraalVM

將 Insight 嵌入應用程式

將 Insight 嵌入 Java #

Graal 語言 (使用 Truffle 框架實作的語言,例如 JavaScript、Python、Ruby 和 R) 可以透過 Polyglot Context API 嵌入到自訂 Java 應用程式中。GraalVM Insight 也可以透過相同的 API 來控制。像

final Engine engine = context.getEngine();
Instrument instrument = engine.getInstruments().get("insight");
Function<Source, AutoCloseable> access = instrument.lookup(Function.class);
AutoCloseable handle = access.apply(agentSrc);

取得 ContextEngine,並請求 insight instrumentation。

然後使用 GraalVM Insight 腳本建立 `Source`,並在取得其 instrumentation 控制代碼時套用它。當不再需要時,使用 `handle.close()` 停用所有腳本的 instrumentation。例如:```java Source instrument = Source.create("js", """ insight.on('return', function(ctx, frame) { console.log(`Instrumented where = ${frame.where}`); }, { roots: true, rootNameFilter: 'end', }); """); Source script = Source.create("js", """ function end() { var where = 'end'; console.log(where + ' invoked') } end(); """); try (Context context = Context.newBuilder().build()) { @SuppressWarnings("unchecked") Function<Source, AutoCloseable> insight = context.getEngine().getInstruments().get("insight").lookup(Function.class); // 在沒有 instrumentation 的情況下執行 context.eval(script); // 在有 instrumentation 的情況下執行 try (AutoCloseable handle = insight.apply(instrument)) { context.eval(script); } // 在沒有 instrumentation 的情況下執行 context.eval(script); } ``` 請參閱 [嵌入依賴項設定](/latest/reference-manual/embed-languages/#dependency-setup)。新增 `insight` 的依賴項:``` org.graalvm.polyglot insight 23.1.1 pom ``` ### 忽略內部腳本 通常會想要將以動態語言撰寫的特定程式碼視為具有特權的程式碼。想像一下與作業系統概念或應用程式其他功能之間的各種繫結。這類腳本最好保持黑箱,並隱藏在 GraalVM Insight instrumentation 功能之外。若要將特權腳本隱藏起來,請[將其標記為內部](https://graalvm.dev.org.tw/sdk/javadoc/org/graalvm/polyglot/Source.Builder.html#internal-boolean-)。依預設,GraalVM Insight 會忽略且不處理內部腳本。 ### 擴充 Insight 腳本的功能 將 GraalVM Insight 嵌入到 Java 應用程式時,您可以讓其他物件可用於正在評估的 Insight 腳本。例如:```java @TruffleInstrument.Registration( id = "meaningOfWorld", name = "Meaning Of World", version = "demo", services = { Insight.SymbolProvider.class } ) public final class MeaningOfWorldInstrument extends TruffleInstrument { @Override protected void onCreate(Env env) { Map<String, Integer> symbols = Collections.singletonMap("meaning", 42); Insight.SymbolProvider provider = () -> symbols; env.registerService(provider); } } ``` 上述 Java 程式碼會建立一個 instrumentation,此 instrumentation 會向每個評估的 Insight 腳本註冊一個新的符號 `meaning`。然後每個腳本都可以參考和使用它,例如,限制方法呼叫的次數:```java insight.on('enter', (ctx, frames) => { if (--meaning <= 0) throw 'Stop!' }, { roots : true }); ``` 可以公開簡單的值以及複雜的物件。如需更詳細的資訊,請參閱 [javadoc](https://graalvm.dev.org.tw/tools/javadoc/org/graalvm/tools/insight/Insight.SymbolProvider.html)。請注意,instrumentation 可以變更程式執行的許多方面,且不受任何安全性沙箱約束。 ## 將 Insight 嵌入 Node.js [Insight 手冊](/latest/tools/graalvm-insight/manual/) 顯示了許多使用 GraalVM Insight 和 `node` 的範例。但是,它們大多數都依賴於命令列選項 `--insight`,並且沒有從該工具的動態性質中獲益。下一個範例顯示如何建立管理伺服器。將此程式碼儲存到 `adminserver.js`:```js function initialize(insight, require) { const http = require("http"); const srv = http.createServer((req, res) => { let method = req.method; if (method === 'POST') { var data = ''; req.on('data', (chunk) => { data += chunk.toString(); }); req.on('end', () => { const fn = new Function('insight', data); try { fn(insight); res.write('GraalVM Insight hook activated\n'); } finally { res.end(); } }); } }); srv.listen(9999, () => console.log("Admin ready at 9999")); } let waitForRequire = function (event) { if (typeof process === 'object' && process.mainModule && process.mainModule.require) { insight.off('source', waitForRequire); initialize(insight, process.mainModule.require.bind(process.mainModule)); } }; insight.on('source', waitForRequire, { roots: true }); ``` 該程式會在連接埠 `9999` 開啟 HTTP 伺服器,並偵聽稍後要套用的傳入腳本。叫用應用程式:```bash node --insight=adminserver.js yourapp.js Admin ready at 9999 ``` 執行時,連接到管理連接埠。將任何 GraalVM Insight 腳本傳送給它。例如,下列腳本將觀察誰呼叫 `process.exit`:```bash curl --data \ 'insight.on("enter", (ctx, frame) => { console.log(new Error("call to exit").stack); }, \ { roots: true, rootNameFilter: "exit" });' \ -X POST https://#:9999/ ``` 撰寫自己的 `adminserver.js` 時,請注意安全性。只有授權人員才能將任意掛勾套用至您的應用程式。不要將管理伺服器連接埠開放給所有人。 ### 後續閱讀 若要深入了解 Insight 並尋找一些使用案例,請前往 [Insight 手冊](/latest/tools/graalvm-insight/manual/)。它從必要的 _HelloWorld_ 範例開始,然後示範更具挑戰性的任務。

與我們聯繫