Experimental feature in GraalVM

将洞察力嵌入应用程序

将洞察嵌入 Java #

Graal 语言(使用 Truffle 框架实现的语言,例如 JavaScript、Python、Ruby 和 R)可以通过 多语言上下文 API 嵌入到自定义 Java 应用程序中。GraalVM 洞察也可以通过相同的 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);

获取用于 `Context` 的 `Engine` 并请求 `insight` 仪器。

然后使用 GraalVM 洞察脚本创建 `Source`,并在获取其仪器句柄时应用它。使用 `handle.close()` 在不再需要时禁用所有脚本的仪器。例如:```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); // 在没有仪器的情况下运行 context.eval(script); // 使用仪器运行 try (AutoCloseable handle = insight.apply(instrument)) { context.eval(script); } // 在没有仪器的情况下运行 context.eval(script); } ``` 查看 [嵌入依赖关系设置](/latest/reference-manual/embed-languages/#dependency-setup)。添加对 `insight` 的依赖关系:``` org.graalvm.polyglot insight 23.1.1 pom ``` ### 忽略内部脚本通常希望将动态语言中编写的某些代码视为特权代码。想象一下与操作系统概念或应用程序其他功能的各种绑定。此类脚本最好保持黑盒状态,并隐藏在 GraalVM 洞察仪器功能之外。要将特权脚本隐藏在视线之外,[将它们标记为内部](https://graalvm.java.net.cn/sdk/javadoc/org/graalvm/polyglot/Source.Builder.html#internal-boolean-)。默认情况下,GraalVM 洞察会忽略并不会处理内部脚本。 ### 扩展洞察脚本的功能将 GraalVM 洞察嵌入到 Java 应用程序中时,可以将其他对象提供给要评估的洞察脚本。例如:```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 代码创建一个仪器,将新符号 `meaning` 注册到每个要评估的洞察脚本。然后,每个脚本都可以引用并使用它,例如,限制方法调用的数量:```java insight.on('enter', (ctx, frames) => { if (--meaning <= 0) throw 'Stop!' }, { roots : true }); ``` 可以公开简单值以及复杂对象。有关详细信息,请查看 [javadoc](https://graalvm.java.net.cn/tools/javadoc/org/graalvm/tools/insight/Insight.SymbolProvider.html)。请注意,仪器可以更改程序执行的许多方面,并且不受任何安全沙箱的约束。 ## 将洞察嵌入到 Node.js 中[洞察手册](/latest/tools/graalvm-insight/manual/) 展示了许多使用 GraalVM 洞察的示例,这些示例使用 `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 洞察脚本发送到它。例如,以下脚本将观察谁调用 `process.exit`:```bash curl --data \ 'insight.on("enter", (ctx, frame) => { console.log(new Error("call to exit").stack); }, \ { roots: true, rootNameFilter: "exit" });' \ -X POST http://localhost:9999/ ``` 在编写自己的 `adminserver.js` 时,请注意安全。只有授权人员应该对应用程序应用任意挂钩。不要将管理服务器端口开放给所有人。 ### 接下来阅读什么要了解有关洞察的更多信息并查找一些用例,请访问 [洞察手册](/latest/tools/graalvm-insight/manual/)。它从必要的 _HelloWorld_ 示例开始,然后演示更具挑战性的任务。

联系我们