您的位置:首页 > 编程语言 > Java开发

Java SE 6概述--对脚本语言的支持

2008-04-09 15:49 260 查看
2006 年底,Sun 公司发布了 Java Standard Edition 6(Java SE 6)的最终正式版,代号 Mustang(野马)。跟 Tiger(Java SE 5)相比,Mustang 在性能方面有了不错的提升。与 Tiger 在 API 库方面的大幅度加强相比,虽然 Mustang 在 API 库方面的新特性显得不太多,但是也提供了许多实用和方便的功能:在脚本,WebService,XML,编译器 API数据JMX网络Instrumentation 方面都有不错的新特性和功能加强。

Java 脚本 API 概述
DK6增加了对脚本语言的支持(JSR 223),原理上是将脚本语言编译成bytecode,这样脚本语言也能享用Java平台的诸多优势,包括可移植性,安全等,另外,由于现在是编译成bytecode后再执行,所以比原来边解释边执行效率要高很多。加入对脚本语言的支持后,对Java语言也提供了以下好处。
1.许多脚本语言都有动态特性,比如,你不需要用一个变量之前先声明它,你可以用一个变量存放完全不同类型的对象,你不需要做强制类型转换,因为转换都是自动的。现在Java语言也可以通过对脚本语言的支持间接获得这种灵活性。
2.可以用脚本语言快速开发产品原型,因为现在可以Edit-Run,而无需Edit-Compile-Run,当然,因为Java有非常好的IDE支持,我 们完全可以在IDE里面编辑源文件,然后点击运行(隐含编译),以此达到快速开发原型的目的,所以这点好处基本上可以忽略。
3.通过引入脚本语言可以轻松实现Java应用程序的扩展和自定义,我们可以把原来分布在在Java应用程序中的配置逻辑,数学表达式和业务规则提取出来,转用JavaScript来处理。

Sun的JDK6实现包含了一个基于Mozilla Rhino的 脚本语言引擎,支持JavaScript,这并不是说明JDK6只支持JavaScript,任何第三方都可以自己实现一个JSR-223兼容的脚本引擎 使得JDK6支持别的脚本语言,比如,你想让JDK6支持Ruby,那你可以自己按照JSR 223的规范实现一个Ruby的脚本引擎类,具体一点,你需要实现javax.script.ScriptEngine(简单起见,可以继承javax.script.AbstractScriptEngine)和javax.script.ScriptEngineFactory两个接口。

在 javax.script 包中定义的实现类并不多,主要是一些接口和对应的抽象类,

这个包的具体实现类少的根本原因是这个包只是定义了一个编程接口的框架规范,至于对如何解析运行具体的脚本语言,还需要由第三方提供实现。虽然这些脚本引擎的实现各不相同,但是对于 Java 脚本 API 的使用者来说,这些具体的实现被很好的隔离隐藏了。Scripting API是用于在Java里面编写脚本语言程序的API, 在Javax.script中可以找到Scripting API,我们就是用这个API来编写JavaScript程序,这个包里面有一个ScriptEngineManager类,它是使用Scripting API的入口,ScriptEngineManager可以通过jar服务发现(service discovery)机制寻找合适的脚本引擎类(ScriptEngine)使用Scripting API的最简单方式只需以下3个步骤:
1.创建一个ScriptEngineManager对象。
2.通过ScriptEngineManager获得ScriptEngine对象。
3.用ScriptEngine的eval()方法执行脚本。

执行脚本语言
import javax.script.*;
public class HelloWorld {
qpublic static void main(String[] args) throws ScriptException {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("JavaScript");
engine.eval("print ('Hello World')");
q}
}

执行脚本语言
ScriptEngine 接口提供了许多 eval 函数的变体用来运行脚本,这个函数的功能就是获取脚本输入,运行脚本,最后返回输出。前面 的例子中直接通过字符串作为 eval 函数的参数读入脚本程序。除此之外,ScriptEngine 还提供了以一个 java.io.Reader 作为输入参数的 eval 函数。脚本程序实质上是一些可以用脚本引擎执行的字节流,通过一个 Reader 对象,eval 函数就能从不同的数据源中读取字节流来运行,这个数据源可以来自内存、文件,甚至直接来自网络。

public class RunScript {
public static void main(String[] args) throws Exception {
String script = "JavaScript";
String file = "D://run.js";
FileReader scriptReader = new FileReader(new File(file));
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName(script); engine.eval(scriptReader);
}
}

调用脚本语言的方法
public class TestInvokeScriptMethod {
public static void main(String[] args) throws Exception {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("JavaScript");
testInvokeScriptMethod(engine);
}
public static void testInvokeScriptMethod(ScriptEngine engine)
throws ScriptException, NoSuchMethodException {
String script = "function hello(name) { return 'Hello,' + name;}";
engine.eval(script);
Invocable inv = (Invocable) engine;
String res = (String) inv.invokeFunction("hello", "何琳");
System.out.println("返回结果:" + res);
}
}

