java6 新特新

JAVA6新特性介绍java

 

1. 使用JAXB来实现对象与XML之间的映射

JAXB是Java Architecture for XML Binding的缩写,能够将一个Java对象转变成为XML格式,反之亦然。咱们把对象与关系数据库之间的映射称为ORM, 其实也能够把对象与XML之间的映射称为OXM(Object XML Mapping). 原来JAXB是JavaEE的一部分,在JDK6中,SUN将其放到了Java SE中,这也是SUN的一向作法。JDK6中自带的这个JAXB版本是2.0, 比起1.0(JSR 31)来,JAXB2(JSR 222)用JDK5的新特性Annotation来标识要做绑定的类和属性等,这就极大简化了开发的工做量。实际上,在Java EE 5.0中,EJB和Web Services也经过Annotation 来简化开发工做。另外,JAXB在底层是用STAX(JSR173)来处理XML文档。程序员

下面用代码演示在JDK6中如何来用JAXB数据库

import java.io.FileReader;编程

import java.io.FileWriter;浏览器

import java.io.IOException;安全

import java.util.Calendar;服务器

 

import javax.xml.bind.JAXBContext;网络

import javax.xml.bind.JAXBException;架构

import javax.xml.bind.Marshaller;app

import javax.xml.bind.Unmarshaller;

import javax.xml.bind.annotation.XmlAttribute;

import javax.xml.bind.annotation.XmlElement;

import javax.xml.bind.annotation.XmlRootElement;

 

public class JAXB2Tester {

         public static void main(String[] args) throws JAXBException, IOException {

                   JAXBContext context = JAXBContext.newInstance(Person.class);

                   //下面代码演示将对象转变为xml

                   Marshaller m = context.createMarshaller();

                   Address address = new Address("China", "Beijing", "Beijing", "ShangDi West", "100080");

                   Person p = new Person(Calendar.getInstance(), "JAXB2", address, Gender.MALE, "SW");

                   FileWriter fw = new FileWriter("person.xml");

                   m.marshal(p, fw);

                   //下面代码演示将上面生成的xml转换为对象

                   FileReader fr = new FileReader("person.xml");

                   Unmarshaller um = context.createUnmarshaller();

                   Person p2 = (Person) um.unmarshal(fr);

                   System.out.println("Country:" + p2.getAddress().getCountry());

         }

}

 

@XmlRootElement

//表示person是一个根元素

class Person {

         @XmlElement

         Calendar birthDay; //birthday将做为person的子元素

         @XmlAttribute

         String name; //name将做为person的的一个属性

 

         public Address getAddress() {

                   return address;

         }

 

         @XmlElement

         Address address; //address将做为person的子元素

         @XmlElement

         Gender gender; //gender将做为person的子元素

         @XmlElement

         String job; //job将做为person的子元素

 

         public Person() {

         }

 

         public Person(Calendar birthDay, String name, Address address, Gender gender, String job) {

                   this.birthDay = birthDay;

                   this.name = name;

                   this.address = address;

                   this.gender = gender;

                   this.job = job;

         }

}

 

enum Gender {

         MALE(true), FEMALE(false);

         private boolean value;

 

         Gender(boolean _value) {

                   value = _value;

         }

}

 

class Address {

         @XmlAttribute

         String country;

         @XmlElement

         String state;

         @XmlElement

         String city;

         @XmlElement

         String street;

         String zipcode; //因为没有添加@XmlElement,因此该元素不会出如今输出的xml中

 

         public Address() {

         }

 

         public Address(String country, String state, String city, String street, String zipcode) {

                   this.country = country;

                   this.state = state;

                   this.city = city;

                   this.street = street;

                   this.zipcode = zipcode;

         }

 

         public String getCountry() {

                   return country;

         }

}

运行该程序,咱们会获得一个person.xml 的文件,以下:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<person name="JAXB2">

         <birthDay>2010-04-21T18:00:08.187+08:00</birthDay>

         <address country="China">

                   <state>Beijing</state>

                   <city>Beijing</city>

                   <street>ShangDi West</street>

         </address>

         <gender>MALE</gender>

         <job>SW</job>

</person>

控制台会输出

Country:China

最后,想说一点,除了JAXB以外,咱们还能够经过XMLBeans和Castor等来实现一样的功能。

