java介面調用——webservice就是一個RPC而已,webservicerpc
很多新手一聽到介面就蒙逼,不知道介面是什麼!其實介面就是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註解,則必須此類至少有一個可以公開的方法,否則將會啟動失敗。
@WebServicepublic 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 style="document" transport="http://schemas.xmlsoap.org/soap/http"/><wsdl:operation name="sayHello"><soap:operation soapAction="" style="document"/><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協議。