webservice的工作原理

 

實際上,WebService的主要目標是跨平臺的可互操作性。為了達到這一目標,WebService完全基于XML(可擴展標記語言)、XSDXMLSchema)等獨立于平臺、獨立于軟件供應商的標準,是創(chuàng)建可互操作的、分布式應用程序的新平臺。由此可以看出,在以下四種情況下,使用WebService會帶來極大的好處。

 

優(yōu)勢一:跨防火墻的通信

如果應用程序有成千上萬的用戶,而且分布在世界各地,那么客戶端和服務器之間的通信將是一個棘手的問題。因為客戶端和服務器之間通常會有防火墻或者代理服務器。在這種情況下,使用DCOM就不是那么簡單,通常也不便于把客戶端程序發(fā)布到數(shù)量如此龐大的每一個用戶手中。傳統(tǒng)的做法是,選擇用瀏覽器作為客戶端,寫下一大堆ASP頁面,把應用程序的中間層暴露給最終用戶。這樣做的結(jié)果是開發(fā)難度大,程序很難維護。

 

舉個例子,在應用程序里加入一個新頁面,必須先建立好用戶界面(Web頁面),并在這個頁面后面,包含相應商業(yè)邏輯的中間層組件,還要再建立至少一個ASP頁面,用來接受用戶輸入的信息,調(diào)用中間層組件,把結(jié)果格式化為HTML形式,最后還要把“結(jié)果頁”送回瀏覽器。要是客戶端代碼不再如此依賴于HTML表單,客戶端的編程就簡單多了。

如果中間層組件換成WebService的話,就可以從用戶界面直接調(diào)用中間層組件,從而省掉建立ASP頁面的那一步。要調(diào)用WebService,可以直接使用MicrosoftSOAPToolkit.NET這樣的SOAP客戶端,也可以使用自己開發(fā)的SOAP客戶端,然后把它和應用程序連接起來。不僅縮短了開發(fā)周期,還減少了代碼復雜度,并能夠增強應用程序的可維護性。同時,應用程序也不再需要在每次調(diào)用中間層組件時,都跳轉(zhuǎn)到相應的“結(jié)果頁”。

從經(jīng)驗來看,在一個用戶界面和中間層有較多交互的應用程序中,使用WebService這種結(jié)構(gòu),可以節(jié)省花在用戶界面編程上20%的開發(fā)時間。另外,這樣一個由WebService組成的中間層,完全可以在應用程序集成或其它場合下重用。最后,通過WebService把應用程序的邏輯和數(shù)據(jù)“暴露”出來,還可以讓其它平臺上的客戶重用這些應用程序。

 

優(yōu)勢二:應用程序集成

允許在不同平臺上、以不同語言編寫的各種程序以基于標準的方式相互通信。企業(yè)級的應用程序開發(fā)者都知道,企業(yè)里經(jīng)常都要把用不同語言寫成的、在不同平臺上運行的各種程序集成起來,而這種集成將花費很大的開發(fā)力量。應用程序經(jīng)常需要從運行在IBM主機上的程序中獲取數(shù)據(jù);或者把數(shù)據(jù)發(fā)送到主機或UNIX應用程序中去。即使在同一個平臺上,不同軟件廠商生產(chǎn)的各種軟件也常常需要集成起來。通過WebService,應用程序可以用標準的方法把功能和數(shù)據(jù)“暴露”出來,供其它應用程序使用。

例如,有一個訂單記錄程序,用于從客戶獲得新訂單,包括客戶信息、發(fā)貨地址、數(shù)量、價格和付款方式等內(nèi)容;還有一個訂單執(zhí)行程序,用于實際貨物發(fā)送的管理。這兩個程序來自不同軟件廠商。一份新訂單進來之后,訂單記錄程序需要通知訂單執(zhí)行程序發(fā)送貨物。通過在訂單執(zhí)行程序上面增加一層WebService,訂單執(zhí)行程序可以把“AddOrder”函數(shù)“暴露”出來。這樣,每當有新訂單到來時,訂單登錄程序就可以調(diào)用這個函數(shù)來發(fā)送貨物了。

 