2. 理解STAX

STAX (JSR 173)是JDK6.0中除了DOM 和SAX以外的又一种处理XML文档的API。

STAX的来历

在JAXP1.3(JSR 206)有两种处理XML文档的方法:DOM(Document Object Model)和SAX(Simple API for XML).因为JDK6.0中的JAXB2(JSR 222)和JAX-WS 2.0(JSR 224)都会用到STAX因此Sun决定把STAX加入到JAXP家族当中来,并将JAXP的版本升级到1.4(JAXP1.4是JAXP1.3 的维护版本). JDK6 里面JAXP的版本就是1.4.

STAX简介

STAX是The Streaming API for XML的缩写,一种利用拉模式解析(pull-parsing)XML文档的API. STAX经过提供一种基于事件迭代器(Iterator)的API让程序员去控制xml文档解析过程,程序遍历这个事件迭代器去处理每个解析事件,解析事件能够看作是程序拉出来的,也就是程序促使解析器产生一个解析事件而后处理该事件,以后又促使解析器产生下一个解析事件,如此循环直到碰到文档结束符;SAX 也是基于事件处理xml 文档,但倒是用推模式解析,解析器解析完整个xml 文档后,才产生解析事件,而后推给程序去处理这些事件;DOM 采用的方式是将整个xml文档映射到一颗内存树,这样就能够很容易地获得父节点和子结点以及兄弟节点的数据,但若是文档很大,将会严重影响性能。

下面代码演示了如何经过STAX读取xml文档和生成xml文档。

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

 

import javax.xml.namespace.QName;

import javax.xml.stream.XMLEventReader;

import javax.xml.stream.XMLInputFactory;

import javax.xml.stream.XMLOutputFactory;

import javax.xml.stream.XMLStreamException;

import javax.xml.stream.XMLStreamWriter;

import javax.xml.stream.events.StartElement;

import javax.xml.stream.events.XMLEvent;

 

public class StaxTester {

         public static void main(String[] args) throws XMLStreamException, FileNotFoundException {

                   readXMLByStAX();//用XMLEventReader 解析xml 文档

                   writeXMLByStAX();//用XMLStreamWriter 写xml文档

         }

 

         private static void readXMLByStAX() throws XMLStreamException, FileNotFoundException {

                   XMLInputFactory xmlif = XMLInputFactory.newInstance();

                   XMLEventReader xmler = xmlif.createXMLEventReader(StaxTester.class.getResourceAsStream("test.xml"));

                   XMLEvent event;

                   StringBuffer parsingResult = new StringBuffer();

                   while (xmler.hasNext()) {

                            event = xmler.nextEvent();

                            if (event.isStartElement()) { //若是解析的是起始标记

                                     StartElement se = event.asStartElement();

                                     parsingResult.append("<");

                                     parsingResult.append(se.getName());

                                     if (se.getName().getLocalPart().equals("catalog")) {

                                               parsingResult.append(" id=\"");

                                               parsingResult.append(se.getAttributeByName(new QName("id")).getValue());

                                               parsingResult.append("\"");

                                     }

                                     parsingResult.append(">");

                            } else if (event.isCharacters()) { //若是解析的是文本内容

                                     parsingResult.append(event.asCharacters().getData());

                            } else if (event.isEndElement()) { //若是解析的是结束标记

                                     parsingResult.append("</");

                                     parsingResult.append(event.asEndElement().getName());

                                     parsingResult.append(">");

                            }

                   }

                   System.out.println(parsingResult);

         }

 

         private static void writeXMLByStAX() throws XMLStreamException, FileNotFoundException {

                   XMLOutputFactory xmlof = XMLOutputFactory.newInstance();

                   XMLStreamWriter xmlw = xmlof.createXMLStreamWriter(new FileOutputStream("output.xml"));

                   // 写入默认的XML 声明到xml文档

                   xmlw.writeStartDocument();

                   xmlw.writeCharacters("\n");

                   // 写入注释到xml 文档

                   xmlw.writeComment("testing comment");

                   xmlw.writeCharacters("\n");

                   // 写入一个catalogs根元素

                   xmlw.writeStartElement("catalogs");

                   xmlw.writeNamespace("myNS", "http://blog.csdn.net/Lj");

                   xmlw.writeAttribute("owner", "Lj");

                   xmlw.writeCharacters("\n");

                   // 写入子元素catalog

                   xmlw.writeStartElement("http://blog.csdn.net/Lj", "catalog");

                   xmlw.writeAttribute("id", "007");

                   xmlw.writeCharacters("Apparel");

                   // 写入catalog元素的结束标签

                   xmlw.writeEndElement();

                   // 写入catalogs元素的结束标签

                   xmlw.writeEndElement();

                   // 结束XML 文档

                   xmlw.writeEndDocument();

                   xmlw.close();

         }

 

}

