package com.wflow.workflow.execute; import lombok.extern.slf4j.Slf4j; import org.graalvm.polyglot.Context; import org.graalvm.polyglot.HostAccess; import org.graalvm.polyglot.Value; import java.util.Objects; import java.util.concurrent.ExecutorService; /** * @author : willian fu * @date : 2023/10/28 */ @Slf4j public class JsExecute { private static final Class[] alowJsCallJavaClass = new Class[]{ //HttpRequest.class, System.class // GraalVM的HostAccess默认允许访问一些常见的类,例如System // 如果你需要访问自定义的类,你需要在这里配置 }; private static Context context; // 使用 Context.Builder 来创建和配置沙箱环境 public JsExecute(ExecutorService executorService) { if (Objects.isNull(context)) { // 使用 Context.Builder 来创建和配置 GraalVM 沙箱 context = Context.newBuilder("js") .allowHostAccess(HostAccess.ALL) // 允许访问所有Java对象 // 如果只想允许特定类,可以使用HostAccess.newBuilder() .allowHostClassLookup(s -> true) // 允许查找所有Java类 // 如果只想允许特定类,可以配置如下: // .allowHostClassLookup(className -> { // return className.equals("com.yourpackage.HttpRequest") || className.equals("java.lang.System"); // }) .allowAllAccess(true) // 允许所有访问,包括I/O、线程等 .option("engine.WarnInterpreterOnly", "false") // 忽略解释器模式警告 .build(); // GraalVM的资源限制配置有所不同,通常是在创建context时设置,或者通过线程池等外部方式管理。 // 例如,CPU时间限制等需要通过更复杂的机制实现,Context.Builder不直接支持MaxCPUTime等。 // 内存限制通常通过JVM的-Xmx参数来控制。 // 你可以继续使用你传入的ExecutorService来控制并发。 } } public T execute(String func, String script, Class resultType, Object... args) { try { // 注意:GraalVM 的 Context.eval() 有两种重载, // 一种是直接执行,另一种是带源文件名的,这里简化使用 context.eval("js", script); // 获取 JavaScript 函数 Value function = context.getBindings("js").getMember(func); if (function == null || !function.canExecute()) { throw new NoSuchMethodException("Function " + func + " not found or not executable."); } // 执行函数并获取结果 Value result = function.execute(args); // 使用 Value.as() 方法进行类型转换,这是 GraalVM 推荐的方式 return result.as(resultType); } catch (Exception e) { log.error("js 函数[{}] [{}]执行异常: [{}]", func, script, e.getMessage()); throw new RuntimeException("js函数解析执行异常:" + e.getMessage(), e); } } public void executeVoid(String func, String script, Object... args) { execute(func, script, Object.class, args); } }