優(yōu)勢三:B2B的集成

WebService集成應用程序,可以使公司內(nèi)部的商務處理更加自動化。但當交易跨越供應商和客戶、突破公司的界限時會怎么樣呢?跨公司的商務交易集成通常叫做B2B集成。

WebServiceB2B集成成功的關(guān)鍵。通過WebService,公司可以把關(guān)鍵的商務應用“暴露”給指定的供應商和客戶。例如,把電子下單系統(tǒng)和電子發(fā)票系統(tǒng)“暴露”出來,客戶就可以以電子的方式發(fā)送訂單,供應商則可以以電子的方式發(fā)送原料采購發(fā)票。當然,這并不是一個新的概念,EDI(電子文檔交換)早就是這樣了。但是,WebService的實現(xiàn)要比EDI簡單得多,而且WebService運行在Internet上,在世界任何地方都可輕易實現(xiàn),其運行成本就相對較低。不過,WebService并不像EDI那樣,是文檔交換或B2B集成的完整解決方案。WebService只是B2B集成的一個關(guān)鍵部分,還需要許多其它的部分才能實現(xiàn)集成。

WebService來實現(xiàn)B2B集成的最大好處在于可以輕易實現(xiàn)互操作性。只要把商務邏輯“暴露”出來,成為WebService,就可以讓任何指定的合作伙伴調(diào)用這些商務邏輯,而不管他們的系統(tǒng)在什么平臺上運行,使用什么開發(fā)語言。這樣就大大減少了花在B2B集成上的時間和成本,讓許多原本無法承受EDI的中小企業(yè)也能實現(xiàn)B2B集成。

 

優(yōu)勢四:軟件和數(shù)據(jù)重用

軟件重用是一個很大的主題,重用的形式很多,重用的程度有大有小。最基本的形式是源代碼模塊或者類一級的重用,另一種形式是二進制形式的組件重用。

WebService集成各種應用中的功能,為用戶提供一個統(tǒng)一的界面

當前,像表格控件或用戶界面控件這樣的可重用軟件組件,在市場上都占有很大的份額。但這類軟件的重用有一個很大的限制,就是重用僅限于代碼,數(shù)據(jù)不能重用。原因在于,發(fā)布組件甚至源代碼都比較容易,但要發(fā)布數(shù)據(jù)就沒那么容易,除非是不會經(jīng)常變化的靜態(tài)數(shù)據(jù)。

WebService在允許重用代碼的同時,可以重用代碼背后的數(shù)據(jù)。使用WebService,再也不必像以前那樣,要先從第三方購買、安裝軟件組件,再從應用程序中調(diào)用這些組件;只需要直接調(diào)用遠端的WebService就可以了。舉個例子,要在應用程序中確認用戶輸入的地址,只需把這個地址直接發(fā)送給相應的WebService,這個WebService就會幫你查閱街道地址、城市、省區(qū)和郵政編碼等信息,確認這個地址是否在相應的郵政編碼區(qū)域。WebService的提供商可以按時間或使用次數(shù)來對這項服務進行收費。這樣的服務要通過組件重用來實現(xiàn)是不可能的,那樣的話你必須下載并安裝好包含街道地址、城市、省區(qū)和郵政編碼等信息的數(shù)據(jù)庫,而且這個數(shù)據(jù)庫還是不能實時更新的。

另一種軟件重用的情況是,把好幾個應用程序的功能集成起來。例如,要建立一個局域網(wǎng)上的門戶站點應用,讓用戶既可以查詢聯(lián)邦快遞包裹,查看股市行情,又可以管理自己的日程安排,還可以在線購買電影票。現(xiàn)在Web上有很多應用程序供應商,都在其應用中實現(xiàn)了這些功能。一旦他們把這些功能都通過WebService“暴露”出來,就可以非常容易地把所有這些功能都集成到你的門戶站點中,為用戶提供一個統(tǒng)一的、友好的界面。