test.xml文件内容以下:

<?xml version="1.0" encoding="UTF-8"?>

<catalogs>

         <catalog id="001">Book</catalog>

         <catalog id="002">Video</catalog>

</catalogs>

运行上面程序后,控制台输出以下:

<catalogs>

         <catalog id="001">Book</catalog>

         <catalog id="002">Video</catalog>

</catalogs>

运行上面程序后,产生的output.xml文件以下:

<?xml version="1.0" ?>

         <!--testing comment-->

<catalogs xmlns:myNS="http://blog.csdn.net/Lj" owner="Lj">

         <myNS:catalog id="007">Apparel</myNS:catalog>

</catalogs>

3. 使用Compiler API

如今咱们能够用JDK6 的Compiler API(JSR 199)去动态编译Java源文件,Compiler API结合反射功能就能够实现动态的产生Java代码并编译执行这些代码,有点动态语言的特征。这个特性对于某些须要用到动态编译的应用程序至关有用, 好比JSP Web Server,当咱们手动修改JSP后,是不但愿须要重启Web Server 才能够看到效果的,这时候咱们就能够用Compiler API来实现动态编译JSP文件,固然,如今的JSP Web Server也是支持JSP热部署的,如今的JSP Web Server经过在运行期间经过Runtime.exec 或ProcessBuilder 来调用javac 来编译代码,这种方式须要咱们产生另外一个进程去作编译工做,不够优雅并且容易使代码依赖与特定的操做系统;Compiler API经过一套易用的标准的API提供了更加丰富的方式去作动态编译,并且是跨平台的。下面代码演示了Compiler API的使用

建立Compiler.java 和Hello.java

1.Compiler.java

import java.io.File;

 

import javax.tools.JavaCompiler;

import javax.tools.StandardJavaFileManager;

import javax.tools.ToolProvider;

 

public class Compiler {

         public static void main(String args[]) {

                   try {

                            JavaCompiler jc = ToolProvider.getSystemJavaCompiler();

                            StandardJavaFileManager sjfm = jc.getStandardFileManager(nullnullnull);

 

                            File javaFile = new File("Hello.java");

                            Iterable fileObjects = sjfm.getJavaFileObjects(javaFile);

                            jc.getTask(null, sjfm, nullnullnullfileObjects).call();

                            // Add more compilation tasks

                            sjfm.close();

                   } catch (Exception e) {

                            e.printStackTrace();

                   }

         }

}

2.Hello.java

import java.util.Date;

 

public class Hello {

         public String getHelloWorld() {

                   return "如今的时间为:" + new Date();

         }

}

编译运行便可,在工做目录下你会发现:Hello.class表示Compiler run OK.

4. 轻量级Http Server

JDK6 提供了一个简单的Http Server API,据此咱们能够构建本身的嵌入式Http Server,它支持Http 和Https 协议,提供了HTTP1.1的部分实现,没有被实现的那部分能够经过扩展已有的Http Server API来实现,程序员必须本身实现HttpHandler接口,HttpServer 会调用HttpHandler 实现类的回调方法来处理客户端请求,在这里,咱们把一个Http 请求和它的响应称为一个交换,包装成HttpExchange类,HttpServer负责将HttpExchange传给HttpHandler实现类的回调方法.下面代码演示了怎样建立本身的Http Server

import java.io.IOException;

import java.net.InetSocketAddress;

 

import com.sun.net.httpserver.HttpServer;

 

public class HTTPServerAPITester {

         public static void main(String[] args) {

                   try {

                            HttpServer hs = HttpServer.create(new InetSocketAddress(8888), 0);//设置HttpServer的端口为8888

                            hs.createContext("/lj", new MyHandler());//用MyHandler类内处理到/lj的请求

                            hs.setExecutor(null); // creates a default executor

                            hs.start();

                   } catch (IOException e) {

                            e.printStackTrace();

                   }

         }

 

}

 MyHandler类:

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

 

