XFire客戶端流程分析
XFire是當(dāng)前J2EE領(lǐng)域非常流行的Web Service框架,以其卓越的性能和簡單易用的特性博得了廣大開發(fā)者的青睞。目前XFire已經(jīng)演變?yōu)?/span>Apache的CXF項(xiàng)目,但仍有大量用戶在使用XFire。
下面是XFire客戶端調(diào)用的流程分析圖,本文后續(xù)本分將圍繞該圖展開。
XFire客戶端的調(diào)用非常靈活,可以有很多種方式,如通過配置調(diào)用、通過API編程調(diào)用或者與Spring等IoC框架集成使用。雖然調(diào)用方式靈活多樣,但萬變不離其中,其內(nèi)部流程是一致的。
創(chuàng)建服務(wù)模型
服務(wù)模型是XFire中非常重要的概念之一,包含了服務(wù)的接口信息、操作信息、Binding信息等諸多服務(wù)調(diào)用過程中需要的信息。因此在進(jìn)行服務(wù)調(diào)用之前首先要?jiǎng)?chuàng)建服務(wù)模型。創(chuàng)建服務(wù)模型的工作是由服務(wù)工廠ServiceFactory完成的,用戶需要為服務(wù)工程提供服務(wù)接口、名稱、命名空間等一些信息,其中服務(wù)接口是必須的,其他為可選信息。
創(chuàng)建Client實(shí)例
Client是XFire客戶端的核心組成部分,間接的代表了一個(gè)服務(wù)。當(dāng)為具體某個(gè)服務(wù)配置攔截器(Handler,有很多種譯法如攔截器、處理器、過濾器等,本文統(tǒng)一用攔截器)時(shí),其實(shí)是將攔截器信息應(yīng)用到Client實(shí)例上。Client可以手工創(chuàng)建也可以由XFireProxyFactory創(chuàng)建,無論通過哪種方式,Client在初始化過程中最重要的一步都是在out攔截器堆棧中增加一個(gè)OutMessageSender攔截器。該攔截器負(fù)責(zé)最終將服務(wù)調(diào)用通過HTTP發(fā)送到服務(wù)提供者并返回處理結(jié)果。本文后續(xù)部分還會(huì)對(duì)OutMessageSender做更加詳細(xì)的講解。
創(chuàng)建服務(wù)代理對(duì)象
XFireProxy,XFire SOAP客戶端代理實(shí)現(xiàn),用戶調(diào)用服務(wù)時(shí)(如Hello.echo(“tony”))就是通過該對(duì)象的invoke方法來執(zhí)行。實(shí)際上,XFireProxy只是將調(diào)用代理到Client實(shí)例,最終執(zhí)行服務(wù)的還是Client實(shí)例。
構(gòu)造調(diào)用鏈信息
Client實(shí)例的invoke方法在執(zhí)行時(shí),生成了一個(gè)Invocation對(duì)象,該對(duì)象構(gòu)造了一次完整的調(diào)用信息,包括OutMessage、MessageContext等。同時(shí)Invocation還負(fù)責(zé)構(gòu)造一個(gè)攔截器管道(HandlerPipeline),該管道包含了本次調(diào)用需要執(zhí)行的所有攔截器,當(dāng)然也包括OutMessageSender。這些攔截器會(huì)分不同的階段來執(zhí)行,這也是XFire一個(gè)特性。XFire默認(rèn)定義了很多階段(Phase),每個(gè)階段都會(huì)有若干攔截器被調(diào)用。
循環(huán)調(diào)用攔截器
攔截器(Handler)是XFire中最為重要的概念,一次服務(wù)調(diào)用就是由若干攔截器組合完成的。XFire默認(rèn)提供了很多預(yù)定義的攔截器,用戶也可以定義自己的攔截器。基本上,通過攔截器可以影響XFire執(zhí)行過程中的任何步驟,你可以為所欲為:)
攔截器有兩個(gè)重要的概念,一個(gè)是階段(Phase),一個(gè)是順序(Order)。這兩個(gè)因素共同決定了攔截器的執(zhí)行順序。可以在三個(gè)不同的地方配置攔截器:
n XFire實(shí)例:全局?jǐn)r截器,對(duì)所有通道上的所有服務(wù)起作用
n Transport:通道特定的攔截器,只對(duì)該通道(如HTTP、JMS)起作用
n 具體服務(wù):服務(wù)特定的攔截器,只對(duì)該服務(wù)起作用
其實(shí),具體服務(wù)上的攔截器最終是配置到Client上。對(duì)于同一個(gè)階段上的攔截器,執(zhí)行順序?yàn)?#8220;具體服務(wù)—>Transport—>XFire實(shí)例”。千萬不要忽視這些順序,這對(duì)你正確的使用攔截器非常有幫助。
發(fā)送遠(yuǎn)程服務(wù)請(qǐng)求
這是整個(gè)調(diào)用鏈中最后的一環(huán),也是最關(guān)鍵的一步。OutMessageHandler,前文已經(jīng)有所提及,是一個(gè)特殊的攔截器,在Client初始化時(shí)創(chuàng)建并加入調(diào)用鏈中。該攔截器處于攔截器調(diào)用鏈的Phase.SEND階段,基本上也是最后的階段。OutMessageHandler從當(dāng)前調(diào)用的消息上下文(MessageContext)中獲取請(qǐng)求的服務(wù)地址URI以及SOAP消息,然后通過HTTP將SOAP請(qǐng)求發(fā)送到遠(yuǎn)程服務(wù)器(針對(duì)HTTP通道,如果是JMS通道則發(fā)送到指定的目的地)。最終將遠(yuǎn)程服務(wù)器的響應(yīng)逐級(jí)返回給調(diào)用者。
案例分析
前文很多地方都提到Handler非常重要,那么具體有那些應(yīng)用場景呢?本部分通過兩個(gè)案例逐步演示Handler的應(yīng)用。
一、 簡單安全驗(yàn)證
這是一個(gè)非常典型的應(yīng)用場景,假設(shè)A公司對(duì)外提供了一個(gè)旅程信息查詢服務(wù),該服務(wù)通過XFire對(duì)外發(fā)布。但是A公司只希望其合作伙伴才能使用該服務(wù),那么A公司可以為該服務(wù)配置一個(gè)Handler,該Handler從SOAP的消息頭中獲取認(rèn)證字符串,只有通過驗(yàn)證的請(qǐng)求才被執(zhí)行。下面是簡單的示例代碼,真實(shí)情況要比這復(fù)雜得多。
publicvoid invoke(MessageContext context) throws Exception { Element header = context.getInMessage().getHeader(); String authCode = header.getChild("authCode",null).getValue(); if(!"tony".equals(authCode)){ thrownew XFireFault("Authentication Fail!", XFireFault.SENDER); } } |
對(duì)于A公司的合作伙伴,要想調(diào)用該服務(wù),必須在其SOAP的消息頭中包含上面代碼中的驗(yàn)證字符串,否則服務(wù)將被拒絕。下面是簡單的示例代碼:
publicvoid invoke(MessageContext context) throws Exception { Element header = context.getInMessage().getHeader(); Element authCode = new Element("authCode"); authCode.addContent("tony"); header.addContent(authCode); } |
二、 查找真實(shí)服務(wù)
這是一個(gè)比較特殊的應(yīng)用場景:假設(shè)A公司已經(jīng)初步實(shí)現(xiàn)SOA,擁有一個(gè)服務(wù)注冊(cè)中心,所有的XFire服務(wù)都在該中心注冊(cè)。客戶端在調(diào)用服務(wù)時(shí)需要?jiǎng)討B(tài)的從該服務(wù)注冊(cè)中心獲取當(dāng)前的服務(wù)地址及版本。通過其他方式肯定也可以實(shí)現(xiàn)該需求,但是通過Handler來實(shí)現(xiàn)會(huì)非常的幽雅,而且對(duì)應(yīng)用不需要做任何變動(dòng)。我們先來看一下Handler的代碼:
publicvoid invoke(MessageContext context) throws Exception { // 1.尋址 lookupRealServiceUri(context); } privatevoid lookupRealServiceUri(MessageContext context) { String uri = context.getOutMessage().getUri(); try { uri = serviceLocator.lookup(requestEnvironment, uri); } catch (Exception e) { // Ignoral this exception } context.getOutMessage().setUri(uri); } |
正如代碼所示,只需要從context中獲取當(dāng)前請(qǐng)求的服務(wù)URI地址,然后用當(dāng)前請(qǐng)求環(huán)境信息及服務(wù)URI地址到服務(wù)注冊(cè)中心查找真實(shí)的服務(wù),并重新設(shè)置服務(wù)的地址。
結(jié)束語
本文粗略的介紹了XFire客戶端的調(diào)用流程,并著重講解了Handler的擴(kuò)展機(jī)制及其應(yīng)用場景,力求讀者能夠通過本文對(duì)XFire能有更加深入的了解和掌握。文中難免存在不足之處,歡迎任何形式的交流。
posted on 2008-05-07 11:09 々上善若水々 閱讀(2644) 評(píng)論(2) 編輯 收藏 所屬分類: WebService