將來,許多應用程序都會利用WebService,把當前基于組件的應用程序結(jié)構(gòu)擴展為組件/WebService的混合結(jié)構(gòu),可以在應用程序中使用第三方的WebService提供的功能,也可以把自己的應用程序功能通過WebService提供給別人。兩種情況下,都可以重用代碼和代碼背后的數(shù)據(jù)。

從以上論述可以看出,WebService在通過Web進行互操作或遠程調(diào)用的時候是最有用的。不過,也有一些情況,WebService根本不能帶來任何好處。

 

短處一:單機應用程序

目前,企業(yè)和個人還使用著很多桌面應用程序。其中一些只需要與本機上的其它程序通信。在這種情況下,最好就不要用WebService,只要用本地的API就可以了。COM非常適合于在這種情況下工作,因為它既小又快。運行在同一臺服務器上的服務器軟件也是這樣。最好直接用COM或其它本地的API來進行應用程序間的調(diào)用。當然WebService也能用在這些場合,但那樣不僅消耗太大,而且不會帶來任何好處。

 

短處二:局域網(wǎng)的同構(gòu)應用程序

在許多應用中,所有的程序都是用VBVC開發(fā)的,都在Windows平臺下使用COM,都運行在同一個局域網(wǎng)上。例如,有兩個服務器應用程序需要相互通信,或者有一個Win32WinForm的客戶程序要連接局域網(wǎng)上另一個服務器的程序。在這些程序里,使用DCOM會比SOAP/HTTP有效得多。與此相類似,如果一個.NET程序要連接到局域網(wǎng)上的另一個.NET程序,應該使用.NETremoting。有趣的是,在.NETremoting中,也可以指定使用SOAP/HTTP來進行WebService調(diào)用。不過最好還是直接通過TCP進行RPC調(diào)用,那樣會有效得多。

總之,只要從應用程序結(jié)構(gòu)的角度看,有別的方法比WebService更有效、更可行,那就不要用WebService

Web Service定義為:通過 SOAP Web上提供的軟件服務,使用 WSDL 文件進行說明,并通過 UDDI 進行注冊。

 

 

Web Service架構(gòu):Web Service是獨立的、模塊化的應用,能夠通過因特網(wǎng)來描述、發(fā)布、定位以及調(diào)用。在Web Service的體系架構(gòu)中包括三個角色:服務提供者(Service Provider)、服務請求者(Service Requestor)、服務注冊器(Service Registry)。角色間主要有三個操作:發(fā)布(Publish)、查找(Find)、綁定(Bind)

下圖清楚的描述了三種角色,以及角色之間的作用關(guān)系。

Web Service協(xié)議標準