import com.sun.net.httpserver.HttpExchange;

import com.sun.net.httpserver.HttpHandler;

 

public class MyHandler implements HttpHandler {

         public void handle(HttpExchange t) throws IOException {

                   InputStream is = t.getRequestBody();

                   String response = "<***>Happy Every Day 2007!--lj</***>";

                   t.sendResponseHeaders(200, response.length());

                   OutputStream os = t.getResponseBody();

                   os.write(response.getBytes());

                   os.close();

         }

}

运行程序后,在浏览器内输入http://localhost:8888/lj,浏览器输出

Happy Every Day 2007!--lj

5. 用Console开发控制台程序

JDK6 中提供了java.io.Console 类专用来访问基于字符的控制台设备. 你的程序若是要与Windows 下的cmd 或者Linux 下的Terminal交互,就能够用Console类代劳. 但咱们不老是能获得可用的Console, 一个JVM是否有可用的Console依赖于底层平台和JVM如何被调用. 若是JVM是在交互式命令行(好比Windows的cmd)中启动的,而且输入输出没有重定向到另外的地方,那么就能够获得一个可用的Console实例。

下面代码演示了Console类的用法:

import java.io.Console;

 

public class ConsoleTest {

         public static void main(String[] args) {

                   Console console = System.console();//得到Console实例

                   if (console != null) {//判断console 是否可用

                            String user = new String(console.readLine("Enter user:")); //读取整行字符

                            String pwd = new String(console.readPassword("Enter passowrd:")); //读取密码,密码输入时不会显示

                            console.printf("User is:" + user + "\n");

                            console.printf("Password is:" + pwd + "\n");

                   } else {

                            System.out.println("Console is unavailable");

                   }

         }

}

若是在eclipse里面运行上面程序,会输出

Console is unavailable

表示Console 不可得到,那是由于JVM 不是在命令行中被调用的或者输入输出被重定向了. 可是若是咱们在命令行中运行上面程序(java ConsoleTest),程序可以得到Console实例,并执行以下:

在这里能够看到输入密码时,控制台时不显示这些密码字符的,可是程序能够获得输入的密码字符串,这与Linux下面输入密码的状况是同样的。

6. Common Annotations

Common annotations 本来是Java EE 5.0(JSR 244)规范的一部分,如今SUN 把它的一部分放到了Java SE 6.0 中.随着Annotation元数据功能(JSR 175)加入到Java SE 5.0里面,不少Java 技术(好比EJB,Web Services)都会用Annotation部分代替XML 文件来配置运行参数(或者说是支持声明式编程,如EJB的声明式事务), 若是这些技术为通用目的都单独定义了本身的Annotations,显然有点重复建设, 因此,为其余相关的Java 技术定义一套公共的Annotation是有价值的,能够避免重复建设的同时,也保证Java SE和Java EE 各类技术的一致性.

下面列举出Common Annotations 1.0里面的10个Annotations

Common Annotations

Annotation Retention Target Description

Generated Source ANNOTATION_TYPE, CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER,TYPE用于标注生成的源代码

Resource Runtime TYPE, METHOD, FIELD 用于标注所依赖的资源,容器据此注入外部资源依赖,有基于字段的注入和基于setter方法的注入两种方式

Resources Runtime TYPE 同时标注多个外部依赖,容器会把全部这些外部依赖注入

PostConstruct Runtime METHOD 标注当容器注入全部依赖以后运行的方法,用来进行依赖注入后的初始化工做,只有一个方法能够标注为PostConstruct

PreDestroy Runtime METHOD 当对象实例将要被从容器当中删掉以前,要执行的回调方法要标注为PreDestroy

RunAs Runtime TYPE 用于标注用什么安全角色来执行被标注类的方法,这个安全角色必须和Container 的Security 角色一致的

RolesAllowed Runtime TYPE, METHOD 用于标注容许执行被标注类或方法的安全角色,这个安全角色必须和Container 的Security角色一致的

PermitAll Runtime TYPE, METHOD 容许全部角色执行被标注的类或方法

