首页 > 解决方案 > 将 Nashorn 迁移到 GraalVM 以缓存和执行脚本

问题描述

所以我有一个 java 应用程序,它使用 NashornScriptEngine 创建一个 CompiledScript,然后我可以在其中创建一个 Invocable。编译后的脚本是从文件输入编译的,这是我要运行的 js。然后我将此 Invocable 缓存在地图中以供稍后执行。使用它就像

import javax.script.Invocable;

public void handleEvent(Event event, Processor processor){
    try {
        Invocable script = cache.get(event);
        if(script != null) {
            script.invokeFunction("run", data);
        } else {
            throw new UnsupportedOperationException(event.name());
        }
    } catch (Exception exception) ...
}

但是,由于 Nashorn 已被弃用,我试图在实现相同目标的同时切换到 GraalVM。我看到一些 GitHub 页面讨论了这个问题,但老实说并没有帮助我。这是我正在看的一些。

https://github.com/graalvm/graaljs/blob/master/docs/user/ScriptEngine.md https://github.com/graalvm/graaljs/issues/78

这是我发现最有用的,但是它不允许我像上面的代码那样在入口点调用,也不能创建一个可调用的缓存并稍后调用。

    public void compile(File file){
        try {
            Source source = Source.newBuilder("js", file).build();
            Engine engine = Engine.create();

            Context context = Context.newBuilder("js").engine(engine).option("js.nashorn-compat", "true").build();
            context.eval(source);
            context.close();
        } catch (Exception exception){
            exceptionCaught(exception);
        }
    }

关于如何使用 GraalVM 将文件 (js) 编译为可调用对象的任何提示?谢谢!

标签: javascriptjavagraalvm

解决方案


context.eval()将返回一个类型的值org.graalvm.polyglot.Value。当source返回 afunction时,此值将回答canExecute()true,您可以value.execute(args...)重复使用它。参见 Value 的 API:https ://www.graalvm.org/truffle/javadoc/org/graalvm/polyglot/Value.html

我看到你正在设置nashorn-compat选项。请理解这是一个向后兼容的选项,您最好不要使用它。在许多情况下,如果没有该选项,您的代码将完美运行。请查看迁移指南以了解在 Nashorn 模式下可用的 GraalVM JavaScript 确实不支持某些内容的情况。


推荐阅读