尚学堂 老师好!

上海:15201841284

广州:020-2989 6995

深圳:0755-23061965

武汉:027-8798 9193

Java Scripting API 使用示例

本章节我们讲述如何使用 Java Scripting API (JSR 223) 在 Java 应用中嵌入脚本功能,同时提供了一些 Java 的例子来演示 Java Scripting API 的特性。

更多精彩内容以及学习资料,尚学堂论坛bbs.bjsxt.com免费下载。

Java Scripting API 包含一组类和接口,在 javax.script 包中定义。这是一个相对比较小的 Java 包,以 ScriptEngineManager 类作为起点。一个 ScriptEngineManager 对象可以通过 JAR 文件服务发现机制来查找脚本引擎,而实例化 ScriptEngine 对象的解析脚本使用专门的脚本语言编写。更多关于 javax.script 包的详细信息请看 Java SE 规范

https://docs.oracle.com/javase/8/docs/api/javax/script/package-summary.html

Nashorn 引擎是 Java SE 开发工具包(JDK)自带的默认 ECMAScript (JavaScript)引擎。Nashorn 引擎是 Oracle 使用纯 Java 开发的,是 OpenJDK 项目的一部分。你可以在下面地址中找到关于 Nashorn 引擎更详细的信息:

https://openjdk.java.net/projects/nashorn/

虽然 Nashorn 是 Java Scripting API 默认使用的 ECMAScript 引擎,但你也可以使用其他兼容 JSR 223 的脚本引擎,或者你可以实现自己的引擎。该文档不涉及脚本引擎的实现方法,但最最基础的级别,你必须实现 javax.script.ScriptEngine 和 javax.script.ScriptEngineFactory 接口。抽象类 javax.script.AbstractScriptEngine 提供了很多默认 ScriptEngine 接口的方法实现。

使用 Java Scripting API 的步骤:

  1. 创建一个 ScriptEngineManager 对象.

  2. 从管理器对象中获取 ScriptEngine 对象

  3. 使用脚本引擎的 eval() 方法来执行脚本

下面我们提供了几个例子来展示如何使用 Java Scripting API。为了让例子尽可能的简单,我们没有对执行过程中的异常进行处理。Java Scripting API 的异常有受检查异常和运行时异常两种,这些异常必须进行正确处理。在每个例子中,ScriptEngineManager 类的实例是通过 Nashorn 引擎的 getEngineByName() 方法来获取的。如果指定名称的引擎不存在,该方法会返回 null 。更多关于 Nashorn 引擎的信息请看 Nashorn User's Guide.

注意:

每个 ScriptEngine 对象都有它独有的变量作用域。要使用多个变量作用域请看  Example 8.

示例 1 —— 执行脚本语句

在这个例子中,调用脚本引擎实例的 eval() 方法来执行以字符串标识的 JavaScript 代码。

 import javax.script.*;  public class EvalScript {     public static void main(String[] args) throws Exception {         ScriptEngineManager manager = new ScriptEngineManager();         ScriptEngine engine = manager.getEngineByName("nashorn");                   engine.eval("print('Hello, World')");     } }

示例 2 —— 执行脚本文件

在这个例子中, eval() 方法传递了一个 FileReader 对象作为参数,从 scripts.js 文件中读取 JavaScript 代码。通过封装不同的输入流对象作为 reader 来实现从文件、URL 或者其他资源中执行脚本。

 import javax.script.*;  public class EvalFile {     public static void main(String[] args) throws Exception {         ScriptEngineManager manager = new ScriptEngineManager();         ScriptEngine engine = manager.getEngineByName("nashorn");                   engine.eval(new java.io.FileReader("script.js"));     } }

示例 3 —— 输出 Java 对象作为全局变量

在这个例子中,我们创建了一个 File 对象并通过 put() 方法暴露给引擎作为一个名为 file 的全局变量。然后在 JavaScript 代码中调用 eval() 方法就可以访问该变量并调用 getAbsolutePath() 方法

注意:

作为变量的 Java 对象的字段访问和方法调用语法取决于脚本语言。该例子使用 JavaScript 语法,和 Java 的类似。

 import javax.script.*; import java.io.*;  public class ScriptVars {     public static void main(String[] args) throws Exception {         ScriptEngineManager manager = new ScriptEngineManager();         ScriptEngine engine = manager.getEngineByName("nashorn");                   File f = new File("test.txt");                   engine.put("file", f);                   engine.eval("print(file.getAbsolutePath())");     } }

示例 4 —— 调用脚本函数

本例中在 JavaScript 代码中调用 eval() 方法,定义了一个包含单个参数的函数。然后创建 Invocable 对象,并使用其方法 invokeFunction() 来调用这个函数。

注意:

并非所有的脚本引擎都实现了 Invocable 接口。本例中使用 Nashorn 引擎,可以在脚本中调用之前引擎已经定义的函数。

 import javax.script.*;  public class InvokeScriptFunction {     public static void main(String[] args) throws Exception {         ScriptEngineManager manager = new ScriptEngineManager();         ScriptEngine engine = manager.getEngineByName("nashorn");                   engine.eval("function hello(name) { print('Hello, ' + name) }");                   Invocable inv = (Invocable) engine;                   inv.invokeFunction("hello", "Scripting!");     } }

示例 5 —— 调用脚本对象的方法

本例中在 JavaScript 代码中调用 eval() 方法定义包含一个方法的对象。该对象在脚本中通过脚本引擎的 get() 方法暴露给 Java 应用,然后创建一个 Invocable 对象,并通过 invokeMethod() 方法调用对象的方法。

注意:

并非素有的脚本引擎都实现了 Invocable 接口。本例中使用 Nashorn 引擎,可以调用引擎之前已经定义的脚本方法。

 import javax.script.*;  public class InvokeScriptMethod {     public static void main(String[] args) throws Exception {         ScriptEngineManager manager = new ScriptEngineManager();         ScriptEngine engine = manager.getEngineByName("nashorn");                   engine.eval("var obj = new Object()");         engine.eval("obj.hello = function(name) { print('Hello, ' + name) }");                   Object obj = engine.get("obj");                   Invocable inv = (Invocable) engine;                            inv.invokeMethod(obj, "hello", "Script Method!");     } }

示例 6 —— 实现一个包含脚本函数的 Java 接口

本例中在 JavaScript 代码中调用 eval() 方法来定义一个函数。然后创建一个 Invocable 对象,并通过其 getInterface() 方法来创建一个 Runnable 接口对象。接口的方法在脚本函数中实现,这是通过函数名称匹配的方式实现的(本例中 run() 函数用来实现接口对象的 run() 方法)。最后,启动一个新的线程来运行脚本函数。

 import javax.script.*;  public class ImplementRunnable {     public static void main(String[] args) throws Exception {         ScriptEngineManager manager = new ScriptEngineManager();         ScriptEngine engine = manager.getEngineByName("nashorn");                   engine.eval("function run() { print('run() function called') }");                   Invocable inv = (Invocable) engine;                   Runnable r = inv.getInterface(Runnable.class);                   Thread th = new Thread(r);         th.start();         th.join();     } }

示例 7 —— 在脚本对象方法中实现 Java 接口

本例中在 JavaScript 代码中调用 eval() 方法来定义一个包含单个方法的对象。该对象在脚本中通过 get() 方法暴露给 Java 应用。然后创建一个 Invocable 对象并通过其 getInterface() 方法来创建一个 Runnable 接口对象。该接口的方法实现是在脚本对象中相同匹配名称的函数中(本例中对象的 run 方法对应接口的 run 方法的实现)。最后启动一个新线程来运行脚本对象的方法。

 import javax.script.*;  public class ImplementRunnableObject {     public static void main(String[] args) throws Exception {         ScriptEngineManager manager = new ScriptEngineManager();         ScriptEngine engine = manager.getEngineByName("nashorn");                   engine.eval("var obj = new Object()")         engine.eval("obj.run = function() { print('obj.run() method called') }");                   Object obj = engine.get("obj");                   Invocable inv = (Invocable) engine;                   Runnable r = inv.getInterface(obj, Runnable.class);                   Thread th = new Thread(r);         th.start();         th.join();     } }

示例 8 —— 使用多个变量作用域

本例中脚本引擎的 put() 方法用来设置 x 变量值为 "hello" 字符串对象。紧接着 eval() 方法用来打印默认作用域下的变量值。然后定义一个不同的脚本上下文,并在其作用域下设置相同变量为不同的值(“world” 字符串)。最后在新的脚本上下文中答应该变量,显示为不同的值。

单一的作用域是 javax.script.Bindings 接口的实例。这个接口继承自 java.util.Map<String,Object> 接口。一个作用域相当于是成对的名称和值的列表,其中名称不能为空。javax.script.ScriptContext 接口通过为每个作用域关联一个 Bindings 对象来实现对多个作用域的支持。默认情况下,每个脚本应用有自己独立的上下文。默认的脚本上下文至少有一个作用域,这是通过静态属性 ENGINE_SCOPE 来定义的。脚本上下文可以通过 getScopes() 方法来实现对不同作用域的支持。

 import javax.script.*;  public class MultipleScopes {     public static void main(String[] args) throws Exception {         ScriptEngineManager manager = new ScriptEngineManager();         ScriptEngine engine = manager.getEngineByName("nashorn");                   engine.put("x","hello");                   engine.eval("print(x)");                   ScriptContext newContext = new SimpleScriptContext();         newContext.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE);         Bindings engineScope = newContext.getBindings(ScriptContext.ENGINE_SCOPE);                   engineScope.put("x", "world");                   engine.eval("print(x)", newContext);

更多精彩内容以及学习资料,尚学堂论坛bbs.bjsxt.com免费下载。

  • 北京校区
  • 山西校区
  • 武汉校区
  • 长沙校区
  • 深圳校区
  • 上海校区
  • 广州校区
  • 保定招生办
  • 黑龙江项目办

北京京南校区:北京亦庄经济开发区科创十四街6号院1号楼 赛蒂国际工业园
咨询电话:400-009-1906 / 010-56233821
面授课程: JavaEE+微服务+大数据     大数据+机器学习+平台架构     Python+数据分析+机器学习  人工智能+模式识别+强化学习   WEB前端+移动端+服务端渲染

山西学区地址:山西省晋中市榆次区大学城大学生活广场万科商业A1座702

武汉学区地址:武汉市东湖高新区光谷金融港B22栋11楼
咨询电话:027-87989193

网址:http://www.cssxt.com/
咨询电话:0731-83072091

深圳校区地址:深圳市宝安区航城大道U8智造产业园U6栋3楼
咨询电话:0755-23061965 / 18898413781

上海尚学堂校区地址:上海市浦东新区城丰路650号
咨询电话:021-67690939

广州校区地址:广州市天河区车陂街道大岗路5号中侨广场2栋321室(四号线车陂站D出口,或brt车陂站)
咨询电话:18948349646

保定招生办公室

地址:河北省保定市竞秀区朝阳南大街777号鸿悦国际1101室

电话:15132423123

黑龙江项目办
地点:哈尔滨市松北区博文路青年部落孵化器1层
电话:15321415678
Copyright 2006-2021 北京尚学堂科技有限公司  京ICP备13018289号-19  京公网安备11010802015183  
网站维护:北京尚学堂科技有限公司昌平分公司