Skc*_*ssm 6 javascript java scripting jshell
背景:
由于 Nashorn 在 JDK15 中被删除,我正在为我正在开发的应用程序寻找替代方案。我目前仅用于在 java swing 桌面应用程序中动态执行一些用户可定义的格式片段。
我并不是特别想向我的应用程序添加另一个库依赖项(例如 rhino)。如果可用的话,我愿意使用 nashorn 作为附加依赖项(这将使我不必重写代码,并确保与现有 js 片段的兼容性)。除了与《我的世界》相关的东西之外,我还没有看到它在任何地方都可用。
我不会切换到 Graal 虚拟机。
问题:
我正在考虑使用 JShell(虽然不是 javascript,但大部分格式化代码非常相似),但我调用它的方式性能很糟糕:
try(JShell js = JShell.create())
{
js.eval("public int add(int a, int b) { return a + b; }");
for(int i = 0; i < 100; i++)
{
List<SnippetEvent> eval = js.eval("add(5,6)");
eval.forEach(se -> {
System.out.println(se.value());
});
}
}
Run Code Online (Sandbox Code Playgroud)
该代码中的 for 循环运行时间约为 6 秒(相比之下,nashorn 中的运行时间约为 11 微秒)。这对于我的应用程序来说不够快。
有没有办法从 JSell 中获取类字节码,以便我可以使用反射直接执行该方法,而不是再次调用“eval”?
有没有办法获取我在 JShell 中创建的方法的“方法句柄”?
有没有什么方法可以创建一个函数,其行为是在 JShell 中定义的,但可以从“正常”java 中高性能地调用?
我今天偶然发现了同样的性能问题,我想我找到了解决方案。归结为以下四个步骤:
LocalExecutionControlProvider使用相同的类加载器在当前运行的 JVM 中启动 JShell以下代码片段为您的示例实现了这种方法。在我的机器上,大约需要。通过 JShell 进行初始函数构建大约需要 350 毫秒 10_000 个后续函数调用需要 50ms。
package app;
import jdk.jshell.JShell;
import jdk.jshell.execution.LocalExecutionControlProvider;
import org.junit.jupiter.api.Test;
import java.util.function.BiFunction;
public class Debug {
public static BiFunction<Integer, Integer, Integer> function = null;
@Test
public void debug() {
JShell jShell = JShell.builder()
.in(System.in).out(System.out).err(System.err)
.executionEngine(new LocalExecutionControlProvider(), null)
.build();
jShell.eval("app.Debug.function = (a,b) -> a+b;");
BiFunction<Integer, Integer, Integer> theFunction = Debug.function;
for (int a = 0; a < 100; a++) {
for (int b = 0; b < 100; b++) {
assert theFunction.apply(a, b) == a + b;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)