使用javax.scriptAPI本节给出了javax.scriptAPI的概览,展示了如何执行脚本来访问Java对象、如何从Java代码调用JavaScript函数,以及如何为所编译的脚本实现缓存机制。执行脚本javax.scriptAPI十分简单。可以先创建一个ScriptEngineManager实例,有了这个实例就能用下列方法中的任一个来获得ScriptEngine对象(参见清单1):getEngineByName()getEngineByExtension()getEngineByMimeType()清单1.获得一个ScriptEngine实例importjavax.script.*;...ScriptEngineManagermanager=newScriptEngineManager();ScriptEngineengine=manager.getEngineByName(JavaScript);...engine.eval(...);此外,还可以通过getEngineFactories()获得可用脚本引擎的列表。目前,只有JavaScript引擎是与JDK6捆绑的,不过ScriptEngineManager实现了一种发现机制,能发现支持JSR-223ScriptingfortheJavaPlatform的第三方引擎。只需将脚本引擎的JAR文件放入CLASSPATH即可。获得了javax.script.ScriptEngine实例后,就可以调用eval()来执行脚本了。也可以将Java对象作为脚本变量导出,其间要将Bindings实例传递给eval()方法。清单2所示的ScriptDemo.java示例导出两个名为demoVar和strBuf的变量、执行DemoScript.js脚本,然后让这些变量输出它们修改后的值。清单2.ScriptDemo.java示例packagejsee.demo;importjavax.script.*;importjava.io.*;publicclassScriptDemo{publicstaticvoidmain(Stringargs[])throwsException{//GettheJavaScriptengineScriptEngineManagermanager=newScriptEngineManager();ScriptEngineengine=manager.getEngineByName(JavaScript);//SetJavaScriptvariablesBindingsvars=newSimpleBindings();vars.put(demoVar,valuesetinScriptDemo.java);vars.put(strBuf,newStringBuffer(stringbuffer));//RunDemoScript.jsReaderscriptReader=newInputStreamReader(ScriptDemo.class.getResourceAsStream(DemoScript.js));try{engine.eval(scriptReader,vars);}finally{scriptReader.close();}//GetJavaScriptvariablesObjectdemoVar=vars.get(demoVar);System.out.println([Java]demoVar:+demoVar);System.out.println(Javaobject:+demoVar.getClass().getName());System.out.println();ObjectstrBuf=vars.get(strBuf);System.out.println([Java]strBuf:+strBuf);System.out.println(Javaobject:+strBuf.getClass().getName());System.out.println();ObjectnewVar=vars.get(newVar);System.out.println([Java]newVar:+newVar);System.out.println(Javaobject:+newVar.getClass().getName());System.out.println();}}DemoScript.js文件(如清单3所示)包含一个printType()函数,该函数可用来输出每个脚本变量的类型。这个示例会调用strBuf对象的append()方法、修改demoVar的值并设置一个名为newVar的新变量脚本。如果传递给printType()的对象具有getClass()方法,那么它一定是个Java对象,该对象的类名由obj.getClass().name获得。这个JavaScript表达式调用此对象的java.lang.Class实例的getName()方法。如果此对象不具备getClass,那么printType()就会调用toSource()方法,而该方法是所有JavaScript对象都有的。清单3.DemoScript.js示例println(Startscript\r\n);//OutputthetypeofanobjectfunctionprintType(obj){if(obj.getClass)println(Javaobject:+obj.getClass().name);elseprintln(JSobject:+obj.toSource());println();}//Printvariableprintln([JS]demoVar:+demoVar);printType(demoVar);//CallmethodofJavaobjectstrBuf.append(usedinDemoScript.js);println([JS]strBuf:+strBuf);printType(strBuf);//ModifyvariabledemoVar=valuesetinDemoScript.js;println([JS]demoVar:+demoVar);printType(demoVar);//SetanewvariablevarnewVar={x:1,y:{u:2,v:3}}println([JS]newVar:+newVar);printType(newVar);println(Endscript\r\n);清单4是ScriptDemo.java示例的输出。值得注意的是demoVar作为JavaScriptString导出,而strBuf的类型仍然是java.lang.StringBuffer。原始变量和Java字符串均作为本地JavaScript对象导出。任何其他的Java对象(包括数组)均原样导出。清单4.ScriptDemo.java的输出Startscript[JS]demoVar:valuesetinScriptDemo.javaJSobject:(newString(valuesetinScriptDemo.java))[JS]strBuf:stringbufferusedinDemoScript.jsJavaobject:java.lang.StringBuffer[JS]demoVar:valuesetinDemoScript.jsJSobject:(newString(valuesetinDemoScript.js))[JS]newVar:[objectObject]JSobject:({x:1,y:{u:2,v:3}})Endscript[Java]demoVar:valuesetinDemoScript.jsJavaobject:java.lang.String[Java]strBuf:stringbufferusedinDemoScript.jsJavaobject:java.lang.StringBuffer[Java]newVar:[objectObject]Javaobject:sun.org.mozilla.javascript.internal.NativeObject运行该脚本后,此引擎就会接受所有变量(包括新变量)并执行反转变换,将JavaScript原始变量和字符串转变成Java对象。其他的JavaScript对象则被包装成Java对象,这些对象能使用某种特定于引擎的内部API,比如sun.org.mozilla.javascript.internal.NativeObject。有时,可能会只想使用那些标准的API,因此Java代码和所执行脚本间的全部数据转换都应通过原始变量、字符串和Java对象(比如bean)完成,这是因为在JavaScript代码内可以很容易地访问到它们的属性和方法。简言之,就是不要试图在Java代码内访问本地JavaScript对象,相反,应该在JavaScript代码内使用Java对象。调用函数在之前的例子中,您已经看到了从JavaScript调用Java方法是可行的。现在您将会了解如何从Java代码调用JavaScript函数。首先,必须先执行包含想要调用的那个函数的脚本。然后,再将ScriptEngine实例强制转换为javax.script.Invocable,后者还提供了invokeFunction()和invokeMethod()。如果脚本实现了Java接口的全部方法,那么也可以使用getInterface()获得一个Java对象,该对象的方法用此脚本语言编码。InvDemo.java示例(如清单5所示)执行一个名为InvScript.js的脚本,它包含demoFunction()例程。在进行强制类型转换以将ScriptEngine实例转换为Invocable之后,这个Java示例才能将函数名和参数传递给引擎的invokeFunction()方法,而此方法会返回由demoFunction()返回的值。清单5.InvDemo.java示例packagejsee.demo;importjavax.script.*;importjava.io.*;publicclassInvDemo{publicstaticvoidmain(Stringargs[])throwsException{//GettheJavaScriptengineScriptEngineManagermanager=newScriptEngineManager();ScriptEngineengine=manager.getEngineByName(JavaScript);//RunInvScript.jsReaderscriptReader=newInputStreamReader(InvDemo.class.getResourceAsStream(InvScript.js));try{engine.eval(scriptReader);}finally{scriptReader.close();}//InvokeaJavaScriptfunctionif(engineinstanceofInvocable){InvocableinvEngine=(Invocable)engine;Objectresult=invEngine.invokeFunction(demoFunction,1,2.3);System.out.println([Java]result:+result);System.out.println(Javaobject:+result.getClass().getName());System.out.println();}elseSystem.out.println(NOTInvocable);}}InvScript.js文件(如清单6所示