在過去的幾個月里,Sun公司已經為Java平台的第6個版本(Java Platform Standard Edition 6)提供了二進位安裝文件,Java文檔和Java源代碼,就是知名的「野馬」.而且這飛馳的野馬要拉住你這車並不算晚.
一個顯而易見的問題是,「為什麼我應該關心?」對於這些質疑者,Java SE 6提升的性能包括擴平台性,從開放的程序管理到Java編譯器,到系統底層和屏幕組件,到在你的源代碼中混合腳本語言(支持JavaScript),到Swing的整潔的外觀,到XML數字簽名,到智能卡I/O API,到JMX監聽線程的升級,為Web服務的服務提供者使用Annotations註釋和更加簡單的客戶端管理——在我們要關心的時候,這些名字僅僅是這個平台中的一小部分新功能.(java.net站點提供了關於J2SE 6平台中所有的新功能.)
這篇文章中,我們僅僅關注Java SE 6中對於Web Services規範的升級以及JAX-WS(Java API for XML Web Services)2.0規範,這些升級是的我們Web Services的創建和調用變得更加容易.使用這些新功能,我們可以僅僅使用簡單的Annotations註釋從一個Java類創建Web Services;隨後,我們在調用這個服務的時候使用JAX-WS2.0.我們同樣可以給這個服務添加一個管理者用來截取這個服務調用而且將截取的SOAP消息傳輸到System.out從控制台列印出來.
事實上,這些功能曾在JSR181(Java Specification Request 181)和JSR224 (JAX-WS)規範中已經被認可了,只是Java的正式版本擁有這些功能使它更加主流;我們同樣期待Java IDE開發平台可以對這些功能進行良好的支持.
JavaEE5規範中,允許基於標準規範讓應用程序開發人員為Web Services提供服務端平台,JSR181和JSR224就是JavaEE5規範中的一部分.理論上講,若在不改變源代碼使用支持這些相同規範的應用程序伺服器,在Java SE 6環境中大規模地發布工程這些功能將會破壞早期的Web Services應用程序,這個最初是不希望的.
我們的「野馬」Web Service:服務端和客戶端
在我們穩定這匹野馬之前,我們先下載這篇文中重提及的zip文件,它主要包括下邊四個文件:
mustangws.zip包括了這篇文章中提及的Web Service服務端應用程序源代碼,構建文件和腳本文件.
mustangwsclient.zip包括了客戶端的源代碼,構建文件和腳本文件.
mustangws.jar包含了已經編譯過的服務端應用程序.
mustangwsclient.jar包含了已經編譯過的客戶端程序.
注意:你需要Java SE 6和Apache Ant這兩個軟體來運行這篇文章中的例子.
在你解壓之後,你將會看到兩個文件架,mustangws 和mustangwsclient,這兩個文件架內分別是Web Services的服務端和客戶端.兩個項目裡面都有同樣的src文件夾,裡面包含了Java的源文件和Apache Ant軟體需要的構建文件build.xml.這裡還有附加的wsgenMustang.bat 和wsimportMustang.bat兩個批處理文件,裡面包含了生成Web Services存根的控制台命令,我們將在下邊的章節中講到.Apache Ant的build.xml文件對於兩個應用程序而言都是放在mustangws 和mustangwsclient兩個根目錄中的.兩個文件中有同樣的ant任務init,compile,dist,clean和run.
HelloServer
Bootstrap
TraceHandler
HelloException
Person
package com.techyatra.hellows;
@WebService(name="HelloServer",targetNamespace=http://mustangws.techyatra.com/
, serviceName="HelloService")
@SOAPBinding(style=SOAPBinding.Style.RPC)
public class HelloServer
{
@WebMethod(operationName="hello", action="urn:hello")
public@WebResult(partName="result")String ping(@WebParam(partName="person",
mode=Mode.IN,targetNamespace="http://mustangws.techyatra.com/") Person person)
throws HelloException
{
if (person == null)
{
System.out.println("function: hello(null)... throwing exception");
throw new HelloException("0001", "Person is null");
}
else
{
System.out.println("function: hello(person.getTitle()
person.getName())");
return "Hello. " person.getTitle() person.getName() "!";
}
}
}
在上邊的代碼中,@WebService註釋是的類MustangServer實現了Web Service,而且@WebMethod標識類中ping方法作為WebService的操作,ping除開返回greeting的值就不會做其他的事情.
需要注意的是:不管你願意不願意,你都不能任意地將Annotation用於任何一個Java類和函數使其暴露為一個WebService和一個WebService操作.Java類若要成為一個實現了WebService的bean,它需要遵循下邊這些原則:
這個類必須是public類
這些類不能是final的或者abstract
這個類必須有一個公共的默認構造函數
這個類絕對不能有finalize()方法
若要成為一個實現了WebService的Bean這個Java類必須遵循這些原則:
這個類必須是public,它的參數、返回值、和異常在每個JAX RPC規範中都描述了Java轉化成XML/WSDL映射文件的規則等等.參數和返回值可以是原始類型、數組等等;異常都可以繼承Exception;請查閱Java API去看基於XML的遠程調用可以知道更多的信息.
現在我們已經擁有了合理規範,讓我們接近代碼來看看WebService Annotation的作用.注意:這篇文章不是描述所有Annotation 和所有的WebService Metadat規範裡面的所有成員.如果要了解細節自己去查閱JSR 181規範.
這裡有各種類型的Annotation.@WebService和@WebMethod是WSDL映射Annatotion.這些Annotation將描述Web Service的WSDL文檔元素和Java源代碼聯繫在一起.@SOAPBinding是一個綁定的annotation用來說明網路協議和格式.
@WebService annotation的元素name,serviceName和targetNamespace成員用來描述wsdl:portType,wsdl:service,和targetNameSpace生成WebService中的WSDL文件.
@SOAPBinding是一個用來描述SOAP格式和RPC的協議的綁定Annotation.
@WebMethod Annotation的operationName成員描述了wsdl:operation,而且它的操作描述了WSDL文檔中的SOAPAction頭部.這是客戶端必須要放入到SQAPHeader中的數值,SOAP 1.1中的一種約束.
@WebParam Annotation的partName成員描述了WSDL文檔中的wsdl:part.
@WebResult Annotation的partName成員描述了wsdl:part用來返回WSDL文檔的值.
HelloException類是一個含有屬性description和錯誤代碼的異常類,Person是一個只有lastname和firstname 屬性的簡單類.這些類都沒有被任何Annotation註釋過.
我們在HelloException中使用@WebFault確實很誘人,可是並非如此!Annotation是被wsgen用來生成異常bean.更加有趣的是,這個不是JSR 181規範中的一部分,但是是JAX-RPC 1.1中的一部分.
/*
* TraceHandler.java
* @author shahga
*/
package com.techyatra.hellows;
...
public class TraceHandler implements SOAPHandler<SOAPMessageContext>
{
...
public boolean handleMessage(SOAPMessageContext messageContext)
{
trace(messageContext);
return true;
}
public boolean handleFault(SOAPMessageContext messageContext)
{
trace(messageContext);
return true;
}
...
private void trace(SOAPMessageContext messageContext)
{
Boolean outMessageIndicator = (Boolean)
messageContext.get (MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outMessageIndicator.booleanValue())
{
System.out.println("nOutbound SOAP:");
}
else
{
System.out.println("nInbound SOAP:");
}
SOAPMessage message = messageContext.getMessage();
try
{
message.writeTo(System.out);
System.out.println("");
}
catch (Exception exp)
{
System.out.println("Exception in TraceHandler:trace(messageContext) : "
exp);
}
}
}
TraceHandler實現了javax.xml.ws.handler.SOAPHandler< c extends MessageContext> 介面.方法handleMessage()和handleFault()將未綁定和沒有綁定的SOAP消息傳輸到System.out管道.這個功能提供給SOAPMessageContext,這部分聚合了所有SOAP消息,它包含了各種消息屬性和SOAP消息本身.
現在我們有一個準備好了操作者的WebService,我們應該如何包裝和部署這樣的服務呢?這個服務打包成下邊我們要討論的一個jar文件,但是看起來更加興奮.
Boostrap
在JavaSE6種,你將會看到javax.xml.ws包裡面包含了終端類,這些專門用來在JVM中部署WebService.當然,聽起來很正確!不需要任何伺服器.正好利用終端類創建一個服務實例,就像下邊顯示的Bootstrap類一樣.終端是用於小的應用程序的,應用伺服器消耗是不合理的,這裡是僅僅用作發布目的.
package com.techyatra.hellows;
...
public class Bootstrap
{
...
public static void main (String [] args) throws Exception
{
HelloServer server = new HelloServer();
Endpoint endpoint = Endpoint.publish(http://localhost:9090/HelloServer,
server);
Binding binding = endpoint.getBinding();
List<Handler> handlerChain = new LinkedList<Handler>();
handlerChain.add(new com.techyatra.hellows.TraceHandler());
binding.setHandlerChain(handlerChain);
}
}
package com.techyatra.helloclient;
public class Client
{
public static void main(String[] args) throws Exception
{
...
if (args[0].equals("jax"))
{
com.techyatra.helloclient.jax.Person person =
new com.techyatra.helloclient.jax.Person();
person.setTitle(args[1]);
person.setName(args[2]);
JAXClient jaxClient = new JAXClient();
jaxClient.invoke(person);
}
}
}
package com.techyatra.helloclient;
import com.techyatra.helloclient.jax.*;
public class JAXClient
{
...
public void invoke(Person person) throws Exception
{
HelloService service = new HelloService();
HelloServer server = (HelloServer) service.getHelloServerPort();
String ret = server.hello(person);
System.out.println(ret);
}
}
[火星人 ] Java SE 6 Web Service 之旅已經有645次圍觀