隨着近幾年來,SOA,EAI等架構體系的日漸成熟,Webservice愈來愈熾手可熱,尤爲是在企業作異質平臺整合時成爲了首選的技術。java
Java的Webservice技術更是層出不窮,比較流行的有:node
Axis2,Spring WS以及Jaxws。web
本人在平常工做和以往工程中,在使用了上述這些Webservice後進行了總結,比較,最終以爲jaxws是目前最標準,須要額外第三方插件最少,配置最少最靈活的webservice。編程
JAXWS適合幾乎全部Webservice客戶端的調用,所以很多巨頭型的廠商如:IBM,Weblogic等,在他們的產品上都使用了以JAXWS爲標準的Webservice接口。tomcat
本教程分紅五天,爲初級教程。安全
經過本教程,可使一個沒有Webservice概念或者沒有寫過Webservice的JAVA Resource快速上手入門,並能知足通常中小型項目中Webservice的應用。服務器
對於Webservice Security,在(初級)教程中並不提供,會在高級教程中詳細描述。session
不過真正利用Webservice Security特性即XML加密技術的工程並很少,少之又少,大多仍是以http: //xxx/xxxService?userId=&password=這樣的形式來進行「假安全」通信的。數據結構
必經咱們的大部分項目是運行在Intranet裏的,並且有很好的監控和佈防。架構
下面開始咱們的教程。
目標:
1. 理解jaxws
2. 寫jaxws以前的準備工做
3. 一切始於HelloWorld
4. 理解同步,異步
JAX-WS2.0 的全稱爲 Java API for XML-Based Webservices (JAX-WS) 2.0。JAX-WS 2.0 是對 JAX-RPC 1.0 規範的擴展,是 JAX-RPC 1.1 的後續版本, JAX-RPC 2.0 標準發佈不久後便被從新命名爲 JAX-WS 2.0。 JAX-WS 2.0 是面向 Java 5 的開發 Web services 的最新編程標準,它提供了新的編程模型和對以往的 JAX-RPC 方式的 Web services 進行了加強。 JAX-WS2.0 (JSR 224)是Sun新的web services協議棧,是一個徹底基於標準的實現。在binding層,使用的是the Java Architecture for XMLBinding (JAXB, JSR 222),在parsing層,使用的是the Streaming API for XML (StAX, JSR 173),同時它還徹底支持schema規範。
支持SOAP 1.1(默認)、1.2
支持XML/HTTP Binding
支持WS-Addressing
支持document/literal樣式
支持WS-I Basic Profile 1.1
支持消息傳輸優化機制(Message Transmission Optimization Mechanism,MTOM)
JAX-WS RI組件下載後爲一個」.jar」文件,它並不能直接在工程中使用,它是一個以JAVA Swing爲界面的JAXWS的安裝程序包。
咱們須要打開一個命令行窗口,並輸入:
輸入完這條命令後,你會獲得一個安裝界面以下:
下一步,下一步完成安裝後你會獲得這樣的一個目錄:
這個目錄裏有咱們寫JAXWS所需的全部lib包以及JAXWS自帶的教程。
能夠看到咱們這個目錄除傳統的src,WebContent目錄外還有幾個目錄,它們分別是:
? build
? wsdl
? wssrc
咱們來書寫咱們的第一個Webservice吧,它的名字叫Hello(Come on, 老套了,又來了)。
package ctsjavacoe.ws.fromjava;
import javax.jws.WebMethod; import javax.jws.WebService;
public class Hello { @WebMethod public String say(String name) { return ("Hello: "+name); } } |
注意:
註釋在了Class之上,這告訴了JAXWS,此類爲Webservice。
@WebMethod
註釋在了public方法上,這告訴了JAXWS,此方法爲soap方法,該方法有兩個參數,一個input的String,一個output的String。
業務邏輯很簡單,客戶端調用傳入一個Name,服務端返回給客戶端一個」Hello: 「+name的字串。
如今咱們經過Java文件來生成Webservice相關佈署文件以及調用接口。
JAX-WS 2.0 有兩種開發過程:自頂向下和自底向上。自頂向下方式指經過一個 WSDL 文件來建立Web Service,自底向上是從 Java 類出發建立 Web Service。兩種開發過程最終造成的文件包括:
1.SEI。一個SEI對應WSDL中WebService的一個port,在Java中是一個Java接口。
2.SEI實現類。
3.WSDL和XSD文件。
結合公司內項目的特色,咱們更多的是碰到如下兩種狀況:
1. Onsite要咱們作一個Webservice或者是客戶要求咱們提供Webservice接口;
2. Onsite已經有一個Webservice了,如今要咱們作客戶端集成。
所以,咱們選用Server端經過Java Class生成webservice,而客戶端經過wsdl生成Java調用類的作法。
JAXWS爲咱們提供了兩個工具:
ü wsgen
主要用於Server端經過Java類編譯成Webservice及相關的wsdl文件
ü wsimport
主要用於Client端(調用端)經過wsdl編譯出調用Server端的Java文件
咱們就來生成一下上面的這個Hello,打開一個command窗口,鍵入以下命令:
-wsdl參數表明生成webservice
- s參數表明生成的.java文件置於何處
-d 參數表明生成的編譯class文件置於何處(這個能夠忽略,咱們利用eclipse編譯)
-r 參數表明生成的.wsdl文件與.xsd文件生成在何處
-cp參數表明classpath,即Hello.class的所在,爲何咱們的-cp後是這麼長一個路徑呢?請看Eclipse裏工程編譯輸出目錄的路徑就知道了:
好,咱們如今回到eclipse工程裏,刷新一下工程:
看 到在wssrc目錄下已經生成了咱們所需的java文件了,請手工cut(對,是cut)這些文件到咱們工程的」src」目錄,若是不cut,下次繼續使 用該目錄生成webservice類時,wsgen有時會生成不了,但也不報錯,不知道爲何,查了一下,多是一個bug,因該會在後續的 jdk1.6.30up裏改進。
這裏咱們有兩個文件,一個是wsdl文件,這個就是咱們的webservice的entry,一個是xsd文件,這個是什麼?
這個就是咱們java的方法裏的參數的對應,或者換句話說,它就是xml格式的java bean,在webservice的世界裏,xsd是做爲數據結構描述用的。
如今咱們的webservice的服務端有了。
佈署前的準備:
在工程的WEB-INF目錄下創建「sun-jaxws.xml」文件,內容以下:
<?xml version="1.0" encoding="UTF-8"?> <endpoints xmlns='http://java.sun.com/xml/ns/jax-ws/ri/runtime' version='2.0'> <endpoint name='Hello' implementation='ctsjavacoe.ws.fromjava.Hello' url-pattern='/HelloService' /> </endpoints> |
將ctsjavacoe.ws.fromjava.Hello聲明爲Web Service。
若是是從WSDL生成的Web Service,則寫法爲,
<?xml version="1.0" encoding="UTF-8"?> <endpoints version="2.0" xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime"> <endpoint implementation="ctsjavacoe.ws.fromjava.HelloSEI" name="Hello" url-pattern="/HelloService" /> </endpoints>
|
修改WEB-INF目錄下的web.xml文件,增長以下內容:
<servlet> <servlet-name>Hello</servlet-name> <servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class> <load-on-startup>2</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Hello</servlet-name> <url-pattern>/HelloService</url-pattern> </servlet-mapping> |
爲每個WebService聲明一個com.sun.xml.ws.transport.http.servlet.WSServlet。
開始佈署:
1. 在tomcat的webapps目錄下創建一個目錄叫「D:\tomcat2\webapps\JaxWSSample」
2. 把eclipse工程JaxWSSample下WebContent目錄下全部的東西copy至該目錄下
3. 重啓tomcat
在ie中輸入:
http://localhost:9090/JaxWSSample/HelloService?wsdl
能夠看到咱們的webservice已經生成了。
同步調用,很好理解,即一來一回,Client端request到Server端,Sever端馬上回一個response。
異步調用,就是客戶端調用一次服務端後,服務端處理事務並非即時返回的,好比說傳一個600MB文件給服務端,服務端在處理接收和解析文件時,客戶端不會立刻獲得一個響應,它會等待一段時間,等服務器處理完後,再通知客戶端「我處理完了」。
咱們新建一個eclipse的工程,只須要是JAVA工程就好了,不須要web工程的,由於咱們這邊只用代碼作調用:
把Server端的wsdl及xsd都手工copy到客戶端工程的wsdl目錄下。
打開一個cmd窗口敲入以下的命令:
wsimport -keep -d bin -s src wsdl/HelloService.wsdl |
以上是產生同步客戶端的命令。
若是要產生異步客戶端命令,須要在工程根目錄下建一個binding.xml的文件,內容以下:
<?xml version="1.0" encoding="UTF-8"?> <bindings xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" wsdlLocation="wsdl/HelloService.wsdl" xmlns="http://java.sun.com/xml/ns/jaxws"> <bindings node="wsdl:definitions"> <enableAsyncMapping>true</enableAsyncMapping> </bindings> </bindings> |
而後產生客戶端代碼的wsimport命令也會不同:
wsimport -keep –b binding.xml -d bin -s src wsdl/HelloService.wsdl |
咱們來看異步調用的代碼(同步代碼比異步調用簡單,留給你們本身作練習)
wsimport命令會在eclipse工程的src目錄中生成你在調用時所用的java src文件。
Hello.java與HelloService.java是wsimport給咱們生成的供客戶端調用的java文件。
咱們把HelloService文件打開,能夠看到兩行:
file:/D:/workspace/JaxWSClient/wsdl/HelloService.wsdl |
把它們改爲:
http://localhost:9090/JaxWSSample/HelloService?wsdl |
有兩行,尤爲是Url url=這一行,千萬不要漏改了。
咱們建立一個調用類,叫:HelloAsyncPollingClient.java文件,內容以下:
package ctsjavacoe.ws.fromjava;
import javax.xml.ws.Response;
public class HelloAsyncPollingClient {
/** * @param args */ public static void main(String[] args) throws Exception { HelloService service = new HelloService(); Hello port = service.getHelloPort(); Response<SayResponse> sayAsync = port.sayAsync("Mk"); while (!sayAsync.isDone()) { System.out.println("is not down"); } try { SayResponse callNameResponse = sayAsync.get(); String message = callNameResponse.getReturn(); System.out.println(message); } catch (Exception ex) { } }
} |
運行,獲得結果以下:
在舊的基於JAX-RPC的webservice編程model中,是不支持異步的service 調用的,在最新的Jax-ws webservice 編程model中,加入了對webservice的異步調用的支持。
首 先我來說一下它的原理,你們不要覺得在異步的調用下,從client到server 之間的soap message 流也是異步的,其實不是,Soap/Http 協議在同步跟異步的調用下是同樣的,都是客戶端的service在運行時打開一個connectin,發送請求,而後接收返回,這些都在同一個 connection中。這種方式對咱們有什麼影響呢?從客戶端程序的角度來說,沒有影響,客戶端的編程模型是由WSDL中的messages跟port types 來定義的,只要這些東西沒有改變,request 跟response是否是在同一個Tcp/ip 的session 中來發送對與咱們來講沒由影響,而後從架構跟資源的角度來說,對咱們的影響就大了,把鏈接層的資源跟應用層的程序運行狀態綁定起來是由許多弊端的,假如在 異步調用時,程序運行出現了異常,將會致使鏈接層的資源被一直佔用,這樣會極大的影響咱們程序的,穩定性,可靠性,資源的使用跟性能。
上例中實現的是一種「polling方式的異步調用」,下面給出「callback」方式的異步調用客戶端。
因爲此callBack當請求發出去之後當前的這個connection就會關閉 ,爲了達到測試的目的,加入了sleep,讓客戶端程序等待服務器端得返回。
callback類型的client要傳入一個javax.xml.ws.AsyncHandler類型的匿名內部類,當soapMessage 到達時,Jax-ws會調handleResponse這個方法來處理response.
客戶端測試代碼以下:
package ctsjavacoe.ws.fromjava; import javax.xml.ws.AsyncHandler; import javax.xml.ws.Response; public class HelloAsyncCallBackClient { public static void main(String[] args) throws Exception { HelloService service = new HelloService(); Hello port = service.getHelloPort(); port.sayAsync("Mk", new AsyncHandler<SayResponse>() { public void handleResponse(Response<SayResponse> res) { try { SayResponse response = null; response = res.get(); String message = response.getReturn(); System.out.println(message); } catch (Exception e) { e.printStackTrace(); } } }); Thread.sleep(1000); } } |