DenyAll Runtime TYPE, METHOD 不容许任何角色执行被标注的类或方法,代表该类或方法不能在Java EE容器里面运行

DeclareRoles Runtime TYPE 用来定义能够被应用程序检验的安全角色,一般用isUserInRole来检验安全角色

注意:

1.RolesAllowed,PermitAll,DenyAll不能同时应用到一个类或方法上

2.标注在方法上的RolesAllowed,PermitAll,DenyAll会覆盖标注在类上的RolesAllowed,PermitAll,DenyAll

3.RunAs,RolesAllowed,PermitAll,DenyAll和DeclareRoles尚未加到Java SE 6.0上来

4.处理以上Annotations的工做是由Java EE 容器来作, Java SE 6.0只是包含了上面表格的前五种Annotations的定义类,并无包含处理这些Annotations的引擎,这个工做能够由Pluggable Annotation Processing API(JSR 269)来作

7. Web服务元数据(Web Services metadata)

JSR-181的元数据清单

下面介绍JSR-181里面各个元数据的相关参数及用途

Annotation Retention Target Description

WebService Runtime Type标注要暴露为Web Services 的类或接口

WebParam Runtime Parameter 自定义服务方法参数到WSDL的映射

WebResult Runtime Method 自定义服务方法返回值到WSDL的映射

WebMethod Runtime Method 自定义单个服务方法到WSDL的映射

Oneway Runtime Method 必须与@WebMethod连用,代表被标注方法只有输入没有输出,这就要求被标注方法不能有返回值,也不能声明checked exception

HandlerChain Runtime Type,Method,Field 将Web 服务与外部Handler chain 关联起来

SOAPBinding Runtime Type,Method 自定义SOAPBinding

JSR-181元数据使用示例

package WebServices;

 

import javax.jws.Oneway;

import javax.jws.WebMethod;

import javax.jws.WebParam;

import javax.jws.WebResult;

import javax.jws.WebService;

import javax.xml.ws.Endpoint;

 

@WebService(targetNamespace = "http://blog.csdn.net/lj", serviceName = "HelloService")

public class WSProvider {

         @WebResult(name = "Greetings")

         //自定义该方法返回值在WSDL中相关的描述

         @WebMethod

         public String sayHi(@WebParam(name = "MyName") String name) {

                   return "Hi," + name; //@WebParam是自定义参数name在WSDL 中相关的描述

         }

 

         @Oneway

         //代表该服务方法是单向的,既没有返回值,也不该该声明检查异常

         @WebMethod(action = "printSystemTime", operationName = "printSystemTime")

         //自定义该方法在WSDL中相关的描述

         public void printTime() {

                   System.out.println(System.currentTimeMillis());

         }

 

         public static void main(String[] args) {

                   Thread wsPublisher = new Thread(new WSPublisher());

                   wsPublisher.start();

         }

 

         private static class WSPublisher implements Runnable {

                   public void run() {

                            //发布WSProvider 到http://localhost:8888/lj/WSProvider这个地址,以前必须调用wsgen命令

                            //生成服务类WSProvider的支持类,命令以下:

                            //wsgen -cp . WebServices.WSProvider

                            Endpoint.publish("http://localhost:8888/lj/WSProvider", new WSProvider());

                   }

         }

}

若是想看到Web Services Engine生成的WSDL文件是否遵照上面的元数据, 咱们没有必要将上面的WSProvider部署到支

持JSR-181的应用服务器或Servlet形式的Web Services Engine,如今JDK6已经提供了一个很简单的机制能够用来测试和发

布Web Services,下面讲讲如何在JDK6环境下发布Web Services和查看生成的WSDL

1.将<JDK_HOME>/bin加入path环境变量

2. 执行以下代码发布WSProvider到http://localhost:8888/lj/WSProvider,在这里能够执行WSProvider类的main方法就能够.

在这个例子中会生成如下3个类的源代码文件及class文件

SayHi

SayHiResponse

PrintTime

3.在浏览器输入http://localhost:8888/lj/WSProvider?wsdl就能够看到生成的WSDL文件,以下图,你们能够本身动手试试。

8. 更简单,更强大的JAX-WS

JAX-WS2.0的来历

