隨筆 - 19, 文章 - 93, 評論 - 17, 引用 - 0
          數(shù)據(jù)加載中……

          在面向服務(wù)的體系結(jié)構(gòu)中管理狀態(tài)

          ??????一個有關(guān) Web 服務(wù)的最常見誤解是,它們只適合于支持基于同步請求/響應(yīng) SOAP(簡單對象訪問協(xié)議)的交互。 造成這種誤解的主要原因之一是,許多 Web 服務(wù)是使用不可靠的無狀態(tài)傳輸協(xié)議(如 HTTP)實現(xiàn)的。

            因此,許多組織正避免用 Web 服務(wù)來處理復(fù)雜的業(yè)務(wù)交互(在復(fù)雜業(yè)務(wù)交互中,服務(wù)使用者可能同時與同一服務(wù)進行多個交互,或同時與多個服務(wù)進行多個交互)。 OASIS(結(jié)構(gòu)化信息標(biāo)準(zhǔn)促進組織)將此類交互稱作 Web 服務(wù)會話,并將支持會話的 Web 服務(wù)稱作會話式 Web 服務(wù)。 會話式 Web 服務(wù)是異步 Web 服務(wù)的基礎(chǔ),在實現(xiàn)持續(xù)長時間業(yè)務(wù)事務(wù)方面起著至關(guān)重要的作用。

            本文將介紹如何使用顯式狀態(tài)標(biāo)識符支持會話式 Web 服務(wù)。 此外,還將概述如何使用 Oracle JDeveloper 10g 10.1.3 J2EE 開發(fā)人員預(yù)覽版(為 J2EE 1.4 JAX-RPC 提供了內(nèi)置的支持)實現(xiàn)該種方法。

            會話式 Web 服務(wù)簡介

            服務(wù)使用者與服務(wù)提供者之間的大多數(shù)交互是 Web 服務(wù)會話,例如,某個服務(wù)端點可能同時從多個客戶端收到多種類型的文檔,處理這些文檔并使用相應(yīng)的響應(yīng)聯(lián)系使用者。 在這樣的應(yīng)用程序中,特別要求正確識別每個客戶端的交互,這使得 Web 服務(wù)實現(xiàn)更加復(fù)雜。 為了避免這種復(fù)雜性,許多公司將 Web 服務(wù)實現(xiàn)局限于簡單的單一請求/響應(yīng)類型的交互(AuthorizeUser、CalculateTax、ConvertFunds 等)。

            但就其理想情形而言,Web 服務(wù)應(yīng)支持服務(wù)使用者和支持提供者之間的單一交互和復(fù)雜交互。 無論傳輸協(xié)議如何,同步或異步 Web 服務(wù)都應(yīng)能夠代表單個客戶端或在跨多個交互的特殊業(yè)務(wù)環(huán)境中保存狀態(tài)或資源。

            長期以來,解決 Web 服務(wù)中的狀態(tài)性問題的需要一直是標(biāo)準(zhǔn)組織和主要供應(yīng)商的焦點。 為解決關(guān)鍵任務(wù)和冗長業(yè)務(wù)流程中的狀態(tài)性問題,涌現(xiàn)了多個 Web 服務(wù)規(guī)范草案,如 WS-Addressing、WS-Resources 和 WS-Coordination。 最重要的是,業(yè)務(wù)流程執(zhí)行語言 (BPEL) 1.0 規(guī)范已經(jīng)整合了 WS-* 標(biāo)準(zhǔn)建議的許多特性來處理持續(xù)時間較長的業(yè)務(wù)事務(wù)。 但也應(yīng)看到新標(biāo)準(zhǔn)和解決 Web 服務(wù)會話問題的相關(guān)供應(yīng)商技術(shù)的廣泛采用。

            總之,實現(xiàn)會話式 Web 服務(wù)仍是一個相當(dāng)大的設(shè)計挑戰(zhàn)。 當(dāng)面臨依賴 Web 服務(wù)的復(fù)雜應(yīng)用程序時,應(yīng)用程序開發(fā)人員別無選擇,只能構(gòu)建定制的解決方案。

            會話式 Web 服務(wù)的工作方式

            會話式 Web 服務(wù)(本質(zhì)上是異步的)有兩個重要的服務(wù)元素類型: 可調(diào)用方法和響應(yīng)方法(通常稱作回調(diào))。 會話式 Web 服務(wù)中的每個可調(diào)用方法和回調(diào)方法確定該服務(wù)、其客戶端以及該服務(wù)所使用的任何執(zhí)行控件(例如,Java 控件)之間的通信行為。 可調(diào)用方法可以啟動、繼續(xù)或結(jié)束會話;而回調(diào)可以繼續(xù)或停止會話。

            為更好地描述會話式 Web 服務(wù),我將介紹一個場景,在本文通篇將以該場景為基礎(chǔ)。 該示例采用兩個會話: 一個是 Web 服務(wù)與它的客戶端之間的會話,另一個是兩個 Web 服務(wù)之間的會話(參見圖 1)。

            在本示例中,BestTermInsurance Web 服務(wù)通過使用另一個服務(wù) (InsuranceQuote) 代表客戶查找各種保險提供商 。 當(dāng)客戶端請求 BestTermInsurance 服務(wù)提供報價時,將啟動第一個會話;當(dāng) BestTermInsurance 服務(wù)調(diào)用 InsuranceQuote 服務(wù)請求報價時,將啟動第二個會話。 當(dāng) InsuranceQuote 服務(wù)找到最低報價時,它將響應(yīng) BestTermInsurance 服務(wù),第二個會話隨即完成。 然后,BestTermInsurance 服務(wù)恢復(fù)與客戶端的第一個會話。



          圖 1: BestTermInsurance 服務(wù)

            Web 服務(wù)會話保存 Web 服務(wù)的狀態(tài);后者包括用于鏈接 Web 服務(wù)、它的客戶端和其他資源之間的通信的相關(guān)數(shù)據(jù)以及在會話完成之前由該服務(wù)保存的任何數(shù)據(jù)。 該狀態(tài)信息稱作會話狀態(tài)(也稱作關(guān)聯(lián)狀態(tài))。 在本示例中,BestTermInsurance 服務(wù)保存客戶端的每個報價以及關(guān)聯(lián)的消息屬性,直到找到最低報價。

          管理會話狀態(tài)

            使用顯式狀態(tài)標(biāo)識符是在 Web 服務(wù)交互中管理會話狀態(tài)的最簡單和最相當(dāng)有效的方法。 盡管名稱暗示了單個 ID,但完全受管理的會話需要更多的信息,尤其是當(dāng)與服務(wù)請求關(guān)聯(lián)時。 因此,狀態(tài)標(biāo)識符實際上是一個控制類,它保存以下一組針對每個請求-響應(yīng)交互的與狀態(tài)相關(guān)的信息:

          •   Web 服務(wù)客戶端的唯一標(biāo)識符
          •   為該客戶端啟動的 Web 服務(wù)會話的標(biāo)識符
          •   該會話中服務(wù)請求的標(biāo)識符
          •   服務(wù)請求者(客戶端)與服務(wù)提供者之間的會話階段指示器,服務(wù)使用該指示器進行正確的狀態(tài)保持
          •   Web 服務(wù)基礎(chǔ)架構(gòu)的分發(fā)函數(shù)與調(diào)用接口之間的交互狀態(tài)指示器(在使用 Web 服務(wù)接口的晚期綁定進行動態(tài)調(diào)用方面很有幫助)

            出于本文的需要,我采用靜態(tài) Web 服務(wù)調(diào)用,因此將不介紹第 5 種信息。

            一般說來,用于關(guān)聯(lián)請求的技術(shù)解決方案是讓服務(wù)請求者將狀態(tài)標(biāo)識符信息(服務(wù)請求的唯一標(biāo)識符(請求 ID)、會話標(biāo)識符(會話 ID)和會話階段指示器(階段)添加到請求消息中,并讓服務(wù)提供者將標(biāo)識符信息復(fù)制到通過回調(diào)傳遞的響應(yīng)消息中,這樣請求者可以將回復(fù)消息與請求消息相關(guān)聯(lián)。

            有多種方法可以將狀態(tài)標(biāo)識符信息包含在消息交換中,具體包括:

          •   將標(biāo)識符信息以額外的參數(shù)形式傳入 Web 服務(wù)方法;可以將 Web 服務(wù)接口設(shè)計為不但接受 XML 文檔消息,而且接受其他代表狀態(tài)標(biāo)識符信息的參數(shù)。
          •   將標(biāo)識符信息作為 XML 文檔的一部分傳遞 — XML 文檔可以包嵌在其主體中的此種信息。
          •   在 SOAP 消息標(biāo)頭中傳遞標(biāo)識符信息。

            但無論是通過添加額外的輸入?yún)?shù)將標(biāo)識符信息包含在服務(wù)接口中的第一種方法,還是將此類信息包含在 XML 文檔本身中的第二種方法,事實上都會使標(biāo)識符信息處理成為服務(wù)結(jié)構(gòu)一部分,從而使代碼更難以維護。 此外,將來隨著新 Web 服務(wù)標(biāo)準(zhǔn)被更廣泛地接受,可能不再需要自定義解決方案了,從而將難以從服務(wù)實現(xiàn)中“拆除”嵌入的、與標(biāo)識符相關(guān)的邏輯。

            因此,第三種方法,即將標(biāo)識符信息包含在 SOAP 消息標(biāo)頭中是最合理的方法。 使用此方法時,服務(wù)請求者將標(biāo)識符信息作為一組新的子元素添加到消息的 SOAP 標(biāo)頭中。 服務(wù)提供者攔截該 SOAP 消息,然后提取標(biāo)頭中相應(yīng)的狀態(tài)標(biāo)識符信息且不會破壞消息主體。

            簡單地說,將標(biāo)識符信息添加到 SOAP 標(biāo)頭中將使相關(guān)的代碼與文檔處理邏輯和關(guān)聯(lián)的業(yè)務(wù)邏輯以及服務(wù)接口的具體實現(xiàn)相分離。

            實現(xiàn)顯式的狀態(tài)標(biāo)識符 - 示例

            現(xiàn)在,我們將繼續(xù)介紹示例場景 - BestTermInsurance 服務(wù)。 (請參見圖 2 以獲得該場景的說明。) 正如邊條中描述的,Oracle 應(yīng)用服務(wù)器提供了兩個服務(wù)實現(xiàn)選項: 無狀態(tài) Java 類(可以部署到 Web 容器中)或無狀態(tài)會話 EJB。 (該設(shè)計基于將 EJB 與一個服務(wù) fa ade — BestTermInsuranceServlet 一起使用)。 建議您使用 fa?ade 將服務(wù)實現(xiàn)為 EJB,這是因為這樣做不但具有更好的服務(wù)可用性和可伸縮性,還可以引入 SOAP JAX-RPC 處理程序(稍后將對其進行詳細(xì)介紹)。


          圖 2: 示例場景

            下面我們將逐步介紹此示例場景并了解該控件。 當(dāng)客戶端通過調(diào)用 servlet 的 requestQuote 方法(傳遞有關(guān)客戶年齡和健康狀況的信息)提交搜索請求時,Web 服務(wù)交互將啟動。 requestQuote() 方法包含一個 void 返回值,并立即返回,從而使客戶端可以繼續(xù)操作,而不必等待稍后將通過 onBestQuote() 回調(diào)發(fā)送的實際結(jié)果。 顯而易見,應(yīng)將客戶端設(shè)計為從回調(diào)方法中接受消息。

          ??????接下來,BestTermInsuranceServlet 調(diào)用 BestTermInsuranceEJB(用于保存客戶年齡和健康狀況指示器)和一個所獲得的報價列表(與客戶端 ID 和請求 ID 關(guān)聯(lián),作為與狀態(tài)相關(guān)的數(shù)據(jù))。 BestTermInsuranceEJB 隨后調(diào)用 InsuranceQuote 服務(wù)的 obtainQuote() 方法以從參與的保險人那里獲得報價。 (參見圖 3,一個演示最重要的服務(wù)交互的序列圖。)


          圖 3: 使用 JDeveloper Modeler 的示例 UML 序列圖

            InsuranceQuote 服務(wù)在特定客戶端作用域內(nèi)運行,因此該服務(wù)需要訪問客戶端 ID。在會話跟蹤方面,InsuranceQuote 服務(wù)使用它自己的會話和請求 ID。

            在根據(jù)給定的客戶年齡和健康狀況指示器收集所有保險報價時,InsuranceQuote 服務(wù)使用 onObtainQuoteComplete() 回調(diào)返回其結(jié)果。 此回調(diào)完成第二個轉(zhuǎn)換,并清除由 InsuranceQuote 服務(wù)保存的所有狀態(tài)數(shù)據(jù)。 但由 BestInsuranceQuoteServlet 控制的第一個會話仍繼續(xù)執(zhí)行: BestTermInsurance 服務(wù)可能從客戶端獲取其他請求,例如,根據(jù)特殊的保單條款(一年、十年等)提供最佳報價。 結(jié)果以消息形式通過 onBestQuoteCallback() 方法發(fā)送給客戶端。

            編碼技巧

            現(xiàn)在,我們來著重介紹以下實現(xiàn)狀態(tài)標(biāo)識符的具體編碼技巧。 遺憾地是,由于篇幅有限,將只在代碼中介紹與本文主題相關(guān)的元素。

            正如前面所介紹的,假設(shè)狀態(tài)標(biāo)識符信息已傳入 SOAP 消息標(biāo)頭中。 用于基于 XML 的遠(yuǎn)程過程調(diào)用的 Java API (JAX-RPC) 非常適于處理 SOAP 消息標(biāo)頭 - 具體而言就是通過使用 JAX-RPC 的某個最有意義的特性: 消息處理程序。 消息處理程序為 Web 服務(wù)提供了附加的消息處理邏輯,以作為對這些服務(wù)的業(yè)務(wù)邏輯實現(xiàn)的擴展。 除了管理身份驗證、加密和解密、日志記錄和審計等外,處理程序還支持狀態(tài)標(biāo)識符的插入。 為此,可以創(chuàng)建多個處理程序來管理每個具體問題。 在 JAX-RPC 中,處理程序的這種用法稱作處理程序鏈。

            處理程序鏈表示一組有序的處理程序。 使用有序組可以使應(yīng)用程序開發(fā)人員能夠定義處理程序調(diào)用策略 - 調(diào)用順序、目標(biāo)(“僅處理請求”或“僅處理響應(yīng)”或兩者都處理)等。 處理程序鏈繼續(xù)處理處理程序,直到引發(fā) SOAP 錯誤或調(diào)用策略指示顯式停止點。

            因此,要使用 SOAP 標(biāo)頭內(nèi)嵌的狀態(tài)標(biāo)識符實現(xiàn) Web 服務(wù),建議用三個步驟來進行開發(fā):

          •   設(shè)計基本的服務(wù)組件并進行編碼。
          •   開發(fā) SOAP 消息處理程序。
          •   用已開發(fā)的 J2EE 組件構(gòu)造 Web 服務(wù)(公開)。

            使用 Oracle JDeveloper 10g J2EE 開發(fā)人員預(yù)覽版時,可以使用應(yīng)用程序?qū)Ш狡飨碌念悇e“Business Tier”將已編譯的 Java 類或 bean 公開為 Web 服務(wù)。 從該類別中,開發(fā)人員可以選擇一個上下文菜單項“Java Web services”。 此菜單項包含兩個選項“J2EE 1.4 (JAX-RPC) Web services”和“Oracle J2EE 1.3 Web services”。 選擇“J2EE 1.4 (JAX-RPC) Web services”。
           以下代碼清單顯示了一個符合要求的 SOAP 消息格式,其中的標(biāo)頭包含 BestTermInsurance 服務(wù)的外部(客戶端-服務(wù))會話的狀態(tài)標(biāo)識符:

          <SOAP-ENV:Envelope>
          ? <SOAP-ENV:Header>
          ????????? <ns:stateIdentifier xmlns:ns="http://xxxxx">
          ????? <ns:ClientID>Client ID</ns:ClientID>
          ????? <ns:ConversationID>Conversation ID</ns:ConversationID>
          ????? <ns:RequestID>Request ID</ns:Request ID>
          ????? <ns:Phase>Phase</ns:Phase>
          </stateIdentifier
          </SOAP-ENV:Header>
          <SOAP-ENV:Body>
          ???? <ns:insuranceParms xmlns:ns="http://yyyyyyy">
          ???? <ns:Age>Age</ns:Age>
          ???? <ns:Health>Health</ns:Health>
          ???? <ns:Term>Term</ns:Term>
          ???? </ns:insuranceParms
          </SOAP-ENV:Body>
          </SOAP-ENV:Envelope>

          但在此進程的開頭,該 SOAP 消息定義不包含狀態(tài)標(biāo)識符信息,如下所示:
          <SOAP-ENV:Envelope>
          ? <SOAP-ENV:Header>
          </SOAP-ENV:Header>
          <SOAP-ENV:Body>
          ???? <ns:insuranceParms xmlns:ns="http://yyyyyyy">
          ???? <ns:Age>Age</ns:Age>
          ???? <ns:Health>Health</ns:Health>
          ???? <ns:Term>Term</ns:Term>
          ???? </ns:insuranceParms
          </SOAP-ENV:Body>
          </SOAP-ENV:Envelope>
          這正是 SOAP 處理程序的用途所在: 對將狀態(tài)限定符插入到標(biāo)準(zhǔn) SOAP 消息定義進行處理。 在 JAX-RPC 服務(wù)中,處理程序由實現(xiàn) handleRequest() 和 handleResponse() 方法(用于修改請求和響應(yīng)消息)的處理程序類表示。 可以將處理程序類配置為在客戶端或服務(wù)級別處理請求和響應(yīng)。 處理程序使用 javax.xml.soap.SOAPMessage 類來處理 SOAP 消息。 SOAPMessage 對象包含一個 SOAPPart 對象,該對象包含實際的 SOAP XML 文檔和一個被分解為訪問 SOAP 主體和標(biāo)頭的 SOAPEnvelope 對象。

            以下代碼清單演示了所描述的方法:

          package exp.oracle.jaxrrpc.headers;

          .............

          import javax.xml.rpc.*;
          import javax.xml.soap.*;

          public class BestTermInsuranceRequestHandler implements javax.xml.rpc.handler.Handler
          {

          ...........................

          ?/*
          ?*The handleRequest method processes the request message.
          ? */
          try {
          SOAPMessageContext msg = (SOAPMessageContext) context;
          SOAPEnvelope env = msg.getMessage().getSOAPPart().getEnvelope();
          SOAPHeader hdr = env.getHeader();
          exit=processRequestHeader(hdr);

          ?????? }
          catch (Exception ex) {
          ex.printStackTrace();
          ?}

          ?return exit;
          ?}


          ?/*
          ?* This version of the process header method inserts the state identifier information.
          ?*/
          ? private boolean processRequestHeader (SOAPHeader hdr) {
          ? boolean exit = false;
          ?
          ? SOAPFactory sFactory = SOAPFactory.newInstance();?
          try {
          SOAPElement he1 = sFactory.createElement("stateIdentifier",PREFIX,URI);
          SOAPElement che11 = sFactory.createElement("ClientID",PREFIX,URI);
          ??????????? che11.addTextNode("Cust1");
          ??????????? ...............................?
          ??????????? he1.addChildElement(che11);
          ??????????? he1.addChildElement(che12);
          ??????????? he1.addChildElement(che13);
          ???????????
          ??????????? // add the state identifier information to the SOAP header object
          ??????????? hdr.addChildElement(he1);
          ??????????? exit = true;??????

          ?????? }
          ?catch (Exception ex) {
          ???? ex.printStackTrace();
          ?}

          ?return exit;
          ??? }
          開發(fā) SOAP 處理程序后,可以使用 WSA 在相應(yīng)的 webservices.xml 文件中配置它們。 然后,可以繼續(xù)創(chuàng)建部署描述文件并將 Web 服務(wù)安裝到 OC4J 中。

            結(jié)論

            顯而易見,將單個請求-響應(yīng)交互與無狀態(tài)的 Web 服務(wù)結(jié)合使用是最簡單的實現(xiàn)方法。 但伴隨簡單性而來的是一個很大的缺點: 無法實現(xiàn)用于處理復(fù)雜和長期運行的業(yè)務(wù)事務(wù)的 Web 服務(wù)。

            本文介紹的狀態(tài)管理方法所基于的策略以更出色的方法對長期運行的業(yè)務(wù)活動進行建模。 具體而言,在本方法中,服務(wù)“注冊”到良好控制的會話(將特定的工作單元表示為業(yè)務(wù)活動進度)。 此功能對于連接企業(yè)內(nèi)部以及跨企業(yè)的、支持 Web 服務(wù)的應(yīng)用程序很重要,并包含一組支持對連接的應(yīng)用程序之間的交互進行管理和監(jiān)控的特性。


          http://www.oracle.com/technology/global/cn/pub/articles/davydov_soa.html

          posted on 2006-12-02 13:09 BPM 閱讀(272) 評論(0)  編輯  收藏 所屬分類: web services

          主站蜘蛛池模板: 治多县| 彩票| 南丹县| 卢龙县| 孟连| 西乌珠穆沁旗| 七台河市| 深水埗区| 仪征市| 广州市| 周至县| 毕节市| 福泉市| 红原县| 宁夏| 新宾| 宕昌县| 保山市| 五指山市| 成武县| 大新县| 临安市| 临汾市| 蒲城县| 南丰县| 金寨县| 固原市| 中江县| 光泽县| 麻栗坡县| 洛阳市| 加查县| 垣曲县| 沁阳市| 融水| 太原市| 宝清县| 镇康县| 彰化县| 高雄县| 集安市|