网站首页 网站导航 课程中心
新闻中心
您所在的位置:Java培训 > 新闻中心 > Java的脚本化编程指南

Java的脚本化编程指南

来源:中软卓越 日期:2017-05-25 10:55 人气:
  Java的脚本化编程指南
       Java脚本化API为谁准备?
  
  脚本语言的一些有用的特性是:
  
  方便:大多数脚本语言都是动态类型的。您通常可以创建新的变量,而不声明变量类型,并且您可以重用变量来存储不同类型的对象。此外,脚本语言往往会自动执行许多类型的转换,例如,必要时将数字10转换为“10”。
  
  开发快速原型:您可以避免编辑编译运行周期,只使用“编辑运行”!
  
  应用扩展/定制:你可以“具体化”的部分应用程序,例如一些配置脚本,业务逻辑/规则和财务应用中的数学表达式。
  
  为应用添加命令行模式,用于调试、运行时配置/部署时间。现在大多数应用程序都有一个基于Web的GUI配置工具。但是系统管理员/部署人员常常喜欢命令行工具。一个“标准”的脚本语言可以用来实现这个目的,而不是发明特设的脚本语言。
  
  Java脚本API是一种独立于框架的脚本语言,使用来自于Java代码的脚本引擎。通过java脚本API,可以使用Java语言编写定制/可扩展的应用程序并将自定义脚本语言选择留给最终用户。Java应用程序开发者不需要在开发过程中选择扩展语言。如果你使用JSR-223API来编写应用,那么你的用户可以使用任何JSR-223兼容的脚本语言。
  
  脚本包
  
  Java脚本功能是在javax.包中。这是一个比较小的,简单的API。脚本的出发点是EngineManager类。一个EngineManager对象可以通过jar文件的服务发现机制发现脚本引擎。它也可以实例化脚本引擎来解释使用特定的脚本语言编写的脚本。使用脚本编程接口的最简单的方法如下:
  
  创建一个EngineManager对象
  
  从EngineManager获取Engine对象
  
  使用Engine的eval方法执行脚本
  
  现在,是时候看一些样本代码了。了解一些Java有助于阅读这些例子,但不是强制的。
  
  实例“Hello,World”
  
  从EngineManager实例中,我们通过getEngineByName方法得到一个Java引擎实例。通过脚本引擎的eval方法来执行给定的Java代码。为简便起见,本例以及随后的例子中,我们不对异常进行处理。javax.API有检查和运行时异常,你必须妥善处理异常。
  
  importjavax..*;publicclassEval{publicstaticvoidmain(String[]args)throwsException{//createaenginemanagerEngineManagerfactory=newEngineManager();//createaJavaengineEngineengine=factory.getEngineByName("Java");//evaluateJavacodefromStringengine.eval("print('Hello,World')");}}执行一个脚本文件
  
  在这个例子中,我们调用eval方法来接收java.io.Reader作为输入源。读入的脚本被执行。这种方式能够成文件执行脚本,用相关的输入流对象读取URL和资源。
  
  importjavax..*;publicclassEvalFile{publicstaticvoidmain(String[]args)throwsException{//createaenginemanagerEngineManagerfactory=newEngineManager();//createJavaengineEngineengine=factory.getEngineByName("Java");//evaluateJavacodefromgivenfile-specifiedbyfirstargumentengine.eval(newjava.io.FileReader(args[0]));}}
  
  假设我们有一个叫”test.js”的文件,里面的内容如下:
  
  println("Thisishellofromtest.js");
  
  我们可以使用下面的方式来运行刚刚的脚本
  
  javaEvalFiletest.js脚本变量
  
  当你的java应用程序嵌入脚本引擎和脚本,你可能希望将您的应用程序对象为全局变量暴露于脚本中。这个例子演示了如何将您的应用程序对象作为全局变量暴露于脚本中。我们在应用程序中创建一个java.io.File对象作为全局变量,名称是file。该脚本可以访问变量,例如,它可以调用它的公共方法。注意访问java对象、领域和方法的语法依赖于脚本语言。Java支持最“自然”的类似java的语法。
  
  publicclassVars{publicstaticvoidmain(String[]args)throwsException{EngineManagermanager=newEngineManager();Engineengine=manager.getEngineByName("Java");Filef=newFile("test.txt");//exposeFileobjectasvariabletoengine.put("file",f);//evaluateastring.Theaccesses"file"//variableandcallsmethodonitengine.eval("print(file.getAbsolutePath())");}}调用脚本函数和方法
  
  有些时候,你可能需要多次调用一个特定脚本函数,例如你的应用程序菜单功能可能由脚本来实现。在菜单中的操作事件处理程序中,可能需要调用一个特定的脚本函数。下面的示例演示在Java代码调用一个特定的脚本。
  
  importjavax..*;publicclassInvokeFunction{publicstaticvoidmain(String[]args)throwsException{EngineManagermanager=newEngineManager();Engineengine=manager.getEngineByName("Java");//JavacodeinaStringString="functionhello(name){print('Hello,'+name);}";//evaluateengine.eval();//javax..Invocableisanoptionalinterface.//Checkwhetheryourengineimplementsornot!//NotethattheJavaengineimplementsInvocableinterface.Invocableinv=(Invocable)engine;//invoketheglobalfunctionnamed"hello"inv.invokeFunction("hello","ing!!");}}
  
  如果你的脚本语言是基于对象(如Java)或面向对象的,你可以在脚本对象上调用脚本方法。
  
  importjavax..*;publicclassInvokeMethod{publicstaticvoidmain(String[]args)throwsException{EngineManagermanager=newEngineManager();Engineengine=manager.getEngineByName("Java");//JavacodeinaString.Thiscodedefinesaobject'obj'//withonemethodcalled'hello'.String="varobj=newObject();obj.hello=function(name){print('Hello,'+name);}";//evaluateengine.eval();//javax..Invocableisanoptionalinterface.//Checkwhetheryourengineimplementsornot!//NotethattheJavaengineimplementsInvocableinterface.Invocableinv=(Invocable)engine;//getobjectonwhichwewanttocallthemethodObjectobj=engine.get("obj");//invokethemethodnamed"hello"ontheobject"obj"inv.invokeMethod(obj,"hello","Method!!");}}通过脚本实现Java接口
  
  有些时候通过脚本函数或者方法可以很方便的实现java接口,而不是在Java中调用。同时,通过接口我们可以避免在很多地方使用javax.API接口。我们可以得到一个接口实现者对象并将其传递给不同的Javaapi。下面的例子演示了通过脚本实现java.lang.Runnable接口。
  
  importjavax..*;publicclassRunnableImpl{publicstaticvoidmain(String[]args)throwsException{EngineManagermanager=newEngineManager();Engineengine=manager.getEngineByName("Java");//JavacodeinaStringString="functionrun(){println('runcalled');}";//evaluateengine.eval();Invocableinv=(Invocable)engine;//getRunnableinterfaceobjectfromengine.Thisinterfacemethods//areimplementedbyfunctionswiththematchingname.Runnabler=inv.getInterface(Runnable.class);//startanewthreadthatrunstheimplemented//runnableinterfaceThreadth=newThread(r);th.start();}}
  
  如果你的脚本语言是基于对象或者面向对象的,可以通过脚本对象的脚本方法来实现Java接口。这避免了不得不调用脚本全局函数的接口方法。脚本对象可以存储接口实现状态。
  
  importjavax..*;publicclassRunnableImplObject{publicstaticvoidmain(String[]args)throwsException{EngineManagermanager=newEngineManager();Engineengine=manager.getEngineByName("Java");//JavacodeinaStringString="varobj=newObject();obj.run=function(){println('runmethodcalled');}";//evaluateengine.eval();//getobjectonwhichwewanttoimplementtheinterfacewithObjectobj=engine.get("obj");Invocableinv=(Invocable)engine;//getRunnableinterfaceobjectfromengine.Thisinterfacemethods//areimplementedbymethodsofobject'obj'Runnabler=inv.getInterface(obj,Runnable.class);//startanewthreadthatrunstheimplemented//runnableinterfaceThreadth=newThread(r);th.start();}}脚本的多作用域
  
  在variables例子中,我们看到怎样将应用对象暴露为脚本的全局变量。它有可能暴露为多个全局的作用域。单作用域是javax..Bindings的实例中.这个借口派生至java.util.Map。scope键值对的集合,其中键为非空、非空字符串。多scopes是javax..Context接口支持的。支持一个或多个脚本上下文与相关的域绑定。默认情况下,每一个脚本引擎都有一个默认的脚本上下文。默认的脚本上下文有至少一个域叫”ENGINE_SCOPE”。不同域的脚本上下文支持可以通过getscopes方法获取。
  
  importjavax..*;publicclassMultiScopes{publicstaticvoidmain(String[]args)throwsException{EngineManagermanager=newEngineManager();Engineengine=manager.getEngineByName("Java");engine.put("x","hello");//printglobalvariable"x"engine.eval("println(x);");//theabovelineprints"hello"//Now,passadifferentcontextContextnewContext=newSimpleContext();BindingsengineScope=newContext.getBindings(Context.ENGINE_SCOPE);//addnewvariable"x"tothenewengineScopeengineScope.put("x","world");//executethesame-butthistimepassadifferentcontextengine.eval("println(x);",newContext);//theabovelineprints"world"}}Java脚本引擎
  
  Sun的JDK6中包含了一个基于MozillaRhinoJava脚本引擎。这个引擎是基于版本为1.6R2的MozillaRhino。多数Rhino实现都被包含在内。少部分组件由于大小和安全原因被排除了:
  
  Java转字节码编译(也称”优化器”).。此功能依赖一个类生成库。去掉本功能意味着:Java是解释执行,且不影响脚本执行,因为优化器是透明的。
  
  Rhino的JavaAdapter也被去掉了。JavaAdapter是一个Java可扩展Java类和Java可实现Java接口功能。此功能也是需要类生成库的。我们把Rhino的JavaAdapter替换为Sun实现的JavaAdapter。在Sun的实现中,仅仅实现了Java对象可实现Java单接口功能。例如,下面的代码会正确执行。varv=newjava.lang.Runnable(){run:function(){print('hello');}}v.run();
  
  在大多数情况下,JavaAdapter是采用匿名类语法来实现单接口。使用JavaAdapter来扩展Java类或实现多接口并不常见。
  
  E4X(ECMAforXML–ECMAStandard357)被去掉了.使用XMLJava代码会产生一个语法错误.请注意,E4X支持ECMA标准是可选的-省略E4X的实现是被支持也是兼容ECMA。
  
  Rhino的命令行工具(Rhinoshell,debugger等)没有被包含在内。但你可以用使用jrun来代替。
  
  Java与Java的通信
  
  在大多数情况下,访问Java类、对象和方法很简单。从Java中访问属性和方法与同Java中一样。这里,我们突出JavaJava访问的重要方面.。更多的细节请阅读http://www.mozilla.org/rhino/java.html。下面是一些Java访问Java的代码片段。本节需要一些Java知识。如果你打算使用JSR-223中非Java脚本语言,那么本节可以跳过。
  
  引入Java包,类
  
  内置的函数importPackage和importClass可以用于引入Java包和类。
  
  //ImportJavapackagesandclasses//likeimportpackage.*;inJavaimportPackage(java.awt);//likeimportjava.awt.FrameinJavaimportClass(java.awt.Frame);//CreateJavaObjectsby"newClassName"varframe=newjava.awt.Frame("hello");//CallJavapublicmethodsfromframe.setVisible(true);//Access"JavaBean"propertieslike"fields"print(frame.title);
  
  全局变量Packages也可以用于访问Java包。例如:Packages.java.util.Vector,Packages.javax.swing.JFrame.请注意:”java”是“Packages.java”的快捷引用。还有一些等价的快捷引用前缀:javax,org,edu,com,net,所以几乎所有的JDK平台下的类都可以不使用”Packages”前缀而访问到。
  
  请注意,java.lang不是默认引入的(与Java不同),因为会与Java’s内置的Object,Boolean,Math等冲突。
  
  importPackage和importClass函数”污染”了Java中的全局变量。为了避免这种情况,你可以使用JavaImporter。
  
  //createJavaImporterwithspecificpackagesandclassestoimportvarSwingGui=newJavaImporter(javax.swing,javax.swing.event,javax.swing.border,java.awt.event);with(SwingGui){//withinthis'with'statement,wecanaccessSwingandAWT//classesbyunqualified(simple)names.varmybutton=newJButton("test");varmyframe=newJFrame("test");}C创建和使用Java的数组
  
  在Java中,创建一个对象时与Java中一样,而创建Java数组时需要显式的使用Java反射。但一旦创建好后,访问其中的元素或获取大小就和Java中一样。另外,也可以使用脚本数组用在Java方法中期望的Java数组(因为可以自动转换)。所以在大多数情况下我们不需要显式地创建Java数组。
  
  //createJavaStringarrayof5elementsvara=java.lang.reflect.Array.newInstance(java.lang.String,5);//AccessingelementsandlengthaccessisbyusualJavasyntaxa[0]="ingisgreat!";print(a.length);
  
  实现Java接口
  
  在Java中,可以使用Java匿名类语法形式实现Java中接口:
  
  varr=newjava.lang.Runnable(){run:function(){print("running...\n");}};//"r"canbepassedtoJavamethodsthatexpectjava.lang.Runnablevarth=newjava.lang.Thread(r);th.start();
  
  当接口中只有一个需要实现的方法时,你可以自己传入脚本的函数(因为可以自动转换)。functionfunc(){print("Iamfunc!");}//passfunctionforjava.lang.Runnableargumentvarth=newjava.lang.Thread(func);th.start();
  
  重载
  
  Java方法是使用参数类型重载的。在Java中,重载发生在编译阶段(执行javac)。当脚本中调用Java方法时,脚本的翻译器或编译器需要选择适当的方法。对于Java引擎,您不需要做任何特别的——正确的Java方法重载变体是根据参数类型选择的。但有时,您可能希望(或有)显式地选择一个特定的过载变体。
  
  varout=java.lang.System.out;//selectaparticularprintlnfunctionout["println(java.lang.Object)"]("hello");
  
  更多Java的Java方法重载细节阅读
  
  http://www.mozilla.org/js/liveconnect/lc3_method_overloading.html
  
  自定义脚本引擎
  
  我们不会覆盖的JSR-223兼容脚本引擎实现细节.至少,您需要实现javax..Engine和javax..EngineFactory接口。抽象类javax..AbstractEngine提供了一些Engine接口中定义的方法。
  
  在开始实现JSR-223引擎之前,您可能需要下载http://ing.dev.java.net工程。这个工程维护了一些流行的开源脚本语言的JSR-223实现。
  
  引用
  
  JSR-223ingfortheJavaPlatform
  
  JavaDeveloperConnection
  
  JavaMethodOverloadingandLiveConnect3
  
  Rhino:JavaforJava
  
  ingJava(fromJava)
  
  ing.dev.java.netproject
  
  中软卓越Java课程作为主打课程之一,课程内容全部提炼自企业一线岗位实际工作经验和能力标准;课程内容来自于企业岗位需求又高于企业岗位任职标准;不仅满足应聘时工作需求,又着眼于未来职业发展需要。课程体系严密,围绕企业需求,以实战项目导入教学体系;模块课程完整,每个模块对应一类岗位,将所有岗位能力对应到各个模块;课程内容全面,所有课程内容吸纳最新Java知识,全面覆盖了各个知识点,中软卓越用技术改变你的未来,用责任帮你谱写人生!

营业执照 版权所有©Copyright 2008-2017,北京中软国际教育科技股份有限公司, All Rights Reserved. ICP备案号:京ICP备14058756号-2

| | 分类导航 | 关于我们