文档章节

Java 脚本引擎入门

阿提说说
 阿提说说
发布于 2019/12/08 00:33
字数 1146
阅读 19
收藏 0

Java Script Engine

Java 脚本引擎可以将脚本嵌入Java代码中,可以自定义和扩展Java应用程序,自JDK1.6被引入,基于Rhino引擎,JDK1.8后使用Nashorn引擎,支持ECMAScript 5,但后期还可能会换。

脚本引擎包位于javax.script中,各个类名及描述如下

接口

  • Bindings

    键值对映射,所有key都为String

  • Compilable

    由具体的脚本引擎实现,用于将脚本进行编译,可重复使用。

  • Invocable 由具体的脚本引擎实现,其允许调用先前已执行的脚本

  • ScriptContext

    脚本引擎上下文,用于将应用程序与脚本引擎进行绑定

  • ScriptEngine

    由具体的脚本引擎实现,定义了执行脚本的方法、键值对映射关系、脚本引擎上下文

  • ScriptEngineFactory

    脚本引擎工厂,每一个ScriptEngine都有一个对应的工厂。ScriptEngineManager会从ClassLoader中获取所有的ScriptEngineFactories实例

  • AbstractScriptEngine

    ScriptEngine的抽象实现类,提供了ScriptEngine的标准实现

  • CompiledScript

    由存储编译结果的类扩展。可以以Java类、Java类文件或者脚本操作码的形式存储,可以重复执行无需重新解析。每个CompiledScript都与一个ScriptEngine相关联,调用CompiledScript的eval方法会导致ScriptEngine执行

  • ScriptEngineManager

    脚本引擎管理器,提供ScriptEngine的实例化机制,并维护了一些键/值对集合,供所有创建的ScriptEngine共享使用

  • SimpleBindings

    使用HashMap 或者其他Map实现的一种简单键值映射

  • SimpleScriptContext

    ScriptContext 的一种简单实现

异常

  • ScriptException

    脚本API的通用异常类,抛出的异常类具有文件名、行号、列号信息

示例

简单的

@Test
public void scriptTest() throws ScriptException {
    ScriptEngineManager engineManager = new ScriptEngineManager();
    //获取JavaScript解析引擎
    ScriptEngine engine = engineManager.getEngineByName("JavaScript");
    //将x变量映射为Hello World!
    engine.put("x", "Hello World!");
    engine.eval("print(x)");
}
//输出
//Hello World!

较复杂的

从文件中读取脚本

/**
     * 从文件中读取Js脚本
     * test.js 中的内容:
     * var obj = new Object();
     * obj.hello = function (name) {
     *     print('Hello, ' + name);
     * }
     * @throws Exception
     */
@Test
public void file() throws Exception{
    ScriptEngineManager manager = new ScriptEngineManager();
    ScriptEngine engine = manager.getEngineByName("JavaScript");
    engine.eval(new FileReader(new File("script/test.js")));
    Invocable inv = (Invocable) engine;
    Object obj = engine.get("obj");
    inv.invokeMethod(obj, "hello", "Script Test!" );
}

将Java变量注入脚本中

有可能需要在脚本中使用Java变量

@Test
public void scriptVar() throws Exception{
    ScriptEngineManager manager = new ScriptEngineManager();
    ScriptEngine engine = manager.getEngineByName("JavaScript");
    File file = new File("F:/test/test.txt");
    //将File对象f直接注入到js脚本中并可以作为全局变量使用
    engine.put("files", file);
    engine.eval("print(files.getPath());print(files.getName());");
}

调用脚本中的方法

使用Invocable 调用已经加载脚本中的方法

@Test
public void scriptTest1() throws ScriptException, NoSuchMethodException {
    ScriptEngineManager engineManager = new ScriptEngineManager();
    ScriptEngine engine = engineManager.getEngineByName("JavaScript");

    StringBuilder sb = new StringBuilder();
    sb.append("var obj = new Object();");
    sb.append("obj.hello = function(name){print('Hello, ' + name);}");
    engine.eval(sb.toString());

    //Invocable 可以调用已经加载过的脚本
    Invocable invocable = (Invocable) engine;
    //获取脚本的obj对象
    Object object = engine.get("obj");
    //调用obj对象的hello函数
    invocable.invokeMethod(object, "hello", "Script Method!");
}
//输出
//Hello, Script Method!

多个作用域

一个脚本引擎,多个scope,x变量并没有覆盖之前的变量

@Test
public void scriptTest() throws ScriptException {
    ScriptEngineManager engineManager = new ScriptEngineManager();
    ScriptEngine engine = engineManager.getEngineByName("JavaScript");
    engine.put("x", "Hello World!");
    engine.eval("print(x)");


    ScriptContext context = new SimpleScriptContext();
    //新的Script context绑定ScriptContext的ENGINE_SCOPE
    Bindings bindings = context.getBindings(ScriptContext.ENGINE_SCOPE);

    // 增加一个新变量到新的范围 engineScope 中
    bindings.put("x", "word hello!!");
    // 执行同一个脚本 - 但这次传入一个不同的script context
    engine.eval("print(x);", bindings);
    engine.eval("print(x);");
}

//输出
//Hello World!
//word hello!!
//Hello World!

使用脚本实现Java接口

@Test
public void runnableImpl() throws Exception{
    ScriptEngineManager manager = new ScriptEngineManager();
    ScriptEngine engine = manager.getEngineByName("JavaScript");

    // String里定义一段JavaScript代码脚本
    String script = "function run() { print('run called'); }";
    // 执行这个脚本
    engine.eval(script);

    // 从脚本引擎中获取Runnable接口对象(实例). 该接口方法由具有相匹配名称的脚本函数实现。
    Invocable inv = (Invocable) engine;
    // 在上面的脚本中,我们已经实现了Runnable接口的run()方法
    Runnable runnable = inv.getInterface(Runnable.class);

    // 启动一个线程运行上面的实现了runnable接口的script脚本
    Thread thread = new Thread(runnable);
    thread.start();
    Thread.sleep(1000);
}

如果脚本是基于对象的,则可以通过执行脚本的方法来实现Java接口,避免调用脚本的全局函数。

@Test
public void runnableObject() throws ScriptException {
    ScriptEngineManager manager = new ScriptEngineManager();
    ScriptEngine engine = manager.getEngineByName("JavaScript");

    String script = "var obj = new Object();obj.run = function() {println('run method called')}";
    engine.eval(script);

    //获得脚本对象
    Object object = engine.get("obj");
    Invocable invocable = (Invocable) engine;
    Runnable runnable = invocable.getInterface(object, Runnable.class);

    Thread thread = new Thread(runnable);
    thread.start();
    Thread.sleep(1000);
}

© 著作权归作者所有

阿提说说

阿提说说

粉丝 3
博文 36
码字总数 36121
作品 0
杭州
高级程序员
私信 提问
Java_脚本引擎_01_用法入门

一、前言 最近有个需求,需要在js中调用java,这样能避免更新java,从而实现代码的热更新。 于是想到用 Nashorn JavaScript 引擎。 二、概述 通过 JDK 8 的 Nashorn JavaScript 引擎 ,可以很...

shirayner
2018/08/01
0
0
在服务器端运行JavaScript文件(一)

简介: 把JavaScript脚本与服务器上Java代码相结合,从而获得在服务器端和客户端都能够自由使用的JavaScript脚本。另外,经过这一系列的被展现技术,无论是基于Ajax还是非Ajax的客户端,都将...

长平狐
2012/10/16
1K
0
【Java动态性】之动态执行JavaScript代码

一、简介 1. Java脚本引擎是从JDK6.0之后添加端新功能; 2. 脚本引擎介绍:1)使得Java应用程序可以通过一套固定端接口与各种脚本引擎交互,从而达到在Java平台调用各种脚本语言的目的;2)J...

谢余峰
2018/07/28
268
0
3D引擎--可移植到Android的开源的引擎

随着android在全球的风靡,越来越多的人将自己的目光投向搭载android的移动设备,但由于手持设备的局限性,怎样利用有限的资源来达到很好的体验,是设备厂商必须要考虑的问题,其中炫目的界面...

长平狐
2012/08/29
1.2W
6
Apache Flink 源码解析(一)入口,bash脚本

概述 因为自己在阅读源码的过程中曾经遇到过很多问题,现在稍微有一点点的经验希望分享给很多从零开始的人。Apache的项目代码量很大,很难做到彻底通读,我也是一步一步的先从整体的架构来分...

铛铛铛clark
2017/12/13
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Kettle自定义jar包供javascript使用

我们都知道 Kettle 是用 Java 语言开发,并且可以在 JavaScript 里面直接调用 java 类方法。所以有些时候,我们可以自定义一些方法,来供 JavaScript 使用。 本篇文章有参考自:https://www...

CREATE_17
昨天
82
0
处理CSV文件中的逗号

我正在寻找有关如何处理正在创建的csv文件的建议,然后由我们的客户上传,并且该值可能带有逗号(例如公司名称)。 我们正在研究的一些想法是:带引号的标识符(值“,”值“,”等)或使用|...

javail
昨天
79
0
如何克隆一个Date对象?

将Date变量分配给另一个变量会将引用复制到同一实例。 这意味着更改一个将更改另一个。 如何实际克隆或复制Date实例? #1楼 简化版: Date.prototype.clone = function () { return new ...

技术盛宴
昨天
73
0
计算一个数的数位之和

计算一个数的数位之和 例如:128 :1+2+8 = 11 public int numSum(int num) { int sum = 0; do { sum += num % 10; } while ((num = num / 10) > 0); return sum;......

SongAlone
昨天
124
0
为什么图片反复压缩后普遍会变绿,而不是其他颜色?

作者:Lion Yang 链接:https://www.zhihu.com/question/29355920/answer/119088684 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 业余版概要:安卓的...

shzwork
昨天
71
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部