GraalJS及平台JS脚本能力建设

GraalJS及平台JS脚本能力建设

GraalJS替换Nashorn

Oracle宣布弃用Nashorn Javascript引擎,最终将从未来所有的JDK中删除。

Nashorn最初是在JDK 8中引入的,用于取代Rhino脚本引擎。发布时,Nashorn是ECMAScript-262 5.1的完整实现,增强了Java和JavaScript的兼容性,并增加了新的ECMAScript 6(ES6)特性。借助Nashorn,开发人员可以从JavaScript调用Java代码,也可以从Java代码调用JavaScript函数。Nashorn实现javax.script API,弃用Nashorn不会影响javax.script API。

Oracle实验室高级研究总监Thomas Wuerthinger表示,GraalVM是一个不错的替代方案,与Nashorn相比,它的性能更好,与ECMAScript的兼容性也更好。

Javax.script API

javax.script 脚本API由定义Java脚本引擎的接口和类组成,提供在Java应用程序中的使用脚本的框架。

javax.script包的功能主要包括

脚本执行:脚本是用作脚本引擎执行的程序源的字符流。 使用ScriptEngine的eval方法和Invocable接口的方法执行脚本。

绑定:允许Java对象作为命名变量绑定给脚本程序。 见:Bindings和ScriptContext类。

编译:允许重复存储和执行脚本引擎前端生成的中间代码。 这有利于多次执行相同脚本的应用程序以提高效率,因为引擎的前端只需要每个脚本执行一次,而不是每次执行脚本一次。 请注意,此功能是可选的,脚本引擎可能会选择不实现它。需要使用instanceof来检查Compilable接口的可用性。

调用:允许重用脚本引擎前端生成的中间代码。 编译允许重新执行由中间代码表示的整个脚本,而调用功能允许重新执行脚本中的各个过程/方法。 与编译的情况一样,并非所有脚本引擎都需要提供此功能。须检查Invocable的可用性。

脚本引擎发现: 引擎发现机制基于ServiceLoader类中描述的服务提供者加载工具。 ScriptEngineManager包括getEngineFactories方法,以获取所有ScriptEngineFactory实例。 ScriptEngineFactory具有查询脚本引擎属性的方法。

使用Graal js引擎执行js代码

    org.graalvm.js

    js

    ${graal.version}

    org.graalvm.js

    js-scriptengine

    ${graal.version}

import javax.script.ScriptEngine;

import javax.script.ScriptEngineManager;

import javax.script.ScriptException;

public class JsEngineHelloWorld {

    public static void main(String[] args) throws ScriptException {

        ScriptEngine engine = new ScriptEngineManager().getEngineByName("graal.js");

        engine.eval("print('Hello World!');");

    }

}

JS和Java对象交互:

ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");

Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);

bindings.put("polyglot.js.allowHostAccess", true);

bindings.put("polyglot.js.allowHostClassLookup", (Predicate) s -> true);

bindings.put("javaObj", new Object());

engine.eval("(javaObj instanceof Java.type('java.lang.Object'));"); // it will not work without allowHostAccess and allowHostClassLookup

平台JS脚本能力建设

当平台需要面对复杂、多变的业务时,基于成熟的领域模型和脚本能力能提供灵活的扩展性,可以考虑从以下层面建立平台脚本能力:

GraalJS及平台JS脚本能力建设_第1张图片

执行引擎层:Graal JS、 Nashorn

平台JS引擎:基于底层引擎平台封装。

  1. 引擎启动和关闭管理。
  2. 多线程(并发): 如使用线程池并发执行脚本。
  3. 监控及运营环境管理:如资源管控和限制。
  4. 基础能力注入(提供JS API): 提供机制插入基础能力至JS环境

创建Java对象代理并注入

JS服务层

  1. 基础JS能力: 基于平台产品能力提供JS能力。基于JS引擎的对象绑定功能,提供公共及Java开发的JS对象能力。
  2. 统一的JS执行API: 如统一的API接口
  3. 应用层JS脚本管理。
  4. 基础能力注入(提供JS API): 提供机制插入基础能力至JS环境。

//加载静态资源

Resource[] otherResources =

 (new PathMatchingResourcePatternResolver()).getResources("classpath*:*.js");

List jsResources = (List)Arrays.stream(otherResources).map((x) -> {

    try {

        return IOUtils.toString(x.getInputStream(), StandardCharsets.UTF_8);

    } catch (IOException var2) {

        throw new IllegalArgumentException(x.getFilename() + "load failed ");

    }

}).collect(Collectors.toList());

String staticSource = String.join("\n", jsResources);

//初始化静态脚本

context.eval(staticSource);

//提供特定接口用于提供增加能力对象(pluginClass)

Enhancer enhancer = new Enhancer();

enhancer.setSuperclass(pluginClass);

enhancer.setCallback(interceptor);

T insertObject = enhancer.create();

private static final TypeLiteral> STRING_MAP = new TypeLiteral>() {};

map = (Map)this.context.eval(Source.newBuilder("js", "this", "internal-script").internal(internal).buildLiteral()).as(STRING_MAP);

//特定标识插入JS引用对象

map.put("XXXX", insertObject)

应用JS

  1. 应用JS脚本开发

应用场景

基于业务模型数据经常需要开发特定数据发分析, 对于大数据场景可以使用大数据技术来进行数据挖掘和分析, 对于短周期或小批量的数据,基于灵活多变规则的实时分析可以考虑使用JS脚本来解决规则多变的问题

你可能感兴趣的:(javascript,开发语言,java,Graal,脚本)