JAX-WS(JSR-224) 是Java Architecture for XML Web Services的缩写,简单说就是一种用Java和XML开发Web Services应用程序的框架, 目前版本是2.0, 它是JAX-RPC 1.1的后续版本, J2EE 1.4 带的就是JAX-RPC1.1, 而Java EE 5里面包括了JAX-WS 2.0,但为了向后兼容,仍然支持JAX-RPC. 如今,SUN 又把JAX-WS 直接放到了Java SE 6里面,因为JAX-WS 会用到

Common Annotation(JSR 250),Java Web Services Metadata(JSR 181), JAXB2(JSR 222), StAX(JSR 173), 因此SUN也必须把后几个原属于Java EE范畴的Components下放到Java SE, 如今咱们能够清楚地理解了为何Sun要把这些看似跟JavaSE没有关系的Components放进来,终极目的就是要在Java SE里面支持Web Services.

JAX-WS2.0的架构

JAX-WS不是一个孤立的框架,它依赖于众多其余的规范,本质上它由如下几部分组成

1.用来开发Web Services的Java API

2.用来处理Marshal/Unmarshal的XML Binding机制,JAX-WS2.0用JAXB2来处理Java Object与XML之间的映射,Marshalling就是把Java Object 映射到XML,Unmarshalling则是把XML映射到Java Object.之因此要作Java Object与XML的映射,是由于最终做为方法参数和返回值的Java Object要经过网络传输协议(通常是SOAP)传送,这就要求必须对Java Object作相似序列化和反序列化的工做,在SOAP中就是要用XML来表示Java object的内部状态

3.众多元数据(Annotations)会被JAX-WS 用来描述Web Services 的相关类,包括Common Annotations, Web Services Metadata, JAXB2的元数据和JAX-WS2.0规范本身的元数据.

4.Annotation Processing Tool(APT)是JAX-WS重要的组成部分,因为JAX-WS2.0规范用到不少元数据,因此须要APT 来处理众多的Annotations.在<JDK_HOME>/bin 下有两个命令wsgen 和wsimport,就是用到APT 和Compiler API 来处理碰到的Annotations,wsgen能够为Web Services Provider产生并编译必要的帮助类和相关支持文件,wsimport以WSDL做为输入为Web Service Consumer 产生并编译必要的帮助类和相关支持文件.

5.JAX-WS还包括JAX-WS Runtime与应用服务器和工具之间的契约关系

JAX-WS2.0的编程模型

如今用JAX-WS2.0 来编写Web Services 很是简单,不像JAX-RPC,JAX-WS 能够把任意POJO暴露为Web Services,服务类不须要实现接口,服务方法也没有必要抛出RMI异常.下面介绍在JDK6环境下用JAX-WS2.0开发和测试Web Services的步骤

1.编写服务类,并用Web Services Metadata(JSR-181)标注这个服务类,用Web 服务元数据中的WSProvider类做为服务类的例子,源代码可见上文。

2.用wsgen生成上面服务类的必要的帮助类,而后调用用EndPoint类的静态方法publish发布服务类(请参考Web服务元数据),我在这里是将服务类发布到http://localhost:8888/lj/WSProvider

3.用wsimport为服务消费者(也就是服务的客户端)生成必要的帮助类,命令以下:

wsimport http://localhost:8888/lj/WSProvider?wsdl

这会在<当前目录>\net\csdn\blog\lj下生成客户端的帮助类,在这个例子中会生成7个类

HelloService.class

ObjectFactory.class

package-info.class

PrintSystemTime.class

SayHi.class

SayHiResponse.class

WSProvider.class

4.在客户端用下面代码便可调用步骤1定义的Web Service

HelloService hs = new HelloService();

WSProvider ws = hs.getWSProviderPort();

System.out.println(ws.sayHi("lj"));

ws.printSystemTime();

调用上述代码后客户端控制台输出

hi,lj

服务端控制台输出服务器当前系统时间

9. 脚本语言支持(Scripting)

概述

JDK6增长了对脚本语言的支持(JSR 223),原理上是将脚本语言编译成bytecode,这样脚本语言也能享用Java平台的诸多优点,包括可移植性,安全等,另外,因为如今是编译成bytecode 后再执行,因此比原来边解释边执行效率要高不少。加入对脚本语言的支持后,对Java语言也提供了如下好处。

