`

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

相关推荐

    JavaSE6入门之脚本引擎让程序如虎添翼.txt

    JSR223是Java平台脚本引擎的核心规范之一,它提供了一套统一的API,使得开发者能够在Java应用程序中无缝集成各种脚本语言。通过这个API,可以轻松获取和管理不同的脚本引擎,并且能够执行脚本代码。下面将详细介绍...

    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之间的互操作性,...

    Beginning Java SE 6 Platform

    讲解了Java脚本引擎API的使用方法,包括如何加载和执行动态脚本语言,并探讨了其在Java应用程序中的应用场景。 #### 国际化与本地化 介绍了Java中处理国际化和本地化的方法,包括资源束、格式化日期时间等,并讨论...

    shell,bat脚本运行java程序

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

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

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

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

    ### JAVA源码SnakeScript Java游戏脚本引擎v1.1 #### 一、SnakeScript Java游戏脚本引擎简介 SnakeScript Java游戏脚本引擎是一款基于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则不包含开发工具,主要是...

    Java SE 6: Top 10 Features

    监控和管理功能也是Java SE 6的重要特性之一。它提供了一系列工具和技术来帮助开发者更好地监控和管理运行时环境,确保应用程序稳定高效地运行。 #### 6. 编译器访问 Java SE 6允许开发者直接访问编译器,这意味着...

    基于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 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的系统级...

Global site tag (gtag.js) - Google Analytics