关于Java Scripting API您不知道的5件事,Java平台上更简朴的剧本编写要领
当前位置:以往代写 > JAVA 教程 >关于Java Scripting API您不知道的5件事,Java平台上更简朴的剧本编写要领
2019-06-14

关于Java Scripting API您不知道的5件事,Java平台上更简朴的剧本编写要领

关于Java Scripting API您不知道的5件事,Java平台上更简朴的剧本编写要领

副标题#e#

此刻,很多Java开拓人员都喜欢在Java平台中利用剧本语言,可是利用编译到 Java 字节码中的动态语言有时是不行行的。在某些环境中,直接编写一个 Java 应用措施的剧本 部门 可能在一个剧本中挪用特定的 Java 工具是更快捷、更高效的要领。

这就是 javax.script 发生的原因了。Java Scripting API 是从 Java 6 开始引入的,它填补了便捷的小剧本语言和结实的 Java 生态系统之间的鸿沟。通过利用 Java Scripting API,您就可以在您的 Java 代码中快速整合险些所有的剧本语言,这使您可以或许在办理一些很小的问题时有更多可选择的要领。

1. 利用 jrunscript 执行 JavaScript

每一个新的 Java 平台宣布城市带来新的呼吁行东西集,它们位于 JDK 的 bin 目次。Java 6 也一样,个中 jrunscript 即是 Java 平台东西会合的一个不小的增补。

设想一个编写呼吁行剧本举办机能监控的简朴问题。这个东西将借用 jmap,每 5 秒钟运行一个 Java 历程,从而相识历程的运行状况。一般环境下,我们会利用呼吁行 shell 脚原来完成这样的事情,可是这里的处事器应用措施陈设在一些不同很大的平台上,包罗 Windows® 和 Linux®。系统打点员将会发明编写可以或许同时运行在两个平台的 shell 剧本是很疾苦的。凡是的做法是编写一个 Windows 批处理惩罚文件和一个 UNIX® shell 剧本,同时担保这两个文件同步更新。

可是,任何阅读过 The Pragmatic Programmer 的人都知道,这严重违反了 DRY (Don’t Repeat Yourself) 原则,并且会发生很多缺陷和问题。我们真正但愿的是编写一种与操纵系统无关的剧本,它可以或许在所有的平台上运行。

虽然,Java 语言是平台无关的,可是这里并不是需要利用 “系统” 语言的环境。我们需要的是一种剧本语言 — 如,JavaScript。

清单 1 显示的是我们所需要的简朴 shell 剧本:

清单 1. periodic.js

while (true)
{
   echo("Hello, world!");
}

由于常常与 Web 欣赏器打交道,很多 Java 开拓人员已经知道了 JavaScript(或 ECMAScript;JavaScript 是由 Netscape 开拓的一种 ECMAScript 语言)。问题是,系统打点员要如何运行这个剧本?

虽然,办理要领是 JDK 所带的 jrunscript 实用措施,如清单 2 所示:

清单 2. jrunscript

C:\developerWorks\5things-scripting\code\jssrc>jrunscript periodic.js
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
...

留意,您也可以利用 for 轮回凭据指定的次数来轮回执行这个剧本,然后才退出。根基上,jrunscript 可以或许让您执行 JavaScript 的所有操纵。惟一差异的是它的运行情况不是欣赏器,所以运行中不会有 DOM。因此,最顶层的函数和工具稍微有些差异。

因为 Java 6 将 Rhino ECMAScript 引擎作为 JDK 的一部门,jrunscript 可以执行任何通报给它的 ECMAScript 代码,不管是一个文件(如此地方示)或是在越发交互式的 REPL(“Read-Evaluate-Print-Loop”)shell 情况。运行 jrunscript 就可以会见 REPL shell。

2. 从剧本会见 Java 工具

可以或许编写 JavaScript/ECMAScript 代码长短常好的,可是我们不但愿被迫从头编译我们在 Java 语言中利用的所有代码 — 这是违背我们初志的。幸好,所有利用 Java Scripting API 引擎的代码都完全可以或许会见整个 Java 生态系统,因为本质上一切代码都照旧 Java 字节码。所以,回到我们之前的问题,我们可以在 Java 平台上利用传统的 Runtime.exec() 挪用来启动历程,如清单 3 所示:

清单 3. Runtime.exec() 启动 jmap

var p = java.lang.Runtime.getRuntime().exec("jmap", [ "-histo", arguments[0] ])
p.waitFor()

数组 arguments 是指向通报到这个函数参数的 ECMAScript 尺度内置引用。在最顶层的剧本情况中,则是通报给剧本自己的的参数数组(呼吁行参数)。所以,在清单 3 中,这个剧本预期吸收一个参数,该参数包括要映射的 Java 历程的 VMID。

除此之外,我们可以操作自己为一个 Java 类的 jmap,然后直接挪用它的 main() 要领,如清单 4 所示。有了这个要领,我们不需要 “传输” Process 工具的 in/out/err 流。

清单 4. JMap.main()

var args = [ "-histo", arguments[0] ]
Packages.sun.tools.jmap.JMap.main(args)

Packages 语法是一个 Rhino ECMAScript 标识,它指向已经 Rhino 内建设的位于焦点 java.* 包之外的 Java 包。


#p#副标题#e#