一、许多脚本语言都有动态特性,好比,你不须要用一个变量以前先声明它,你能够用一个变量存放彻底不一样类型的对象,你不须要作强制类型转换,由于转换都是自动的。如今Java语言也能够经过对脚本语言的支持间接得到这种灵活性。

二、能够用脚本语言快速开发产品原型,由于如今能够Edit-Run,而无需Edit-Compile-Run,固然,由于Java 有很是好的IDE 支持,咱们彻底能够在IDE 里面编辑源文件,而后点击运行(隐含编译),以此达到快速开发原型的目的,因此这点好处基本上能够忽略。

三、经过引入脚本语言能够轻松实现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 两个接口。固然,在你实现本身的脚本语言引擎以前,先到scripting.dev.java.net project 这里看看是否是有人已经帮你作了工做,这样你就能够直接拿来用就行。

Scripting API

Scripting API是用于在Java 里面编写脚本语言程序的API, 在Javax.script 中能够找到Scripting API,咱们就是用这个API来编写JavaScript程序,这个包里面有一个ScriptEngineManager 类,它是使用Scripting API的入口,ScriptEngineManager能够经过jar 服务发现(service discovery)机制寻找合适的脚本引擎类(ScriptEngine),使用Scripting API的最简单方式只需下面三步

一、建立一个ScriptEngineManager 对象

二、经过ScriptEngineManager得到ScriptEngine对象

三、用ScriptEngine的eval方法执行脚本

下面是一个Hello World 程序

import javax.script.ScriptEngine;

import javax.script.ScriptEngineManager;

 

public class HelloScript {

         public static void main(String[] args) throws Exception {

                   ScriptEngineManager factory = new ScriptEngineManager();//step 1

                   ScriptEngine engine = factory.getEngineByName("JavaScript");//Step 2

                   engine.eval("print('Hello, Scripting')");//Step 3

         }

}

运行上面程序,控制台会输出Hello, Scripting上面这个简单的Scripting程序演示了如何在Java里面运行脚本语言,除此以外,咱们还能够利用Scripting API实现如下功能

一、暴露Java对象为脚本语言的全局变量

二、在Java中调用脚本语言的方法

三、脚本语言能够实现Java的接口

四、脚本语言能够像Java同样使用JDK平台下的类。

下面的类演示了以上4种功能

package Scripting;

 

import java.io.File;

 

import javax.script.Invocable;

import javax.script.ScriptEngine;

import javax.script.ScriptEngineManager;

import javax.script.ScriptException;

 

public class ScriptingAPITester {

         public static void main(String[] args) throws Exception {

                   ScriptEngineManager manager = new ScriptEngineManager();

                   ScriptEngine engine = manager.getEngineByName("JavaScript");

                   testScriptVariables(engine);//演示如何暴露Java对象为脚本语言的全局变量

                   testInvokeScriptMethod(engine);//演示如何在Java中调用脚本语言的方法

                   testScriptInterface(engine);//演示脚本语言如何实现Java的接口

                   testUsingJDKClasses(engine);//演示脚本语言如何使用JDK平台下的类

         }

 

         public static void testScriptVariables(ScriptEngine engine) throws ScriptException {

                   File file = new File("test.txt");

                   engine.put("f", file);

                   engine.eval("println('Total Space:'+f.getTotalSpace())");

         }

 

         public static void testInvokeScriptMethod(ScriptEngine engine) throws Exception {

                   String script = "function hello(name) { return 'Hello,' + name;}";

                   engine.eval(script);

                   Invocable inv = (Invocable) engine;

                   String res = (String) inv.invokeFunction("hello", "Scripting");

                   System.out.println("res:" + res);

         }

 

         public static void testScriptInterface(ScriptEngine engine) throws ScriptException {

                   String script = "var obj = new Object(); obj.run = function() { println('run method called'); }";

                   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();

         }

 

         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");

         }

}

Scripting Tool

SUN 提供的JDK6 中有一个命令行工具??jrunscript,你能够在<JDK6_Home>/bin 下面找到这个工具,jrunscript 是一个脚本语言的解释程序,它独立于脚本语言,但默认是用JavaScript,咱们能够用jrunscript来测试本身写的脚本语言是否正确,下面是一个在命令行运行jrunscript 的简单例子。以下图:

 
相关文章
相关标签/搜索