`

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方法。 
分享到:
评论

相关推荐

    Rhino脚本引擎技术介绍

    Rhino脚本引擎的使用让Java程序能够借助脚本的便捷性,实现对Java对象的操作。 在JDK1.6中,javax.script包中的主要类和接口包括Bindings、Compilable、CompiledScript、ScriptEngine、ScriptEngineManager等。...

    为Java应用程序加入脚本引擎

    BeanShell作为一种强大的脚本引擎,不仅能够提高Java应用程序的灵活性和可扩展性,还能让非专业程序员也能参与到应用程序的定制化开发过程中。通过本文的介绍,相信您已经掌握了BeanShell的基本特性和集成方法,希望...

    Java 8 Nashorn 脚本引擎

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

    SnakeScript Java游戏脚本引擎 v1.1

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

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

    Java运行JavaScript脚本引擎——Rhino,是一种在Java平台上执行JavaScript代码的重要工具。Rhino是Mozilla基金会的一个开源项目,它实现了ECMAScript标准,也就是JavaScript的标准化版本。Rhino以其高性能和深度集成...

    Java SE 6 新特性

    Java SE 6 是Java平台的一个重要版本,引入了许多新特性,其中一个显著的更新是对脚本语言的支持。这一特性是通过实现Java Specification Request (JSR) 223来达成的,目的是为了在Java应用程序中方便地集成和使用...

    Java脚本引擎1

    Java脚本引擎1 在Java中,为了与各种脚本语言进行交互,如JavaScript,Java提供了ScriptEngine API,这是Java Scripting API的一部分。这个API允许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平台的...

    JAVA SE6.0 API文档

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

    第 1 部分: 引入 Java 脚本 API

    这个API在Java 6版本中得到了显著增强,为开发者提供了在Java程序中嵌入和执行脚本引擎的能力,例如JavaScript、Groovy或Rhino等。通过Java脚本API,开发者可以利用脚本语言的灵活性和简洁性,同时保持Java的系统级...

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

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

    java_se_6.zip

    首先,Java SE 6的重要更新之一是增强了Swing GUI库。这一版本引入了新的组件,如JTabbedPane的改进,使得创建多标签界面更加简单直观。此外,JTable和JTree也得到了优化,提供了更好的数据绑定支持,使得与数据库或...

    shell脚本启动Java程序测试工程

    当涉及到启动Java应用程序时,shell脚本可以提供一个方便、可重复且灵活的方法。下面我们将深入探讨如何使用shell脚本来启动Java程序以及相关的知识点。 首先,我们需要了解Java程序的运行方式。Java应用程序通常由...

    JAVA SE 6.0 中文版 API 手册

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

    Java脚本言程序手册语员

    Java脚本API设计用于在Java应用程序中嵌入脚本引擎的能力,无需依赖具体的脚本语言。这一API的核心价值在于提供了一种灵活的方式,使得开发者能够根据实际需求选择最适合项目的脚本语言,同时也允许最终用户根据个人...

    java源码:SnakeScript Java游戏脚本引擎 v1.1.rar

    总的来说,SnakeScript Java游戏脚本引擎 v1.1 提供了一个平台,让开发者可以专注于游戏逻辑的编写,而不必关心底层的实现细节。通过深入研究源代码和文档,开发者不仅可以学习到游戏脚本引擎的设计,还可以提升自己...

    Java虚拟机规范(Java SE 7)

    Java虚拟机规范(Java SE 7)是Java开发的关键组成部分,它是Java程序运行的基础,确保了跨平台的兼容性和可移植性。Java虚拟机(JVM)是Java平台的核心,它是一个抽象的计算机系统,执行编译后的Java字节码。在Java...

Global site tag (gtag.js) - Google Analytics