3. 从 Java 代码挪用剧本

从剧本挪用 Java 工具仅仅完成了一半的事情:Java 剧本情况也提供了从 Java 代码挪用剧本的成果。这只需要实例化一个 ScriptEngine 工具,然后加载和评估剧本,如清单 5 所示:

清单 5. Java 平台的剧本挪用

#p#分页标题#e#

import java.io.*;
import javax.script.*;

public class App
{
   public static void main(String[] args)
   {
     try
     {
       ScriptEngine engine =
         new ScriptEngineManager().getEngineByName("javascript");
       for (String arg : args)
       {
         FileReader fr = new FileReader(arg);
         engine.eval(fr);
       }
     }
     catch(IOException ioEx)
     {
       ioEx.printStackTrace();
     }
     catch(ScriptException scrEx)
     {
       scrEx.printStackTrace();
     }
   }
}

eval() 要领也可以直接操纵一个 String,所以这个剧本不必然必需是文件系统的一个文件 — 它可以来自于数据库、用户输入,可能甚至可以基于情况和用户操纵在应用措施中生成。

4. 将 Java 工具绑定到剧本空间

仅仅挪用一个剧本还不足:剧本凡是会与 Java 情况中建设的工具举办交互。这时,Java 主机情况必需建设一些工具并将它们绑定,这样剧本就可以很容易找到和利用这些工具。这个进程是 ScriptContext 工具的任务,如清单 6 所示:

清单 6. 为剧本绑定工具

import java.io.*;
import javax.script.*;

public class App
{
   public static void main(String[] args)
   {
     try
     {
       ScriptEngine engine =
         new ScriptEngineManager().getEngineByName("javascript");

       for (String arg : args)
       {
         Bindings bindings = new SimpleBindings();
         bindings.put("author", new Person("Ted", "Neward", 39));
         bindings.put("title", "5 Things You Didn't Know");

         FileReader fr = new FileReader(arg);
         engine.eval(fr, bindings);
       }
     }
     catch(IOException ioEx)
     {
       ioEx.printStackTrace();
     }
     catch(ScriptException scrEx)
     {
       scrEx.printStackTrace();
     }
   }
}

会见所绑定的工具很简朴 — 所绑定工具的名称是作为全局定名空间引入到剧本的,所以在 Rhino 中利用 Person 很简朴,如清单 7 所示:

清单 7. 是谁撰写了本文?

println("Hello from inside scripting!")

println("author.firstName = " + author.firstName)

您可以看到,JavaBeans 样式的属性被简化为利用名称直接会见,这就仿佛它们是字段一样。

#p#副标题#e#

5. 编译频繁利用的剧本

剧本语言的缺点一直存在于机能方面。个中的原因是,大大都环境下剧本语言是 “即时” 解译的,因而它在执行时会损失一些理会和验证文本的时间和 CPU 周期。运行在 JVM 的很多剧本语言最终会将吸收的代码转换为 Java 字节码,至少在剧本被第一次理会和验证时举办转换;在 Java 措施封锁时,这些即时编译的代码会消失。将频繁利用的剧本保持为字节码形式可以辅佐晋升可观的机能。

我们可以以一种很自然和有意义的要领利用 Java Scripting API。假如返回的 ScriptEngine 实现了 Compilable 接口,那么这个接口所编译的要领可用于将剧本(以一个 String 或一个 Reader 通报过来的)编译为一个 CompiledScript 实例,然后它可用于在 eval() 要领中利用差异的绑定反复地处理惩罚编译后的代码,如清单 8 所示:

清单 8. 编译解译后的代码

import java.io.*;
import javax.script.*;

public class App
{
   public static void main(String[] args)
   {
     try
     {
       ScriptEngine engine =
         new ScriptEngineManager().getEngineByName("javascript");

       for (String arg : args)
       {
         Bindings bindings = new SimpleBindings();
         bindings.put("author", new Person("Ted", "Neward", 39));
         bindings.put("title", "5 Things You Didn't Know");

         FileReader fr = new FileReader(arg);
         if (engine instanceof Compilable)
         {
           System.out.println("Compiling....");
           Compilable compEngine = (Compilable)engine;
           CompiledScript cs = compEngine.compile(fr);
           cs.eval(bindings);
         }
         else 
           engine.eval(fr, bindings);
       }
     }
     catch(IOException ioEx)
     {
       ioEx.printStackTrace();
     }
     catch(ScriptException scrEx)
     {
       scrEx.printStackTrace();
     }
   }
}

#p#分页标题#e#

在大大都环境中,CompiledScript 实例需要存储在一个长时间存储中(譬喻,servlet-context),这样才气制止一次次地反复编译沟通的剧本。然而,假如剧本产生变革,您就需要建设一个新的 CompiledScript 来反应这个变革;一旦编译完成,CompiledScript 就不再执行原始的剧本文件内容。

竣事语

Java Scripting API 在扩展 Java 措施的范畴和成果方眼前进了很大一步,而且它将剧本语言的编码效率的优势带到 Java 情况。jrunscript — 它显然不是很难编写的措施 — 以及 javax.script 给 Java 开拓人员带来了诸如 Ruby (JRuby) 和 ECMAScript (Rhino) 等剧本语言的优势,同时还不会粉碎 Java 情况的生态系统和可扩展性。

    关键字:

在线提交作业