`

Java SE 6之脚本引擎 让程序如虎添翼

    博客分类:
  • Java
阅读更多
  现在Java SE 5已经发布,在明年Java SE 6也将发布。Java SE 6较Java SE5有了很大的改进,它的功能更强,而且是专为Vista所设计,这就意味着Java SE 6将是Vista上的最佳选择。而Java SE 6所提供的最众多的新功能必将成为它的最大卖点。

  Java SE 6最引人注目的新功能之一就是内嵌了脚本支持。在默认情况下,Java SE 6只支持JavaScript,但这并不以为着Java SE 6只能支持JavaScript。在Java SE 6中提供了一些接口来定义一个脚本规范,也就是JSR223。通过实现这些接口,Java SE 6可以支持任意的脚本语言(如PHP或Ruby)。 

  运行第一个脚本程序

  在使用Java SE 6运行脚本之前,必须要知道你的Java SE 6支持什么脚本语言。在javax.script包中有很多的类,但这些类中最主要的是ScriptEngineManager。可以通过这个类得到当前Java SE 6所支持的所有脚本。如下面例子将列出所有可以使用的脚本引擎工厂。

import javax.script.*;
import java.io.*;
import java.util.*;
import static java.lang.System.*;
public class ListScriptEngines 
{
 public static void main(String args[]) 
 {
  ScriptEngineManager manager = new ScriptEngineManager();
  // 得到所有的脚本引擎工厂
  List factories = manager.getEngineFactories();
  // 这是Java SE 5 和Java SE 6的新For语句语法
  for (ScriptEngineFactory factory: factories) 
  {
   // 打印脚本信息
   out.printf("Name: %s%n" +
    "Version: %s%n" +
    "Language name: %s%n" +
    "Language version: %s%n" +
    "Extensions: %s%n" +
    "Mime types: %s%n" +
    "Names: %s%n",
    factory.getEngineName(),
    factory.getEngineVersion(),
    factory.getLanguageName(),
    factory.getLanguageVersion(),
    factory.getExtensions(),
    factory.getMimeTypes(),
    factory.getNames());
   // 得到当前的脚本引擎
   ScriptEngine engine = factory.getScriptEngine();
  }
 }


  上面的例子必须要在Java SE 6中编译。其中import static java.lang.System.*是新的语法,将System中的所有静态成员进行引用,以后就可以直接使用out、in或err了。

  通过运行java ListScriptEngines,将显示如下信息

Name: Mozilla Rhino
Version: 1.6 release 2
Language name: ECMAScript
Language version: 1.6
Extensions: [js]
Mime types: [application/javascript, application/ecmascript, text/javascript, text/ecmascript]
Names: [js, rhino, JavaScript, javascript, ECMAScript, ecmascript] 

  在最下面一行是脚本的别名,也就是使用它们中的任意一个都可以。得到一个具体的脚本引擎有3种方法。

  ?根据扩展名得到脚本引擎

ScriptEngine engine = manager.getEngineByExtension("js"); 

  getEngineByExtension的参数就是Extensions:[js]中[…]里的部分。

  ?根据Mime类型得到脚本引擎

ScriptEngine engine = manager.getEngineByMimeType("text/javascript"); 

  getEngineByMimeType的参数可以是Mime types: [application/javascript, application/ecmascript, text/javascript, text/ecmascript]中的任何一个,可以将text/javascript改成text/ecmascript。

  ?根据名称得到脚本引擎

ScriptEngine engine = manager.getEngineByName("javascript"); 

  getEngineByName后的参数可以是Names: [js, rhino, JavaScript, javascript, ECMAScript, ecmascript]中的任何一个,如可以将javascript改成ecmascript。

  上面已经讨论了执行脚本的第一步,就是得到一个可用的脚本引擎。在完成这项工作之 后就可以利用这个脚本引擎执行相应的脚本了。我们可以使用ScriptEngine的eval方法来执行脚本。eval方法被重载的多次,但最常用的是public Object eval(String script)。
下面的例子演示了如何使用eval方法来执行javascript脚本。

import javax.script.*;
import java.io.*;
import static java.lang.System.*;
public class FirstJavaScript 
{
 public static void main(String args[]) 
 {
  ScriptEngineManager manager = new ScriptEngineManager();
  // 得到javascript脚本引擎
  ScriptEngine engine = manager.getEngineByName("javascript");
  try 
  {
   // 开始运行脚本,并返回当前的小时
   Double hour = (Double)engine.eval("var date = new Date();" +"date.getHours();");
   String msg;
   // 将小时转换为问候信息
   if (hour < 10) 
   {
    msg = "上午好";
   } 
   else if (hour < 16) 
   {
    msg = "下午好";
   } 
   else if (hour < 20) 
   {
    msg = "晚上好";
   } 
   else 
   {
    msg = "晚安";
   }
   out.printf("小时 %s: %s%n", hour, msg);
  }
  catch (ScriptException e) 
  {
   err.println(e);
  }
 }


  上面的例子通过得到当前的小时,并将其转化为问候语。上面的程序的输出信息为:

  小时9.0:上午好

  这个例子最值得注意的是执行的2句脚本,最后一句是date.getHours()。并未将这个值赋给一个javascript变量。这时,eval方法就将这样的值返回。这有些类似C语言的(…)运算符。如(c=a+b, c + d),这个表达式的返回值是a+b+d。
和脚本语言进行交互

  上面例子只是运行了一个非常简单的脚本。这个脚本是孤立的,并未通过Java向这脚本传递任何的值。虽然从这个脚本返回了一个值,但这种返回方式是隐式的。

  脚本引擎除了这些简单的功能,还为我们提供了更强大的功能。甚至可以通过Java向脚本语言中传递参数,还可以将脚本语言中的变量的值取出来。这些功能要依靠ScriptEngine中的两个方法put和get。

  put 有两个参数,一个是脚本变量名,另一个是变量的值,这个值是Object类型,因此,可以传递任何值。
  get 有一个参数,就是脚本变量的名。

  下面的代码通过javascript脚本将一个字符串翻转(这个字符串是通过java传给javascript的),然后通过java得到这个被翻转后的字符后,然后输出。

import javax.script.*;
import java.io.*;
import static java.lang.System.*;
public class ReverseString
{
 public static void main(String args[]) 
 {
  ScriptEngineManager manager = new ScriptEngineManager();
  // 建立javascript脚本引擎
  ScriptEngine engine = manager.getEngineByName("javascript");
  try 
  {
   // 将变量name和变量值abcdefg传给javascript脚本
   engine.put("name", "abcdefg");
   // 开始执行脚本
   engine.eval("var output = ;" +
    "for (i = 0; i <= name.length; i++) {" +
    " output = name.charAt(i) + output" +
    "}");
   // 得到output变量的值
   String name = (String)engine.get("output");
   out.printf("被翻转后的字符串:%s", name);
  } 
  catch (ScriptException e) 
  {
   err.println(e);
  }
 }


  以上代码的输出结果为:被翻转后的字符串:gfedcba
让脚本运行得更快

  众所周知,解释运行方式是最慢的运行方式。上述的几个例子无一例外地都是以解释方式运行的。由于Java EE 6的脚本引擎可以支持任何实现脚本引擎接口的语言。有很多这样的语言提供了编译功能,也就是说,在运行脚本之前要先将这些脚本进行编译(这里的编译一般将不是生成可执行文件,而只是在内存中编译成更容易运行的方式),然后再执行。如果某段脚本要运行之交多次的话,使用这种方式是非常快的。我们可以使用ScriptEngine的compile方法进行编译。并不是所有脚本引擎都支持编译,只有实现了Compilable接口的脚本引擎才可以使用compile进行编译,否则将抛出一个错误。下面的例子将演示如何使用compile方法编译并运行javascript脚本。

import javax.script.*;
import java.io.*;
import static java.lang.System.*;
public class CompileScript
{
 public static void main(String args[]) 
 {
  ScriptEngineManager manager = new ScriptEngineManager();
  ScriptEngine engine = manager.getEngineByName("javascript");
  engine.put("counter", 0); // 向javascript传递一个参数
  // 判断这个脚本引擎是否支持编译功能
  if (engine instanceof Compilable) 
  {
   Compilable compEngine = (Compilable)engine;
   try 
   {
    // 进行编译
    CompiledScript script = compEngine.compile("function count() { " +
     " counter = counter +1; " +
     " return counter; " +
    "}; count();");
    out.printf("Counter: %s%n", script.eval());
    out.printf("Counter: %s%n", script.eval());
    out.printf("Counter: %s%n", script.eval());
   } 
   catch (ScriptException e) 
   {
    err.println(e);
   }
  } 
  else 
  {
   err.println("这个脚本引擎不支持编译!");
  }
 }


  上面的代码运行后的显示信息如下:

  Counter: 1.0
  Counter: 2.0
  Counter: 3.0

  在这个例子中,先通过compile方法将脚本编译,然后通过eval方法多次进行调用。在这段代码中只有一个函数,因此,eval就返回了这个函数的值。

动态调用脚本语言的方法

  上面的例子只有一个函数,可以通过eval进行调用并将它的值返回。但如果脚本中有多个函数或想通过用户的输入来决定调用哪个函数,这就需要使用invoke方法进行动态调用。和编译一样,脚本引擎必须实现Invocable接口才可以动态调用脚本语言中的方法。下面的例子将演示如何通过动态调用的方式来运行上面的翻转字符串的javascript脚本。

import javax.script.*;
import java.io.*;
import static java.lang.System.*;
public class InvocableTest
{
 public static void main(String args[]) 
 {
  ScriptEngineManager manager = new ScriptEngineManager();
  ScriptEngine engine = manager.getEngineByName("javascript");
  if (engine instanceof Invocable) 
  {
   try 
   {
    engine.eval("function reverse(name) {" +
     " var output = ;" +
     " for (i = 0; i <= name.length; i++) {" +
      " output = name.charAt(i) + output" +
       " } return output;}");
    Invocable invokeEngine = (Invocable)engine;
    Object o = invokeEngine.invoke("reverse", name);
    out.printf("翻转后的字符串:%s", name);
   }
   catch (NoSuchMethodException e) 
   {
    err.println(e);
   } 
   catch (ScriptException e) 
   {
    err.println(e);
   }
  }
  else
  {
   err.println("这个脚本引擎不支持动态调用");
  }



动态实现接口

  脚本引擎还有一个更吸引的功能,那就是动态实现接口。如我们要想让脚本异步地执行,即通过多线程来执行,那InvokeEngine类必须实现Runnable接口才可以通过Thread启动多线程。因此,可以通过getInterface方法来使InvokeEngine动态地实现Runnable接口。这样一般可分为3步进行。

  1. 使用javascript编写一个run函数

engine.eval("function run() {print(异步执行);}"); 

  2. 通过getInterface方法实现Runnable接口

Runnable runner = invokeEngine.getInterface(Runnable.class); 

  3. 使用Thread类启动多线程

Thread t = new Thread(runner);
t.start(); 

  下面是实现这个功能的详细代码。

import javax.script.*;
import static java.lang.System.*;

public class InterfaceTest 
{
 public static void main(String args[]) 
 {
  ScriptEngineManager manager = new ScriptEngineManager();
  ScriptEngine engine = manager.getEngineByName("javascript");
  try 
  {
   engine.eval("function run() {print(异步调用);}");
   Invocable invokeEngine = (Invocable)engine;
   Runnable runner = invokeEngine.getInterface(Runnable.class);
   Thread t = new Thread(runner);
   t.start();
   t.join();
  }
  catch (InterruptedException e) 
  {
   err.println(e);
  }
  catch (ScriptException e) 
  {
   System.err.println(e);
  }
 }


  其实上面的代码是通过javascript实现了Runnable接口的run方法。 
分享到:
评论

相关推荐

    Java 8 Nashorn 脚本引擎

    Java 8 Nashorn脚本引擎是Java平台上的一个强大工具,它允许开发者在Java应用程序中直接执行JavaScript代码。Nashorn引擎是Oracle公司为Java 8引入的一个重要特性,其目的是提升Java与JavaScript之间的互操作性,...

    基于java的开发源码-SnakeScript Java游戏脚本引擎 v1.1.zip

    基于java的开发源码-SnakeScript Java游戏脚本引擎 v1.1.zip 基于java的开发源码-SnakeScript Java游戏脚本引擎 v1.1.zip 基于java的开发源码-SnakeScript Java游戏脚本引擎 v1.1.zip 基于java的开发源码-...

    shell,bat脚本运行java程序

    下面将详细介绍如何使用shell脚本(适用于Unix/Linux系统)和bat脚本(适用于Windows系统)来运行Java程序。 **shell脚本运行Java程序** 在Unix/Linux环境中,我们可以创建一个.sh文件作为shell脚本来执行Java程序...

    SnakeScript Java游戏脚本引擎 v1.1

    SnakeScript是一款JAVA游戏模拟脚本引擎,程序代码类似于C。  本版新增功能及特性:  1.动态优先级设定;  2.动态实现脚本的加载、释放、暂停、恢复、结束等控制;  3.自动堆栈平衡;  4.无限级别函数调用...

    JAVA源码SnakeScriptJava游戏脚本引擎v1.1

    ### JAVA源码SnakeScript Java游戏脚本引擎v1.1 #### 一、SnakeScript Java游戏脚本引擎简介 SnakeScript Java游戏脚本引擎是一款基于Java语言开发的游戏脚本处理工具,它允许开发者通过简单的脚本语言来控制游戏...

    java运行js脚本引擎-----rhino

    Java运行JavaScript脚本引擎Rhino是一个强大的工具,它允许Java应用程序执行JavaScript代码并利用JavaScript的灵活性和动态性。Rhino是Mozilla基金会开发的一个开源项目,它完全用Java编写,因此可以无缝集成到Java...

    Sun Java SE Runtime Environment(JRE)6

    Sun Java SE Runtime Environment (JRE) 6 是Java平台标准版的一个重要版本,它为运行基于Java技术的应用程序提供了所需的运行环境。Java SE是Java Development Kit (JDK)的一部分,但JRE则不包含开发工具,主要是...

    Delphi实现脚本引擎

    在IT领域,脚本引擎是一种能够解释和执行脚本语言的软件组件,它使得开发者可以在应用程序中嵌入自定义的编程逻辑。Delphi,作为一款强大的面向对象的 Pascal 编译器,提供了丰富的功能和工具来创建高效、可扩展的...

    基于java的SnakeScript Java游戏脚本引擎 v1.1.zip

    《基于Java的SnakeScript Java游戏脚本引擎 v1.1》 在计算机编程领域,游戏开发是一项技术密集型的工作,而脚本引擎是其中的关键组件之一。SnakeScript Java游戏脚本引擎v1.1,正如其名,是一个专门用于Java平台的...

    脚本引擎内核源代码之:类C/C++脚本引擎_AngelScript_2.17.2

    AngelScript是一款开源的、类C/C++的脚本引擎,它允许开发者在应用程序中嵌入自定义的脚本语言,从而实现灵活的逻辑控制和动态行为。版本2.17.2是其一个重要里程碑,它在稳定性和性能上都得到了显著提升,同时保持了...

    java的windows启动脚本

    java的windows启动脚本

    JAVA SE6.0 API文档

    9. **脚本引擎支持**:Java 6通过`javax.script`包添加了对脚本语言(如JavaScript、Groovy等)的支持,可以在Java环境中直接运行和集成这些脚本。 10. **JDBC 4.0**:Java Database Connectivity (JDBC) API在Java...

    windows环境下启动java服务脚本

    windows环境下,启动java服务的bat脚本。注意修改: START "app" javaw -jar 服务jar包名.jar

    Java SE6 技术手册(上)

    4. **动态语言支持**:Java SE6引入了JSR 223(Scripting for the Java Platform),提供了对脚本语言的支持,允许在Java程序中直接执行JavaScript、Ruby等脚本代码,增强了Java的灵活性。 5. **NIO.2**:新的I/O ...

    C#脚本引擎,包括源码、执行程序和帮助文档

    这种执行程序使得用户能够在不接触源代码的情况下使用C#脚本引擎,只需提供C#脚本来执行。 5. **帮助文档**:`cs-scriptDocs.zip`很可能是C#脚本引擎的文档集合,包含了详细的使用指南、API参考、示例代码等,对于...

    基于Java的SnakeScript Java游戏脚本引擎 v1.1.zip

    《基于Java的SnakeScript Java游戏脚本引擎 v1.1》 在当今的软件开发领域,游戏引擎扮演着至关重要的角色,它们为开发者提供了一种高效、便捷的方式来创建游戏。而SnakeScript Java游戏脚本引擎v1.1,正是一个专注...

    JAVA SE 6.0 中文版 API 手册

    10. **脚本引擎**:Java 6开始支持内置的脚本引擎,如JavaScript(通过Nashorn引擎),使得在Java应用中执行脚本成为可能。 通过阅读和理解《JAVA SE 6.0 中文版 API 手册》,开发者可以深入学习Java语言的核心特性...

    Java脚本教程(学习资料)

    总之,Java脚本教程涵盖了如何在Java应用程序中集成和执行脚本语言的各个方面,包括如何发现和实例化脚本引擎,以及如何与不同的脚本环境进行交互。通过学习这些内容,开发者可以更好地利用Java的多语言支持,提高...

Global site tag (gtag.js) - Google Analytics