1、簡單對象訪問協(xié)議(SOAP

SOAPSimple Object Access Protocol的縮寫,是一種基于XML的不依賴傳輸協(xié)議的表示層協(xié)議,用來在分散或分布式的應用程序之間方便地以對象的形式交換數(shù)據(jù)。在SOAP的下層,可以是HTTP,也可以是SMTP/POP3,還可以是為一些應用而專門設計的特殊的通信協(xié)議。

SOAP包括三個主要部分:

SOAP封裝結(jié)構(gòu):定義了一個整體框架,以表示消息中包含什么內(nèi)容,誰來處理這些內(nèi)容以及這些內(nèi)容是可選的或是必需的。

SOAP編碼規(guī)則:定義了用以交換應用程序定義的數(shù)據(jù)類型的實例的一系列機制。

SOAP RPC表示:定義了一個用來表示遠程過程調(diào)用和應答的協(xié)定。

2Web Service描述語言(WSDL

WSDLWeb Service Description Language的縮寫,該語言將網(wǎng)絡服務定義成一個能交換消息的通信端點集,為分布式系統(tǒng)提供了幫助文檔,同時也可作為自動實現(xiàn)應用間通信的解決方案。

3、統(tǒng)一描述、發(fā)現(xiàn)和集成協(xié)議(UDDI

UDDI是一套基于Web的、分布式的、為Web Service提供的、信息注冊中心的實現(xiàn)標準規(guī)范,同時也包含一組使企業(yè)能將自身提供的Web Service注冊,以使別的企業(yè)能夠發(fā)現(xiàn)的訪問協(xié)議的實現(xiàn)標準。

 

 

       通過xfire實現(xiàn)了webservice。下面詳細介紹一下xfire

XFire是一個免費的,開源的SOAP框架. 它不僅允許你輕松簡易地實現(xiàn)這么一個環(huán)境.而且還提供了很多先進的特性.如果你的Web應用有一個Java, 現(xiàn)在你希望這個類變成Web服務,XFire完成這一工作你不必寫一句代碼.僅需操作一下部署描述器,你就會得到一個Web服務.

一、建立接口文件com.resoft.recis.ws.ReCISService

public interface ReCISService {

       //請求系統(tǒng)設置信息

       public AppInfo getAppInfo();

}

public class ReCISServiceImp implements ReCISService {

       public com.resoft.recis.ws.AppInfo getAppInfo() {

              // TODO Auto-generated method stub

              return com.resoft.recis.ws.AppInfo.getAppInfo();

       }

}

二、已存在類com.resoft.recis.ws. AppInfo

public class AppInfo {

       double cardLeft;

       /** default constructor */

       public AppInfo() {

       }

       public double getCardLeft() {

              return cardLeft;

       }

       public void setCardLeft(double cardLeft) {

              this.cardLeft = cardLeft;

       }

       public static  AppInfo getAppInfo() {

              Session session = HibernateUtil.getSession();

              com.resoft.recis.biz.AppInfo dbappinfo = (com.resoft.recis.biz.AppInfo) Util

                            .getHQLResult(session, "from AppInfo");

              if (dbappinfo == null) {

                     return null;

              }           

              com.resoft.recis.ws.AppInfo appinfo = new com.resoft.recis.ws.AppInfo();

              appinfo.setOperid("");

              appinfo.setOrgcode("");

              appinfo.setCardHeight(dbappinfo.getCardHeight());

              appinfo.setCardLeft(dbappinfo.getCardLeft());

              appinfo.setCardTop(dbappinfo.getCardTop());

              appinfo.setCardWidth(dbappinfo.getCardWidth());

              HibernateUtil.closeSession();

              return appinfo;

       }

}

三、Web.xml應用的部署描述

    <!—        xfireservlet配置文件 -->

    <servlet>

       <servlet-name>XFireServlet</servlet-name>

       <display-name>XFire Servlet</display-name>

       <servlet-class>

           org.codehaus.xfire.transport.http.XFireConfigurableServlet

       </servlet-class>

    </servlet>

    <servlet-mapping>

       <servlet-name>XFireServlet</servlet-name>

       <url-pattern>/servlet/XFireServlet/*</url-pattern>

    </servlet-mapping>

    <servlet-mapping>

       <servlet-name>XFireServlet</servlet-name>

       <url-pattern>/services/*</url-pattern>

    </servlet-mapping>

    <servlet-mapping>

四、創(chuàng)建services.xml文件

XFire本身就是基于Servlet的應用,xfire使用services.xml文件來完成Web服務配置。這個文件位于src/META-INF/xfire目錄下,

src\META-INF\xfire

下面是基本的配置條目,這個配置文件中配置了xfire的接口,實現(xiàn)與驗印控件的交互。

<beans xmlns="http://xfire.codehaus.org/config/1.0">

 <service>

    <name>ReCISService</name>   

    <namespace>http://resoft</namespace>

    <serviceClass>com.resoft.recis.ws.ReCISService</serviceClass>   <implementationClass>com.resoft.recis.ws.ReCISServiceImp</implementat          ionClass>

 </service>

</beans>

 

services.xml文件中的具體內(nèi)容如下:

<service>元素:

Web服務的定義包含在<service>元素內(nèi)。<service>元素下還有若干子元素。

<name>子元素:

可以提供任何有效的xml名字,這個名字會被客戶端程序和服務器上的其他組件使用.例如,當服務器起來以后,你可以在瀏覽器上使用這個名稱來查看WSDL.

<namespace>子元素:

任何有效地xml名稱都可以, <namespace>將作為你服務器的唯一標識變量使用.

<serviceClass>子元素:

包含Java類名用來指明方法的簽名.在這個例子中是ReCISService接口.如果Java類沒有實現(xiàn)任何接口,那就填入類名.只需要這一個入口來將他們轉(zhuǎn)換成Web服務.

<implementationClass>子元素:

記錄實現(xiàn)接口的Java類名.這是一個可選元素.如果前一個元素<serviceClass>填入的是接口,那么此處就要填入相應的實現(xiàn)類名.

五、XFire和所有必要的庫文件

訪問XFire官方網(wǎng)站http://xfire.codehaus.org/ 下載xfire-distribution-1.2.5.zip并解壓到本地文件夾中.參考xfire-distribution-1.2.5\xfire-1.2.5\manual\Dependency Guide.html中介紹拷貝相關(guān)jar包到WEB-INF\libxfire-distribution-1.2.5需要的jar包如下:

 

  xfire-all-1.2.5.jar

? activation-1.1.jar

commons-codec-1.3.jar

commons-httpclient-3.0.jar

commons-logging-1.0.4.jar

mail-1.4.jar

jaxen-1.1-beta-9.jar

jdom-1.0.jar

junit-3.8.1.jar

servlet-api-2.3.jar

spring-1.2.6.jar

stax-api-1.0.1.jar

wsdl4j-1.6.1.jar

wstx-asl-3.2.0.jar

xbean-2.2.0.jar

xbean-spring-2.8.jar

XmlSchema-1.1.jar

xfire-jsr181-api-1.0-M1.jar

六、通過URL驗證Web服務有效性

首先,我們先來看看WSDL是否有效。在瀏覽器中輸入URL地址為http://127.0.0.1/test/services/ReCISService?wsdl 注意URLIP地址和端口號是否需要修改。如果輸入了有效的URL,將會看到以<wsdl:definitions>為根結(jié)點的xml文件。這個文件叫做web服務的WSDL.如果你看到了這個文件,那么初步驗證你的Web服務有效。

但是這個驗證還不夠。有時候情況會復雜一些,你可以看到WSDL,但是客戶端卻無法訪問Web服務。因此要真正檢驗Web服務是否真的好使,就要用客戶端程序?qū)?/span>Web服務作一次真正的調(diào)用。

七、客戶端驗證Web服務有效性

建立下面測試類測試Web服務器的有效性。

public class TestWebservice

{

    public static void main(String args[])

    {

        String serviceURL ="http://127.0.0.1/test/services/ReCISService";  

Service serviceModel = new ObjectServiceFactory().create(ReCISService.class,null,"http://resoft",null);

       

        XFireProxyFactory serviceFactory = new XFireProxyFactory();

       

        try

        {

            ReCISService service = (ReCISService) serviceFactory.create(serviceModel, serviceURL);

            Client client = Client.getInstance(service);

            System.out.println("begin");

            com.resoft.recis.ws.AppInfo ai=service.getAppInfo();

            System.out.println(ai.getCardHeight());

            System.out.println("end");

        }

        catch (MalformedURLException e)

        {

            e.printStackTrace();

        } catch (Exception e) {

           e.printStackTrace();

        }

    }

}