天天看點

JDK6的新特性之十一:更簡單,更強大的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要把這些看似跟Java SE沒有關系的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)标注這個服務類,我用 我的另一篇Blog JDK6的新特性之十:Web服務中繼資料 中的WSProvider類作為服務類的例子,在此我重複貼一下 WSProvider 類的源代碼:

@WebService(targetNamespace="http://blog.csdn.net/chinajash",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/chinajash/WSProvider這個位址,之前必須調用wsgen指令

            //生成服務類WSProvider的支援類,指令如下:

            //wsgen -cp . WebServices.WSProvider

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

        }       

    }

}

2.用wsgen生成上面服務類的必要的幫助類,然後調用用EndPoint類的靜态方法publish釋出服務類(步驟請參考我的另一篇Blog JDK6的新特性之十:Web服務中繼資料),我在這裡是将服務類釋出到 http://localhost:8888/chinajash/WSProvider

3.用wsimport為服務消費者(也就是服務的用戶端)生成必要的幫助類,指令如下:

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

這會在 <目前目錄>/net/csdn/blog/chinajash下生成用戶端的幫助類,在這個例子中會生成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("chinajash"));

ws.printSystemTime();

調用上述代碼後用戶端控制台輸出

hi,chinajash

服務端控制台輸出伺服器目前系統時間