AutoCAD 3DMAX C语言 Pro/E UG JAVA编程 PHP编程 Maya动画 Matlab应用 Android
Photoshop Word Excel flash VB编程 VC编程 Coreldraw SolidWorks A Designer Unity3D
 首页 > JAVA编程

动态调用动态语言之Java脚本API

51自学网 2015-09-03 http://www.wanshiok.com

 

  ScriptEngine 接口

  如前所述,代码将使用 ScriptEngine 实例执行脚本。脚本引擎充当脚本代码和最后执行代码的底层语言解释器或编译器之间的中间程序。这样,我们就不需要了解各个解释器使用哪些类来执行脚本。比如说,JRuby 脚本引擎可以将代码传递给 JRuby 的 org.jruby.Ruby 类的一个实例,首先将脚本编译成中间形式,然后再调用它计算脚本并处理返回值。脚本引擎实现隐藏了一些细节,包括解释器如何与 Java 代码共享类定义、应用程序对象和输入/输出流。

  图 1 显示了应用程序、Java 脚本 API 和 ScriptEngine 实现、脚本语言解释器之间的总体关系。我们可以看到,应用程序只依赖于脚本 API,它提供了 ScriptEngineManager 类和 ScriptEngine 接口。ScriptEngine 实现组件处理使用特定脚本语言解释器的细节。

脚本 API 组件图 
图 1:脚本 API 组件关系

  您可能会问:如何才能获取脚本引擎实现和语言解释器所需的 JAR 文件呢?最好的方法是在 java.net 上托管的开源 Scripting 项目中查找脚本引擎实现(请参阅 参考资料)。您可以在 java.net 上找到许多语言的脚本引擎实现和其他网站的链接。Scripting 项目还提供了各种链接,通过这些链接可以下载受支持的脚本语言的解释器。

  在 清单 1 中,main() 方法将 ScriptEngine 传递给各个方法用于计算该方法的 JavaScript 代码。第一个方法如清单 2 所示。invokeHelloScript() 方法调用脚本引擎的 eval 方法计算和执行 JavaScript 代码中的特定字符串。ScriptEngine 接口定义了 6 个重载的 eval() 方法,用于将接收的脚本当作字符串或 java.io.Reader 对象计算,java.io.Reader 对象一般用于从外部源(例如文件)读取脚本。

  清单 2. invokeHelloScript 方法

private static void invokeHelloScript(ScriptEngine jsEngine) throws ScriptException {
jsEngine.eval("println('Hello from JavaScript')");
}

  脚本执行上下文

  HelloScriptingWorld 应用程序中的示例脚本 使用 JavaScript println() 函数向控制台输出结果,但是我们拥有输入和输出流的完全控制权。脚本引擎提供了一个选项用于修改脚本执行的上下文,这意味着我们可以修改标准输入流、标准输出流和标准错误流,同时还可以定义哪些全局变量和 Java 对象对正在执行的脚本可用。

  invokeHelloScript() 方法中的 JavaScript 将 Hello from JavaScript 输出到标准输出流,在本例中为控制台窗口。(清单 6 含有运行 HelloScriptingWorldApplication 时的完整输出。)

  注意,类中的这一方法和其他方法都声明抛出了 javax.script.ScriptException。这个选中的异常(脚本包中定义的惟一一个异常)表示引擎无法解析或执行给定的代码。所有脚本引擎 eval() 方法都声明抛出一个 ScriptException,因此我们的代码需要适当处理这些异常。

  清单 3 显示了两个有关的方法:defineScriptFunction() 和 invokeScriptFunctionFromEngine()。defineScriptFunction() 方法还使用一段硬编码的 JavaScript 代码调用脚本引擎的 eval() 方法。但是有一点需要注意,该方法的所有工作只是定义了一个 JavaScript 函数 sayHello()。并没有执行任何代码。sayHello() 函数只有一个参数,它会使用 println() 语句将这个参数输出到控制台。脚本引擎的 JavaScript 解释器将这个函数添加到全局环境,以供后续的 eval 调用使用(该调用发生在 invokeScriptFunctionFromEngine() 方法中,这并不奇怪)。

  清单 3. defineScriptFunction 和 invokeScriptFunctionFromEngine 方法

private static void defineScriptFunction(ScriptEngine engine) throws ScriptException {
// Define a function in the script engine
engine.eval(
"function sayHello(name) {" +
" println('Hello, ' + name)" +
"}"
);
}

private static void invokeScriptFunctionFromEngine(ScriptEngine engine)
throws ScriptException
{
engine.eval("sayHello('World!')");
}

  这两个方法演示了脚本引擎可以维持应用程序组件的状态,并且能够在后续的 eval() 方法调用过程中使用其状态。invokeScriptFunctionFromEngine() 方法可以利用所维持的状态,方法是调用定义在 eval() 调用中的 sayHello() JavaScript 函数。

  许多脚本引擎在 eval() 调用之间维持全局变量和函数的状态。但是有一点值得格外注意,Java 脚本 API 并不要求脚本引擎提供这一特性。本文中所使用的 JavaScript、Groovy 和 JRuby 脚本引擎确实在 eval() 调用之间维持了这些状态。

  清单 4 中的代码在前一个示例的基础上做了几分修改。原来的 invokeScriptFunctionFromJava() 方法在调用 sayHello() JavaScript 函数时没有使用 ScriptEngine 的 eval() 方法或 JavaScript 代码。与此不同,清单 4 中的方法使用 Java 脚本 API 的 javax.script.Invocable 接口调用由脚本引擎所维持的函数。invokeScriptFunctionFromJava() 方法将脚本引擎对象传递给 Invocable 接口,然后对该接口调用 invokeFunction() 方法,最终使用给定的参数调用 sayHello() JavaScript 函数。如果调用的函数需要返回值,则 invokeFunction() 方法会将值封装为 Java 对象类型并返回。

  清单 4. invokeScriptFunctionFromJava 方法

private static void invokeScriptFunctionFromJava(ScriptEngine engine)
throws ScriptException, NoSuchMethodException
{
Invocable invocableEngine = (Invocable) engine;
invocableEngine.invokeFunction("sayHello", "from Java");
}


  使用代理实现高级脚本调用

  当脚本函数或方法实现了一个 Java 接口时,就可以使用高级 Invocable。Invocable 接口定义了一个 getInterface() 方法,该方法使用接口做为参数并且将返回一个实现该接口的 Java 代码对象。从脚本引擎获得代理对象之后,可以将它作为正常的 Java 对象对待。对该代理调用的方法将委托给脚本引擎通过脚本语言执行。

  注意,清单 4 中没有 JavaScript 代码。Invocable 接口允许 Java 代码调用脚本函数,而无需知道其实现语言。如果脚本引擎无法找到给定名称或参数类型的函数,那么 invokeFunction() 方法将抛出一个 java.lang.NoSuchMethodException。

  Java 脚本 API 并不要求脚本引擎实现 Invocable 接口。实际上,清单 4 中的代码应该使用 instanceof 运算符确保脚本引擎在转换(cast)之前实现了 Invocable 接口。

 
 
说明
:本教程来源互联网或网友上传或出版商,仅为学习研究或媒体推广,wanshiok.com不保证资料的完整性。
 

上一篇:使用Java操作Windows系统注册表  下一篇:Spring集成XFire开发WebService