很多新手一聽到接口就蒙逼,不知道接口是什麼!其實接口就是RPC,通過遠程訪問別的程序提供的方法,然後獲得該方法執行的接口,而不需要在本地執行該方法。就是本地方法調用的升級版而已,我明天會上一篇如何通過socket實現rpc,以及服務的注冊和動態上下線。這裡先上一篇RPC的實現者一webservice,便於後面理解源碼執行過程,框架就是在原理的基礎上提供更加便捷的使用而已,協議就是基於TCP或UDP之上,服務者和調用者之間約定消息按照什麼樣的格式發送以及解析罷了。協議沒什麼高深莫測的。
原文和作者一起討論:http://www.cnblogs.com/intsmaze/p/6055684.html
可接網站開發,java開發。
新浪微博:intsmaze劉洋洋哥
微信:intsmaze
下面是我多年前學習webservice時,做的筆記,今天整理一下,分享出來,為我源碼剖析RPC做准備。
WebService,顧名思義就是基於Web的服務。它使用Web(HTTP)方式,接收和響應外部系統的某種請求,從而實現遠程調用。我們可以調用互聯網上查詢天氣信息Web服務,然後將它嵌入到我們的程序(C/S或B/S程序)當中來,用戶可以在我們的網點看到天氣信息,他會認為我們為他提供了很多的信息服務,但其實我們只是簡單調用了一下服務器上的一段代碼來調用別人寫好的WebService。WebService可以將你的服務(一段代碼)發布到互聯網上讓別人去調用,也可以調用別人機器上發布的WebService,就像使用自己的代碼一樣.
webservice是兩個軟件系統之間的遠程調用,這裡的調用是跨語言的調用。兩個不同的應用程序之間通過xml進行數據交互的。這樣任何一種語言都可以解析xml文件中的數據。數據進行交互遵循的協議是http協議。http協議,以及我們用jdbc訪問數據庫其實底層都是依賴socket連接。比我我們經常在別的網站登錄第三方賬號也可以登錄,其實也是用的webservice,別的網站拿到賬號到第三方提供的賬號服務去驗證。
在JDK1.6以後JAX-WS規范定義了如何發布一個webService服務。
JAX-WS是指Java Api for XML – WebService.
用Jdk1.6.以後的版本發布一個WebService服務.
與Web服務相關的類,都位於javax.jws.*包中。
主要類有:
@WebService - 它是一個注解,將 Java 類標記為實現 Web Service,或者將 Java 接口標記為定義 Web Service 接口。
Endpoint – 此類為端點服務類,它的方法publish用於將一個已經添加了@WebService注解對象綁定到一個地址的端口上,接收兩個參數,一個是本地的服務地址,二是提供服務的類。
如何發布一個web服務:
1、在類上添加@WebService注解。
2、通過EndPoint(端點服務)static Endpoint.publish(String address, Object implementor) 發布一個webService。
EndPoint發布完成服務以後,將會啟動一個獨立的線程運行,這個啟動的線程其實就是一個servicesocket,它會接收來至其他端的socket連接。
其他注意事項:
1,給類添加上@WebService注解後,類中所有的非靜態方法都將會對外公布。不支持靜態方法,final方法。
2,如果希望某個方法(非static,非final)不對外公開,可以在方法上添加@WebMethod(exclude=true),阻止對外公開。
3,如果一個類上,被添加了@WebService注解,則必須此類至少有一個可以公開的方法,否則將會啟動失敗。
@WebService public class HelloService { public String sayHello( String intsmaze){ System.out.println("sayHello()..."); return "hello " + intsmaze; } public String sayHello2(String intsmaze){ return "hello " + intsmaze; } public static void main(String[] args) { Endpoint.publish("http://127.0.0.1:6789/hello ", new HelloService());
//這個地方其實就是進行了封裝,裡面根據指定參數啟動了一個servicesocket,並且生成了一個WSDL文檔。 System.out.println("Server ready..."); } }
服務發布成功了,如何調用呢?請看說明書-WSDL:
任何一個服務在地址欄輸入服務地址加?wsdl 如:http://127.0.0.1:6789/hello ?wsdl
目前不是訪問webService,只是獲取一個用於描述WebService的說明文件,即:wsdl文件.wsdl- WebService Description Language,是以XML文件形式來描述WebService的”說明書”,有了說明書,我們才可以知道如何使用或是調用這個服務。
wsimport.exe是jdk自帶的,可以根據wsdl文檔生成客戶端調用代碼。
當然,無論服務器端的WebService是用什麼語言寫的,都將在客戶端生成Java代碼.服務器端用什麼寫的並不重要.
注意生成的這些代碼服務端並沒有,不是從服務端下載的。
wsimport.exe位於JAVA_HOME\bin目錄下.
常用參數為:
-d<目錄> - 將生成.class文件。默認參數。
-s<目錄> - 將生成.java文件。
-p<生成的新包名> -將生成的類,放於指定的包下:-p com.intsmaze.demo
(wsdlurl) - http://server:port/service?wsdl,必須的參數。
示例:
C:/> wsimport –s . http://192.168.0.100/one?wsdl
注意:-s不能分開,-s後面有個小點,用於指定源代碼生成的目錄。點即當前目錄。(注意.前後有空格)
如果使用了-s參數則會在目錄下生成兩份代碼,一份為.class代碼。一份為.java代碼。
.class代碼,可以經過打包以後使用。java代碼可以直接Copy到我們的項目中運行。
然後只需要根據wsdl文件提供的信息調用生成類提供的方法。建議從下往上看。
wsimport.exe是jdk自帶的,可以根據wsdl文檔生成客戶端調用java代碼,當然如果是用其他語言的類似工具,解析wsdl後將會生成對應語言的代碼,這裡只是用java為例子,注意這些代碼不是通過服務端下載的,而是通過解析wsdl生成對應java文件(就是一個本地IO)。
wsimport.exe位於JAVA_HOME\bin目錄下.
常用參數為: -d<目錄> - 將生成.class文件。默認參數。 -s<目錄> - 將生成.java文件。 -p<生成的新包名> -將生成的類,放於指定的包下:-p com.intsmaze.demo (wsdlurl) - http://server:port/service?wsdl,必須的參數。
示例:C:/> wsimport –s . http://192.168.0.100/one?wsdl
注意:-s不能分開,-s後面有個小點,用於指定源代碼生成的目錄。點即當前目錄。(注意.前後有空格)
如果使用了-s參數則會在目錄下生成兩份代碼,一份為.class代碼。一份為.java代碼。.class代碼,可以經過打包以後使用。java代碼可以直接Copy到我們的項目中運行。
生成代碼
然後只需要根據wsdl文件提供的信息調用生成類提供的方法。建議從下往上看。
wsdl:definitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://jdkservice.intsmaze.com/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:ns1="http://schemas.xmlsoap.org/soap/http" name="HelloServiceService" targetNamespace="http://jdkservice.intsmaze.com/">這是服務端的包結構,一般來說通過注解修改最多,不要暴露出去! <wsdl:types> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://jdkservice.intsmaze.com/"
elementFormDefault="unqualified" targetNamespace="http://jdkservice.intsmaze.com/" version="1.0"> <xs:element name="sayHello" type="tns:sayHello"/> <xs:element name="sayHelloResponse" type="tns:sayHelloResponse"/> <xs:complexType name="sayHello"> <xs:sequence> <xs:element minOccurs="0" name="arg0" type="xs:string"/> <xs:element name="arg1" type="xs:int"/> </xs:sequence> </xs:complexType> <xs:complexType name="sayHelloResponse">6,子元素說明了它的類型,已經是參數還是返回值 <xs:sequence> <xs:element minOccurs="0" name="return" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:schema> </wsdl:types> <wsdl:message name="sayHelloResponse">5,通過element可以知道參數類型 <wsdl:part element="tns:sayHelloResponse" name="parameters"></wsdl:part> </wsdl:message> <wsdl:message name="sayHello"> <wsdl:part element="tns:sayHello" name="parameters"></wsdl:part> </wsdl:message> <wsdl:portType name="HelloService">3,找到標簽它的子元素就是提供的方法 <wsdl:operation name="sayHello">方法名 <wsdl:input message="tns:sayHello" name="sayHello"></wsdl:input>
4,輸入參數,通過message的屬性可以知道參數類型,但是如果生成本地代碼,通過調用函數就可以知道參數類型了。 <wsdl:output message="tns:sayHelloResponse" name="sayHelloResponse">輸出參數 </wsdl:output> </wsdl:operation> </wsdl:portType> <wsdl:binding name="HelloServiceServiceSoapBinding" type="tns:HelloService">2,根據type的屬性找到對應的標簽 <soap:binding transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="sayHello"> <soap:operation soapAction="" /> <wsdl:input name="sayHello"> <soap:body use="literal"/> </wsdl:input> <wsdl:output name="sayHelloResponse"> <soap:body use="literal"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="HelloServiceService">服務的名稱,創建具體服務對象。 <wsdl:port binding="tns:HelloServiceServiceSoapBinding" 1,根據這個名稱找到對應的標簽 name="HelloServicePort">服務對象調用getHelloServicePort()獲取端口返回服務接口。 <soap:address location="http://127.0.0.1:7777/hello"/> </wsdl:port> </wsdl:service> </wsdl:definitions>
package com.intsmaze.jdkservice; /** * 通過wsimport生成客戶端代碼調用webservice服務 */ public class App { public static void main(String[] args) { /** * wsdl:<service name="HelloServiceService"> */ HelloServiceService hss = new HelloServiceService(); /** * wsdl:<port name="HelloServicePort" binding="tns:HelloServicePortBinding"> */ HelloService soap = hss.getHelloServicePort(); String str = soap.sayHello("intsmaze");//這裡我們看視乎在調用我們本地的方法,其實內部把發送數據組裝為soap協議,
然後把數據發送到了服務端,服務端的線程接收到請求處理返回了數據。
System.out.println(str); } }
我們使用過HttpWatch獲取的HTTP的調用過程,並獲得了HTTP的請求頭及其他請求的詳細信息。既然WebServie也是通過HTTP進行通信的,能不使用HTTPWatch來獲取它的請求過程呢?我們的代碼不僅僅是向服務器發送的HTTP協議,更具體的說應該叫SOAP協議,它是WebService進行通信的基礎。為了獲取SOAP數據發送和接收的格式。我們有必要使用一個工具來深入的了解WebService.
我們使用TCP/IP Monitor來監控攔截請求和響應具體數據的完整過程。
以下發出HTTP請求
響應的信息,同發送信息一樣,先必須是HTTP協議,然後再遵循SOAP協議。