http://docs.oracle.com/javase/8/docs/api/javax/script/package-summary.html
http://openjdk.java.net/projects/nashorn/
虽然 Nashorn 是 Java Scripting API 默认使用的 ECMAScript 引擎,但你也可以使用其他兼容 JSR 223 的脚本引擎,或者你可以实现自己的引擎。该文档不涉及脚本引擎的实现方法,但最最基础的级别,你必须实现 javax.script.ScriptEngine 和 javax.script.ScriptEngineFactory 接口。抽象类 javax.script.AbstractScriptEngine 提供了很多默认 ScriptEngine 接口的方法实现。
ScriptEngineManager
对象. ScriptEngine
对象 下面我们提供了几个例子来展示如何使用 Java Scripting API。为了让例子尽可能的简单,我们没有对执行过程中的异常进行处理。Java Scripting API 的异常有受检查异常和运行时异常两种,这些异常必须进行正确处理。在每个例子中,ScriptEngineManager 类的实例是通过 Nashorn 引擎的 getEngineByName() 方法来获取的。如果指定名称的引擎不存在,该方法会返回 null 。更多关于 Nashorn 引擎的信息请看 Nashorn User’s Guide .
ScriptEngine
对象都有它独有的变量作用域。要使用多个变量作用域请看 Example 8
.
在这个例子中,调用脚本引擎实例的 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"); // evaluate JavaScript code engine.eval("print('Hello, World')"); } }
在这个例子中, 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"); // evaluate JavaScript code engine.eval(new java.io.FileReader("script.js")); } }
在这个例子中,我们创建了一个 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"); // create File object File f = new File("test.txt"); // expose File object as a global variable to the engine engine.put("file", f); // evaluate JavaScript code and access the variable engine.eval("print(file.getAbsolutePath())"); } }
本例中在 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"); // evaluate JavaScript code that defines a function with one parameter engine.eval("function hello(name) { print('Hello, ' + name) }"); // create an Invocable object by casting the script engine object Invocable inv = (Invocable) engine; // invoke the function named "hello" with "Scripting!" as the argument inv.invokeFunction("hello", "Scripting!"); } }
本例中在 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"); // evaluate JavaScript code that defines an object with one method engine.eval("var obj = new Object()"); engine.eval("obj.hello = function(name) { print('Hello, ' + name) }"); // expose object defined in the script to the Java application Object obj = engine.get("obj"); // create an Invocable object by casting the script engine object Invocable inv = (Invocable) engine; // invoke the method named "hello" on the object defined in the script // with "Script Method!" as the argument inv.invokeMethod(obj, "hello", "Script Method!"); } }
本例中在 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"); // evaluate JavaScript code that defines a function with one parameter engine.eval("function run() { print('run() function called') }"); // create an Invocable object by casting the script engine object Invocable inv = (Invocable) engine; // get Runnable interface object Runnable r = inv.getInterface(Runnable.class); // start a new thread that runs the script Thread th = new Thread(r); th.start(); th.join(); } }
本例中在 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"); // evaluate JavaScript code that defines a function with one parameter engine.eval("var obj = new Object()") engine.eval("obj.run = function() { print('obj.run() method called') }"); // expose object defined in the script to the Java application Object obj = engine.get("obj"); // create an Invocable object by casting the script engine object Invocable inv = (Invocable) engine; // get Runnable interface object Runnable r = inv.getInterface(obj, Runnable.class); // start a new thread that runs the script Thread th = new Thread(r); th.start(); th.join(); } }
本例中脚本引擎的 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"); // set global variable engine.put("x","hello"); // evaluate JavaScript code that prints the variable (x = "hello") engine.eval("print(x)"); // define a different script context ScriptContext newContext = new SimpleScriptContext(); newContext.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE); Bindings engineScope = newContext.getBindings(ScriptContext.ENGINE_SCOPE); // set the variable to a different value in another scope engineScope.put("x", "world"); // evaluate the same code but in a different script context (x = "world") engine.eval("print(x)", newContext);