脚本引擎本身并不负责调用在脚本中定义的方法,而是将其转换成实现javax.script.Invocable接口的inv对象,由inv对象利用invokeFunction()方法来调用脚本方法。invokeFunction()接受不定数量的参数,但第一个入参必须是方法名,而后面的入参是将要传入的给脚本方法的参数,均为java.lang.Object类型。我们知道JavaScript是一种弱类型定义语言,有脚本引擎将java.lang.Object类型的参数转换为脚本语言能接受的值。

脚本语言使用java变量
运行在脚本宿主机中的脚本语言,它的执行权限和能访问的设备范围是有限的,往往需要借助其他手段才能访问磁盘文件,正是这个原因在javaScript语言中甚至没有定义文件对象类型。下面通过一个例子了解运行在java脚本引擎中的javaScript是如何借助java文件对象来访问文件系统的。

脚本语言使用java变量
public class TestScriptVariables {
public static void main(String[] args) throws Exception {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("JavaScript");
testScriptVariables(engine);
}
public static void testScriptVariables(ScriptEngine engine)
throws ScriptException, NoSuchMethodException {
File file = new File("D://test.txt");
engine.put("f", file);
engine.eval("println('文件大小:'+f.length())");
}
}

n在程序的第19行,通过java.script.ScriptEngine的put()方法为javaScript脚本定义了一个名为f的全局变量,其值类型为java语言的文件对象。ScriptEngine的put()方法本意是用于设置脚本引擎的状态键值对,一般用于定义脚本的全局变量。其第1个参数为变量名称,定义为java.lang.String类型,第2个参数为变量值,定义为java.lang.Object类型。
javaScript变量f由java脚本引擎定义并赋值,该变量继承了java的File对象的全部属性和方法,所以我们可以看到,在javaScript中获得到了文件的尺寸大小。

脚本语言使用Java的类
javascript不仅能使用java为之定义的变量,而且能够完整的引入java的类包。我们可以发现Javascript可以实现java所能实现的全部功能。

脚本语言使用Java的类
public class TestUsingJDKClasses {
public static void main(String[] args) throws Exception {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("JavaScript");
testUsingJDKClasses(engine);
}
public static void testUsingJDKClasses(ScriptEngine engine)
throws Exception {
// Packages是脚本语言里的一个全局变量,专用于访问JDK的package
String js = "function doSwing(t){var f=new Packages.javax.swing.JFrame(t);f.setSize(400,300);f.setVisible(true);}";
engine.eval(js);
Invocable inv = (Invocable) engine;
inv.invokeFunction("doSwing", "Scripting Swing");
}
}

在代码的第17行,我们在脚本中定义了一个方法doSwing(),接着利用Invocable接口调用该脚本方法。在脚本语言中使用到了Packages这一全局变量。Packages是脚本语言里的一个全局变量,专用于访问java的类包。

脚本语言实现Java的接口
public class TestScriptInterface {
public static void main(String[] args) throws Exception {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("JavaScript");
testScriptInterface(engine);
}
public static void testScriptInterface(ScriptEngine engine)
throws ScriptException {
String script = "var obj = new Object(); obj.run = function() { println('run()方法被调用'); }";
engine.eval(script);
Object obj = engine.get("obj");
Invocable inv = (Invocable) engine;
Runnable r = inv.getInterface(obj, Runnable.class);
Thread th = new Thread(r);
th.start();
}
}

我们在代码的第17行,在脚本中定义了一个obj的对象,该对象拥有一个方法run(),方法是向终端输出“run()方法被调用”。在代码的19行利用javax.script.ScriptEngine.get()方法获得javaScript定义的变量obj。然后用javax.script.Invocable接口的一个方法getInterface()来获得javaScript定义的Interface,并将其转化成实现特定的Java Interface的对象。javax.script.Invocable接口的getInterface() 方法接收两个参数:第1个参数是从javaScript中获得的变量,也就是带转换成特定Java Interface的对象。第2个参数是转换目标接口的类名,这里将obj转换成实现java.lang.Runnable接口的对象。这种转换不是任意的,如果转换的对象不具备目标接口的方法,将返回null。这里将obj对象转换成java.lang.Runnable接口的对象后,利用转换得到的进程对象创建并启动一个子进程,从而触发了obj的run()方法。

JDK6.0中有一个命令行工具——jrunscript,可以在JDK6.0安装目录的bin子目录下找到这个命令行工具。 jrunscript是一个脚本语言的解释程序,它独立于脚本语言,但默认是用JavaScript。我们可以用jrunscript来测试自己写的脚本语言是否正确。



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: