java6.0新特性<二>

4.java平台中的脚本语言

4.1简介

java 6 提供了公共脚本语言框架用来集成多种脚本语言。大多数流行的脚本语言,如Java Script,PHP Script,Bean Shell Script和PNuts Script等,都可以集成在java平台中。由于这个框架的存在,脚本语言和java语言之间的通信成为了可能。也就是说脚本语言可以获取java的库,同时,java语言中,可以直接嵌入脚本语言。java应用程序在脚本引擎的支持下,也可以直接编译和执行脚本语言,下面我们就了解一下这方面的具体信息:

脚本引擎提供的两大核心组件:

  1. 语言绑定
  2. 脚本API

4.2语言绑定

语言绑定为java代码与脚本代码之间提供了建立通信的机制,具体的说,就是以下几个方面:

  1. 脚本语言创建的java对象,在脚本引擎中是如何存储和维持的
  2. 脚本参数是如何来回转换的
  3. 脚本语言如何调用java方法
  4. 脚本代码如何获得java代码的返回值

我们通过一段代码,来更清楚的了解这些内容:   

 var aJavaString =new String("A Test String");

上面的代码,就是创建一个java对象,并且,把这个对象分配给javascript的一个var型变量aJavaString。当Rhino Script 引擎(一种javaScript引擎的名字)解析这段代码的时候,它会创建一个String类型的对象,然后,存储起来。这些java对应和script对象,到底存储在哪里,依赖于Bindings。在这里,aJavaString其实就是扮演java.lang.String对象的代理。

接着,我们看下面的代码:

var aJavaString =newjava.lang.String('A Test String');
var length = aJavaString.substring(7,13);

如果我们仔细分析上面的代码,会有很多步骤:

  1. 脚本参数转换成java参数
  2. 指定要引用的java方法
  3. java方法中执行相应的业务逻辑
  4. 方法如果有返回值,返回到脚本代码中

第一行代码,创建一个String对象,并把这个对象存储在aJavaString这个脚本对象中,在这里aJavaString就是原始String对象的代理对象。接下来是,参数7和13被传入到String.subString方法中,传参的时候,引擎会使用默认的Script-Java映射,把参数传递到java方法中。然后,脚本引擎要保证在运行时可以通过Java Reflection API获取到String.subString(int,int)方法。现在,方法被调用,逻辑开始执行。最后,通过Java-Script映射,将java代码的返回值转换成javaScript对象。

4.3脚本API

这个API比较强大,它允许java程序直接把脚本语言嵌入过来,它还提供了方便插入新的脚本引擎的框架,我们可以在javax.script脚本下看到整个API。

ScriptEngineManager类提供了搜索和添加脚本引擎到java平台的机制。有一些便利的方法用来发现已经存在的脚本引擎。下面这个例子,就是遍历java 6 中分布的脚本引擎:

List allFactories = ScriptEngineManager.getEngineFactories();
 
for(ScriptEngineFactory engineFactory : allFactories){
    System.out.println("Engine Name"+ engineFactory.getEngineName());
}

ScriputEngineFactory是用来创建ScriptEngine对象的工厂。在这里,有两种不同的方法获取ScriptEngine类的实例。一种方法是调用ScripteEngineFactory.getScriptEngine(),另一种直接的方法ScriptEngineManager的getEngineByName方法。

// First Way
ScriptEngineFactory rhinoFactory = getScriptEngineFactory();
ScriptEngine rhinoEngine = rhinoFactory.getScriptEngine();
 
// Second Way
String name  ="javascript";
ScriptEngine rhinoEngine = ScriptEngineManager.getEngineByName(engineName);

通过调用ScriptEngine.eval(String)方法就可以执行相应的脚本程序了。

javax.script.Bindings,为ScriptEngines提供key/value信息。在这里,Bindings有两中作用范围:Global Scope和Engine Scope。默认情况下。ScriptEngineManager管理一些默认的Bindings,这些Bindings可以通过ScriptManager.getBindings()获得,这种方法获得的Bindings是Global Bindings,如下面的代码所示:

Bindings globalBindings = scriptEngineManager.getBindings();
globalBindings.put("key1","value1");
globalBindings.put("key2","value2");

也可以在引擎之间定制Bindings信息,比如,通过ScriptEngine.getBindings获得Bindings为Engine Bindings.

4.4示例

下面的代码,演示了如何之间在java程序中嵌入脚本代码,以及如何在Java代码和脚本代码之间进行参数传递:

package test;
 
import javax.script.*;
 
public class ScriptTest{
 
    public static void main(String[] args){
 
        try{
            // Create an instance of the Scripting manager.
            ScriptEngineManager manager = new ScriptEngineManager();
 
            // Get the reference to the rhino scripting engine.
            ScriptEngine rhinoEngine = manager.getEngineByName("javascript");
 
            // Get the Binding object for this Engine.
            Bindings bindings = rhinoEngine.getBindings(ScriptContext.ENGINE_SCOPE);
 
            // Put the input value to the Binding.
            bindings.put("strValue", "A Test String");
 
            // Populate the script code to be executed.
            StringBuilder scriptCode = new StringBuilder();
            scriptCode.append("var javaString = new java.lang.String(strValue);");
            scriptCode.append("var result = javaString.length();");
 
            // Evaluate the Script code.
            rhinoEngine.eval(scriptCode.toString());
 
            // Take the output value from the script, i.e from the Bindings.
            int strLength = (Integer)bindings.get("result");
 
            System.out.println("Length is " + strLength);
        }catch(Exception exception){
            exception.printStackTrace();
        }
    }
}

上面的代码中,首先创建了一个ScriptEngineManager实例,然后,通过ScriptEngineManager.getEngineByName(“javascript”)获得脚本引擎,通过Bindings在java代码和脚本代码之间传递参数,Bindings.put(“strValue”,”A Test String”)方法将参数添加到Bindings中。注意参数怎么在脚本语言运行时填充的,也就是说在运行时,脚本语言var javaString = new java.lang.String(strValue)变成了var javaString = new java.lang.String(‘A Test String’),然后,通过调用ScriptEngine.eval(String)这个方法执行相应的脚本。正如上面所提到的那样,脚本对象和java对象都是在Bindings里面进行保存和控制的,那么,可以直接调用Bindings.get(“result”)方法来获取脚本对象的结果值。

5.结论

这篇文章(包含java 6.0 新特性<一>)主要介绍了java 6 中的注释和脚本语言两个特性,之中,有一些示例性的代码出现以及一些API的介绍,这些都仅仅是皮毛性的东西,如果想在这些方面深入,还需要多实践以及更透彻的研究相应的实现以及原理。

备注:

1.原文地址:http://www.javabeat.net/2007/06/introduction-to-java-6-0-new-features-part-i/

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>