天天看點

XFire用戶端流程分析

XFire是目前J2EE領域非常流行的Web Service架構,以其卓越的性能和簡單易用的特性博得了廣大開發者的青睐。目前XFire已經演變為Apache的CXF項目,但仍有大量使用者在使用XFire。

下面是XFire用戶端調用的流程分析圖,本文後續本分将圍繞該圖展開。

XFire用戶端流程分析

XFire用戶端的調用非常靈活,可以有很多種方式,如通過配置調用、通過API程式設計調用或者與Spring等IoC架構內建使用。雖然調用方式靈活多樣,但萬變不離其中,其内部流程是一緻的。

建立服務模型

服務模型是XFire中非常重要的概念之一,包含了服務的接口資訊、操作資訊、Binding資訊等諸多服務調用過程中需要的資訊。是以在進行服務調用之前首先要建立服務模型。建立服務模型的工作是由服務工廠ServiceFactory完成的,使用者需要為服務工程提供服務接口、名稱、命名空間等一些資訊,其中服務接口是必須的,其他為可選資訊。

建立Client執行個體

Client是XFire用戶端的核心組成部分,間接的代表了一個服務。當為具體某個服務配置攔截器(Handler,有很多種譯法如攔截器、處理器、過濾器等,本文統一用攔截器)時,其實是将攔截器資訊應用到Client執行個體上。Client可以手工建立也可以由XFireProxyFactory建立,無論通過哪種方式,Client在初始化過程中最重要的一步都是在out攔截器堆棧中增加一個OutMessageSender攔截器。該攔截器負責最終将服務調用通過HTTP發送到服務提供者并傳回處理結果。本文後續部分還會對OutMessageSender做更加詳細的講解。

建立服務代理對象

XFireProxy,XFire SOAP用戶端代理實作,使用者調用服務時(如Hello.echo(“tony”))就是通過該對象的invoke方法來執行。實際上,XFireProxy隻是将調用代理到Client執行個體,最終執行服務的還是Client執行個體。

構造調用鍊資訊

Client執行個體的invoke方法在執行時,生成了一個Invocation對象,該對象構造了一次完整的調用資訊,包括OutMessage、MessageContext等。同時Invocation還負責構造一個攔截器管道(HandlerPipeline),該管道包含了本次調用需要執行的所有攔截器,當然也包括OutMessageSender。這些攔截器會分不同的階段來執行,這也是XFire一個特性。XFire預設定義了很多階段(Phase),每個階段都會有若幹攔截器被調用。

循環調用攔截器

攔截器(Handler)是XFire中最為重要的概念,一次服務調用就是由若幹攔截器組合完成的。XFire預設提供了很多預定義的攔截器,使用者也可以定義自己的攔截器。基本上,通過攔截器可以影響XFire執行過程中的任何步驟,你可以為所欲為:)

攔截器有兩個重要的概念,一個是階段(Phase),一個是順序(Order)。這兩個因素共同決定了攔截器的執行順序。可以在三個不同的地方配置攔截器:

n         XFire執行個體:全局攔截器,對所有通道上的所有服務起作用

n         Transport:通道特定的攔截器,隻對該通道(如HTTP、JMS)起作用

n         具體服務:服務特定的攔截器,隻對該服務起作用

其實,具體服務上的攔截器最終是配置到Client上。對于同一個階段上的攔截器,執行順序為“具體服務—>Transport—>XFire執行個體”。千萬不要忽視這些順序,這對你正确的使用攔截器非常有幫助。

發送遠端服務請求

這是整個調用鍊中最後的一環,也是最關鍵的一步。OutMessageHandler,前文已經有所提及,是一個特殊的攔截器,在Client初始化時建立并加入調用鍊中。該攔截器處于攔截器調用鍊的Phase.SEND階段,基本上也是最後的階段。OutMessageHandler從目前調用的消息上下文(MessageContext)中擷取請求的服務位址URI以及SOAP消息,然後通過HTTP将SOAP請求發送到遠端伺服器(針對HTTP通道,如果是JMS通道則發送到指定的目的地)。最終将遠端伺服器的響應逐級傳回給調用者。

案例分析

前文很多地方都提到Handler非常重要,那麼具體有那些應用場景呢?本部分通過兩個案例逐漸示範Handler的應用。

一、             簡單安全驗證

這是一個非常典型的應用場景,假設A公司對外提供了一個旅程資訊查詢服務,該服務通過XFire對外釋出。但是A公司隻希望其合作夥伴才能使用該服務,那麼A公司可以為該服務配置一個Handler,該Handler從SOAP的消息頭中擷取認證字元串,隻有通過驗證的請求才被執行。下面是簡單的示例代碼,真實情況要比這複雜得多。

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);

  }

}

對于A公司的合作夥伴,要想調用該服務,必須在其SOAP的消息頭中包含上面代碼中的驗證字元串,否則服務将被拒絕。下面是簡單的示例代碼:

    publicvoid invoke(MessageContext context) throws Exception {

        Element header = context.getInMessage().getHeader();

        Element authCode = new Element("authCode");

        authCode.addContent("tony");

        header.addContent(authCode);

    }

二、             查找真實服務

這是一個比較特殊的應用場景:假設A公司已經初步實作SOA,擁有一個服務注冊中心,所有的XFire服務都在該中心注冊。用戶端在調用服務時需要動态的從該服務注冊中心擷取目前的服務位址及版本。通過其他方式肯定也可以實作該需求,但是通過Handler來實作會非常的幽雅,而且對應用不需要做任何變動。我們先來看一下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中擷取目前請求的服務URI位址,然後用目前請求環境資訊及服務URI位址到服務注冊中心查找真實的服務,并重新設定服務的位址。

結束語

本文粗略的介紹了XFire用戶端的調用流程,并着重講解了Handler的擴充機制及其應用場景,力求讀者能夠通過本文對XFire能有更加深入的了解和掌握。文中難免存在不足之處,歡迎任何形式的交流。

XFire用戶端流程分析

々上善若水々 2008-05-07 11:09 發表評論

繼續閱讀