精彩的人生

          好好工作,好好生活

          BlogJava 首頁 新隨筆 聯(lián)系 聚合 管理
            147 Posts :: 0 Stories :: 250 Comments :: 0 Trackbacks

          #

            Web services 是一種很有前途的技術(shù),在面向服務(wù)的架構(gòu)( Service Oriented Architectures , SOA )中起著重要的作用。這種正在興起的技術(shù)的一個關(guān)鍵方面就是提供了異步服務(wù)的能力。盡管現(xiàn)在的 web service 標(biāo)準(zhǔn)規(guī)范中包括了提供異步服務(wù)的內(nèi)容,但客戶端應(yīng)用程序前景的細(xì)節(jié)還有一些混亂和模糊。 Web services 回調(diào)是實現(xiàn)這些異步服務(wù)的一個重要因素。這篇文章為創(chuàng)建帶有回調(diào)操作的 Web services 的客戶應(yīng)用程序提供了實踐指導(dǎo)。這篇文章中所有的代碼段都來自于您可以下載的例子。這些例子包含了這些代碼段的完整實現(xiàn)和使用指導(dǎo)。

          術(shù)語

            在開始討論支持回調(diào)的客戶端之前,闡明相關(guān)術(shù)語是很重要的。下圖就顯示了客戶端使用帶有回調(diào)操作的 Web service 時所涉及到的主要實體。

          Figure 1
          圖 1. 調(diào)用 Web service 的客戶端

            上圖描述了客戶端對 Web service 的調(diào)用。 Web service 能夠在一段時間后通過對客戶端的回調(diào)做出響應(yīng) 。因此,包含回調(diào)操作的 Web service 客戶端的特別之處在于,客戶端本身必須提供一個端點。我們調(diào)用這一回調(diào)端點 ,并將這個端點定義為由 URI 確定的唯一地址, SOAP 請求消息將發(fā)送到這個 URI 。

            將 SOAP 消息發(fā)送到Web service 端點 之后,客戶端本身開始與 Web service 進(jìn)行交互。由客戶端發(fā)送給 Web service 的相關(guān)請求消息及其相關(guān)響應(yīng)消息構(gòu)成了客戶端初始化操作 。如前所述,客戶能夠處理 Web service 發(fā)送到回調(diào)端點的請求消息。相關(guān)的請求和響應(yīng)消息一起被稱為一個回調(diào) 操作。

            理解這些術(shù)語之后,讓我們走近一步考察 Web service 回調(diào)的概念,以及它與會話式 Web services 和異步 Web service 調(diào)用之間的關(guān)系。

          異步、回調(diào)和會話

            異步 Web service 調(diào)用的概念有時容易與 Web services 回調(diào)和會話式 Web services 相混淆。雖然這三個概念很相關(guān),但卻不同。

            異步 Web services 調(diào)用 是指在不阻塞接收服務(wù)器發(fā)來的相應(yīng)響應(yīng)消息的情況下,客戶端能夠發(fā)送 SOAP 消息請求 。 BEA WebLogic Platform 8.1 web services 上進(jìn)行異步 Web service 調(diào)用的過程已經(jīng)詳細(xì)地 記錄在軟件文檔中了 ,因此在本文中不作進(jìn)一步的討論。

            Web services 回調(diào) 是指 Web services 提供者向客戶端發(fā)回 SOAP 消息的情況。 Web Services Description Language (WSDL) specifications 將這種操作定義為一種“請求 / 響應(yīng)”。支持回調(diào)操作的 Web services 客戶端本身必須有一個 Web services 端點,這樣 Web service 就可以利用這個 Web services 端點在任意時間發(fā)送回調(diào)請求,也就是說,可以是異步的。注意,這跟我們上面討論的異步調(diào)用 沒有關(guān)聯(lián)。

            如果一系列可在兩個端點之間來回傳送的消息可以被唯一會話 ID 追蹤,而這個 ID 又由特定的操作來標(biāo)識消息流的始末,這種 Web services 就是 會話式 的。提供回調(diào)的 Web services 也定義為會話式的。這是因為正常情況下如果 Web services 能夠?qū)蛻舳诉M(jìn)行回調(diào)訪問,它就必須有它自己的回調(diào)端點信息。這種情況只有客戶端做出了初始調(diào)用以后才會發(fā)生。因此,至少由客戶啟動的初始化操作和由 Web services 做出的回調(diào)操作是相互關(guān)聯(lián)的,并且由唯一的會話 ID 跟蹤。如果不是這樣,客戶端就無法分辨與不同初始調(diào)用相關(guān)聯(lián)的回調(diào)操作。

            我們現(xiàn)在將考慮這些問題并創(chuàng)建支持回調(diào)的客戶端,就像我們剛才所看到的,這些客戶端構(gòu)成了請求 - 響應(yīng)和會話式 Web services 的基礎(chǔ)。

          創(chuàng)建支持回調(diào)的客戶端

            正如前面討論的,支持回調(diào)的 Web services 客戶端需要提供一個能夠異步接收和處理回調(diào)操作消息的回調(diào)端點。為避免必須提供回調(diào)端點這類復(fù)雜的事情,一種叫做 polling (輪詢)的技術(shù)可以作為替代技術(shù)。然而這種技術(shù)要求客戶端周期性地調(diào)用服務(wù)端以校驗回調(diào)事件。如果這種事件很少發(fā)生,那么調(diào)用的開銷就太大了。如果客戶端提供一個回調(diào)端點并直接處理回調(diào)操作,這種開銷就可以避免。

            我們還應(yīng)該注意到,盡管可以通過用 JMS 上的 Web services (如果提供了這種連接)創(chuàng)建支持回調(diào)的客戶端,但這種方法有一些限制,其中一個重要的限制就是客戶端要被迫采用與 Web services 提供者相同的 JMS 實現(xiàn)。因此我們將集中于經(jīng)過 HTTP 傳輸來完成我們的任務(wù)。有兩個領(lǐng)域需要創(chuàng)建這樣的客戶端:創(chuàng)建適當(dāng)?shù)目蛻舳藛?SOAP 消息,以及處理回調(diào)操作。

            當(dāng)客戶端啟動有回調(diào)的 Web service 操作時,它需要以某種方式包含回調(diào)端點的 URI ,使其在請求消息中監(jiān)聽。 Web Services Addressing SOAP Conversation Protocol 規(guī)范都定義了 SOAP 頭部元素,允許您實現(xiàn)這一目標(biāo)。從理論上說,用于規(guī)定回調(diào)端點的規(guī)范并不重要。但是大多數(shù) Web services 容器(包括 BEA WebLogic Server 8.1 )都還沒有包含 Web services Addressing 規(guī)范的實現(xiàn)形式。當(dāng)前, BEA WebLogic Workshop 8.1 的 Web services 支持 SOAP Conversation Protocol 規(guī)范,我們將在例子客戶端中使用。

            根據(jù) SOAP Conversation Protocol , SOAP 頭部在會話的不同階段是不同的。對于會話中的第一個客戶端啟動(開始)操作,我們需要通過 callbackLocation 頭部元素 提供有回調(diào)端點的 Web service 。所有操作(包括第一個操作)也將需要唯一的 ID ,這個 ID 在整個會話過程中都用在我們的 SOAP 消息里。這可通過 conversationID 元素 來完成。下面是一個啟動支持回調(diào)會話的 SOAP 請求消息的例子:

          <soapenv:Envelope soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" 
              xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
              xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
              xmlns:enc="http://schemas.xmlsoap.org/soap/encoding/" 
              xmlns:env="http://schemas.xmlsoap.org/soap/envelop/" 
              xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
            <soapenv:Header>
              <con:StartHeader soapenv:actor="http://schemas.xmlsoap.org/soap/actor/next" 
               soapenv:mustUnderstand="0" 
               xmlns:con="http://www.openuri.org/2002/04/soap/conversation/">
                <con:conversationID>[123456]:192.168.1.100:8181</con:conversationID>
                   <con:callbackLocation>
                    http://192.168.1.100:8181/StockNotificationCallback
                   </con:callbackLocation>
                </con:StartHeader>
           </soapenv:Header>
            <soapenv:Body>
              <n1:registerForThresholdNotif xmlns:n1="http://www.openuri.org/">
                <n1:stockTicker>CCC</n1:stockTicker>
                <n1:threshold>10</n1:threshold>
              </n1:registerForThresholdNotif>
            </soapenv:Body>
          </soapenv:Envelope>
          

            現(xiàn)有的大多數(shù) Java Web service 工具包(例如 BEA WebLogic 的 clientgen 、 Apache Axis 和 JWSDP )都允許您創(chuàng)建一個代理庫,客戶端程序可以容易地用它來調(diào)用 Web services 操作。但是,這些框架中沒有一種支持回調(diào)操作,主要問題是它們的代理不生成所需的頭部。在能提供這種支持以前,通過擴(kuò)展它們對回調(diào)操作的支持來利用這些框架(例如復(fù)雜類 XML 映射),這種益處還是很需要的。一種用來達(dá)到這種效果的技術(shù)就是應(yīng)用 SOAP 消息處理程序

            上面提到的所有 Web services 工具包都能支持 SOAP 消息處理程序。消息處理程序是一種 Java 類,它實現(xiàn)了 javax.xml.rpc.handler.GenericHandler 界面,并且還包含一種稱為先送出(或后接收) SOAP 消息的方法。這里介紹我們客戶端中的消息處理程序,它能夠找出一個特定會話的當(dāng)前階段,并據(jù)此擴(kuò)展帶有所需頭部的請求消息。

            注意到這一點是很重要的,客戶端 SOAP 消息處理程序必須能確定消息屬于會話的哪個階段,以便創(chuàng)建合適的頭部元素。生成會話 ID 也是客戶端處理程序要完成的一個任務(wù)。

            一旦 Web services 端點收到擴(kuò)展的請求消息,它就會將請求消息發(fā)送到由開始消息的 callbackLocation 元素規(guī)定的回調(diào)端點。在大多數(shù)情況下,客戶端過程自身就需要提供這個端點,并且恰當(dāng)?shù)靥幚砘卣{(diào)消息。如果客戶端在 Web services 的容器中運行,這項工作就可以通過把有回調(diào)操作的 Web services 部署在同一個容器內(nèi)來完成。然而,如果客戶端不是正在容器中運行,這項工作就要靠在一個嵌入在客戶端過程本身的輕量級容器中執(zhí)行回調(diào)端點來完成。這使我們能夠調(diào)用客戶端生成的操作,并且處理同一過程上下文中的傳入回調(diào)操作。注意在回調(diào)端點背后(和在客戶端中)的過程實體要求不僅能夠分配對適當(dāng)域的代碼操作,而且還能處理 XML 映射。

            當(dāng)然,客戶端也可以選擇簡單地設(shè)置恰當(dāng)?shù)?callbackLocation 頭部元素來規(guī)定一個在容器中的回調(diào)端點,而這個容器與訪問過程相分離。

            正如我們已經(jīng)看到的,為帶回調(diào)操作的 Web services 創(chuàng)建客戶端并不是毫無意義的,它包含了復(fù)雜元素,比如處理 SOAP 消息、管理會話(包括階段和 ID )、參數(shù)映射以及操作分配。當(dāng) Web service 通過 BEA WebLogic Workshop Service Control 訪問時,這些復(fù)雜性就都不存在了,它會自動為用戶執(zhí)行所有操作。

          使用服務(wù)控件創(chuàng)建支持回調(diào)的客戶端

            通過 WebLogic Workshop Service Control 訪問 Web services 在 軟件文檔 中已經(jīng)做了詳細(xì)描述。如果客戶端實體能夠使用控件(也就是 Java Process Definition 業(yè)務(wù)流程或其他控件; Page Flows 不能使用控件回調(diào)),這個解決方案就是最簡單的使用支持回調(diào)的 Web services 的方案了。采用這種方法,所有涉及訪問支持回調(diào)的 Web service 的復(fù)雜性就都迎刃而解了。

          股票通知服務(wù)例子

            本文的例子包括一個股票通知( Stock Notification )的會話式 Web service 和一個能闡明概念的示例客戶端。 Web service 提供的操作允許客戶端注冊股票接收機(jī)并設(shè)置一個相關(guān)的閾值價格。然后服務(wù)端就監(jiān)視股票,只要股票價格超過了閾值價格就通過一個回調(diào)( onThresholdPassed() )通知客戶端。

          Figure 2
          圖 2. 本圖說明了這個例子的配置

            很顯然,輪詢技術(shù)不是創(chuàng)建客戶端的最佳解決方案:股票價格有可能經(jīng)常超過閾值價格也可能極少超過閾值價格。輪詢間隔短就會造成很多不必要的訪問,而另一方面,輪詢間隔長又可能導(dǎo)致股票價格超過閾值價格很長時間后客戶端才被告知。

            客戶端應(yīng)用程序中回調(diào)端點的實現(xiàn)應(yīng)該是一種更好的解決方案。讓我們首先來看一下例子客戶端是如何將操作傳遞給 StockNotification Web service 的。我們已經(jīng)采用兩種不同的技術(shù)實現(xiàn)了客戶端。第一種技術(shù)使用 WebLogic Workshop 生成的代理庫,并由 StockNotificationClient 類的 makeCallUsingBEAProxy() 方法來實現(xiàn):

          public void makeCallUsingBEAProxy() {
              try {
                // Get the proxy instance so that we can start calling the web service operations
                StockNotificationSoap sns = null;
                StockNotification_Impl snsi = new StockNotification_Impl();
                sns = snsi.getStockNotificationSoap();
          
                // Register our conversational handler so that it can properly set our
                // our conversation headers with a callback location
                QName portName = new QName("http://www.openuri.org/",
                                           "StockNotificationSoap");
                HandlerRegistry registry = snsi.getHandlerRegistry();
                List handlerList = new ArrayList();
                handlerList.add(new HandlerInfo(ClientConversationHandler.class, null, null));
                registry.setHandlerChain(portName, handlerList);
          
                // Register, call some methods, then sleep a bit so that our callback
                // location can receive some notifications and finally finish the conversation.
                sns.registerForThresholdNotif("AAAAA", "100");
                sns.addToRegistration("BBBBB", "5");
                StockList stocks = sns.getAllRegisteredStocks();
          
                ...
          
                sns.endAllNotifications();
              }
              catch (Exception e) {
                throw new RuntimeException(e);
              }
          }
          

            正如從上述代碼段中看到的,我們可以使用 clientgen 生成的類。與沒有回調(diào)的 Web service 調(diào)用相比,這段代碼唯一強(qiáng)調(diào)的就是,在方法一開始就實例化和注冊了客戶端 SOAP 消息處理程序。這個處理程序截取了發(fā)出的 SOAP 消息,并加上必要的會話頭部。每當(dāng)客戶端過程發(fā)出 SOAP 請求消息時,消息處理程序的 handleRequest() 方法就被調(diào)用,它利用了一個包含了輸出 SOAP 請求信息的 MessageContext 對象。下面是例子客戶端消息處理程序的代碼段:

          package weblogic.webservice.core.handler;
          
          ...
          
          public class ClientConversationHandler
              extends GenericHandler {
          
          public boolean handleRequest(MessageContext ctx) {  
            ...
            if (phase.equals("START")) {
              headerElement
                        = (SOAPHeaderElement) header
                        .addChildElement("StartHeader",
                                         "con",
                                         "http://www.openuri.org/2002/04/soap/conversation/");
          
              headerElement.addChildElement("con:callbackLocation")
                        .addTextNode(CALLBACK_URI);
            }
            else if (phase.equals("CONTINUE") || phase.equals("FINISH")) {
              headerElement
                        = (SOAPHeaderElement) header
                        .addChildElement("ContinueHeader",
                                         "con",
                                         "http://www.openuri.org/2002/04/soap/conversation/");
            }
          
            headerElement.addChildElement("con:conversationID").addTextNode(convID);
            ...
          }
          }
          

            BEA clientgen 工具生成的代理庫已經(jīng)用了一個缺省的客戶端 SOAP 消息處理程序,可創(chuàng)建會話式 StartHeader 頭部元素。不幸的是,目前的 clientgen 輸出不支持回調(diào)操作,因此缺省的處理程序不會創(chuàng)建所需的 callbackLocation 次級元素。所以我們必須保證自己的消息處理程序重寫缺省的會話式處理程序,以便管理創(chuàng)建 callbackLocation 頭部的額外任務(wù)。我們通過確保處理程序在一個與缺省處理程序相同的程序包中創(chuàng)建來做到這一點,這個程序包就是 weblogic.webservice.core.handler ,并且它還有具體的相同類名稱 ClientConversationHandler 。注意,這種技術(shù)涉及到重寫現(xiàn)有會話消息處理程序,但它并不能保證是向前兼容的。這個例子展示了消息處理程序如何用于創(chuàng)建回調(diào)頭部,以及這種概念如何應(yīng)用于任何其他支持 SOAP 消息處理程序的 Web services 框架中。

            有一種使用 SOAP 消息處理程序和代理類的可選技術(shù),它使用 JAXM API 直接創(chuàng)建 SOAP 請求消息,并把它們送往 Web service 。這是我們例子客戶端采用的第二種技術(shù),它在 StockNotificationClient 類的 makeCallsUsingJAXM() 和 callMethodFromFile() 方法中實現(xiàn):

          public void makeCallsUsingJAXM() {
                callMethodFromFile("C:\\registerForNotifSOAP.xml");
                ...
                callMethodFromFile("C:\\endAllNotifSOAP.xml");
          }
          
          private void callMethodFromFile(String fileName) {
          
              try {
                // Create a SOAP connection object
                SOAPConnectionFactory scf = SOAPConnectionFactory.newInstance();
                SOAPConnection conn = scf.createConnection();
          
                // Create the SOAP request message from the specified file
                MessageFactory mf = MessageFactory.newInstance();
                SOAPMessage msg = mf.createMessage();
                SOAPPart sp = msg.getSOAPPart();
          
                // Read the file content into a string and replace the conversation ID with
                // the current one.
                String fileContent = readFileIntoString(fileName);
                fileContent = fileContent.replaceFirst(CONV_ID_HOLDER,
                                                       ConvIDGenerator.getInstance().
                                                       getConversationID());
          
                StreamSource prepMsg = new StreamSource(new StringBufferInputStream(
                    fileContent));
                sp.setContent(prepMsg);
                msg.saveChanges();
          
                // Make the actual call
                conn.call(msg, TARGET_SERVICE_URI);
                conn.close();
              }
              catch (Exception ex) {
                throw new RuntimeException(ex);
              }
          }   
          

            callMethodFromFile() 方法從指定的文件讀取 SOAP 消息,用客戶端的當(dāng)前會話 ID 取代消息會話 ID ,最后生成實際調(diào)用。當(dāng)使用 JAXM 方法時, Java 到 XML 的映射操作參數(shù)和返回值必須由客戶端來完成。通過使用從文件中預(yù)先生成的 SOAP 消息(它已經(jīng)包含了所需的參數(shù)值),我們已經(jīng)避免了這一任務(wù)。盡管從概念上來說這種方法很好,但對于比較復(fù)雜的客戶端端來說,這不是一種可行的解決方案。這些客戶端必須從頭開始通過編程方式使用 JAXM 來創(chuàng)建消息。

            既然我們已經(jīng)回顧了客戶端在生成 Web services 操作中的作用,下面讓我們轉(zhuǎn)向客戶端的回調(diào)端點的實現(xiàn)方式和對來自 Web services 回調(diào)消息的處理。因為回調(diào)端點需要能夠處理輸入的 HTTP 請求, servlet 就是一種合適的選擇。進(jìn)一步說,我們非常需要一個 servlet ,它能夠從輸入的 HTTP 請求中提取 SOAP 消息,并以一種容易使用的方式提供給我們。 javax.xml.messaging 程序包里的 ReqRespListener 接口和 JAXMServlet 類提供給我們這個功能。只要安排合理,應(yīng)用了這種接口和類的 servlet 將把所有的目標(biāo) HTTP post 請求自動轉(zhuǎn)換成 SOAPMessage 實例,并通過 onMessage() 方法傳遞給我們。下面的代碼顯示了 onMessage() 方法如何幫助例子客戶端實現(xiàn)這些功能。

          public class CallBackHandlerServlet
              extends JAXMServlet
              implements ReqRespListener {
          
          
            public SOAPMessage onMessage(SOAPMessage message) {
              try {
                // We have just received a SOAP message at the callback
                // endpoint. In this example we will just assume that
                // the message received is in fact the onThresholdPassed
                // callback request. However, a servlet handling
                // multiple callbacks cannot make this assumption and
                // should process the SOAP message to see what callback
                // it relates to and do as appropriate for each.
                String stockTicker = extractOnThresholdPassedArgument(message);
          
          	System.out.println("[DEV2DEV CALLBACK EXAMPLE]: Received treshold notification 
          	                                for: " + stockTicker);
          
                // Now we have to create a proper response to the callback
                // request. Returning this response as part of the onMessage()
                // method will ensure that the SOAP response gets back to the server.
                SOAPMessage response = createThresholdPassedResponse();
          
                return response;
              }
              catch (Exception e) {
                throw new RuntimeException(e);
              }
            }
            ...
          }
          

            一旦回調(diào)請求消息被 onMessage() 方法所接收,客戶端就從股票接收機(jī)中提取參數(shù),將它輸出到標(biāo)準(zhǔn)設(shè)備上,并生成一條相應(yīng)的響應(yīng)消息,它還會通過 servlet 返回到 Web service 。使用帶有多個回調(diào)操作的 Web services 客戶端也需要把傳入的請求分發(fā)給客戶端代碼的合適部分,這個過程是基于相應(yīng)的回調(diào)操作的。

            盡管 servlet 包含了合適代碼來處理來自 Web services 的傳入 onThresholdPassed() 回調(diào)消息,但它需要在監(jiān)聽回調(diào) URI 的 servlet 容器中部署完成,這樣才能完成回調(diào)端點的實現(xiàn)。 Jetty 開源項目有一個輕量級 servlet 容器,它可以嵌入在我們的客戶端中。將 CallBackHandlerServlet servlet 部署在一個嵌入式 Jetty 容器中,允許我們將回調(diào)端點駐留在客戶端 Java 進(jìn)程中。 StockNotificationCallbackProcessor 類是一種客戶端使用的公共類,它用于啟動 Jetty 服務(wù)器和部署CallBackHandlerServlet servlet :

          public class StockNotificationCallbackProcessor {
          
            public static final String CALLBACK_SERVER_PORT = ":8181";
            public static final String CALLBACK_SERVLET_CLASS = 
                 "asynchwsconsumer.CallBackHandlerServlet";
            public static final String CALLBACK_SERVLET_NAME = "CallBackHandlerServlet";
          
            private HttpServer server;
          
            public StockNotificationCallbackProcessor() {}
          
            public void startListening() {
          
              try {
                // Configure the server so that we listen on the callback URI
                server = new Server();
                server.addListener(CALLBACK_SERVER_PORT);
                ServletHttpContext context = (ServletHttpContext) server.getContext("/");
                context.addServlet(CALLBACK_SERVLET_NAME, "/*",
                                   CALLBACK_SERVLET_CLASS);
          
                // Start the http server
                server.start();
              }
              catch (Exception e) {
                throw new RuntimeException(e);
              }
            }
          
            public void stopListening() {
              try {
                server.stop();
              }
              catch (Exception e) {
                throw new RuntimeException(e);
              }
            }
          }
          

            startListening() 方法把 CallBackHandlerServlet 部署在端口 8181 上并配置嵌入式 servlet 容器,這樣所有 HTTP 請求都將指向這個端口。這種方法還啟動了嵌入式 servlet 容器。

            現(xiàn)在我們已經(jīng)考察了 Web service 操作的創(chuàng)建和回調(diào)操作的處理,下面我們來看看例子客戶端的 main() 方法是如何使用這些元素的:

          public static void main(String[] args) {
          
              StockNotificationClient snClient = new StockNotificationClient();
          
              snClient.snCallbackProcessor.startListening();
          
              snClient.makeCallUsingBEAProxy();
          
              ConvIDGenerator.getInstance().resetConversationID();
          
              snClient.makeCallsUsingJAXM();
          
              snClient.snCallbackProcessor.stopListening();
          }
          

            正如您所看到的,這種方法開始于建立一個回調(diào)端點(正如前面所看到的,它包括啟動嵌入式 servlet 容器和部署回調(diào)過程)。該方法接著使用 BEA clientgen 代理來調(diào)用股票通知的 Web service 。這樣,這種與 Web services 的交互就通過調(diào)用 endAllNotifications() 端操作來完成會話,客戶端需要改變會話 ID 以啟動新會話。客戶端使用 ConvIDGenerator 單一類來管理會話 ID ,而 ConvIDGenerator 類又使用 java.rmi.dgc.VMID 類來創(chuàng)建合適的格式化唯一會話 ID 。

            一旦會話 ID 發(fā)生了變化,客戶端就會用 JAXM 再一次調(diào)用股票通知 Web services 。最后,客戶端終止嵌入式 servlet 容器,這個過程就結(jié)束了。

            我們現(xiàn)在已經(jīng)完成了對例子客戶端的分析,該例子客戶端可作為本文的一部分下載。當(dāng)您運行客戶端和股票通知 Web services 的時候,客戶端和 Web service 都將把消息顯示在標(biāo)準(zhǔn)輸出設(shè)備上,用以描述會話的不同階段,包括對回調(diào)操作的處理。

          結(jié)束語

            本文展示了為包含回調(diào)操作的 Web services 創(chuàng)建獨立客戶端過程的步驟。這種客戶端需要管理 Web services 調(diào)用的會話方面,并提供一個端點用于 Web service 進(jìn)行回調(diào)操作。

          下載

          CallbackExample.zip (1.7Mb) ——這個文件包括了本文講述的完整實例應(yīng)用程序。

          參考資料

          原文出處

          http://dev2dev.bea.com/pub/a/ 2005/03/c allback_clients.html

          posted @ 2006-05-07 16:19 hopeshared 閱讀(1336) | 評論 (0)編輯 收藏

          摘要:

          到目前為止,web service交互作用是獨立同步的,同時本質(zhì)上是應(yīng)答式的。不過,很顯然同步應(yīng)答類型在基于消息的應(yīng)用中只是一個很小的子集。消息在耦合松散系統(tǒng)中是非常重要的,因此這種限制很關(guān)鍵。Web service規(guī)范,例如WS-addressing和WSDL,已經(jīng)融入了消息的概念并且為包含一個相當(dāng)大范圍的消息應(yīng)用奠定了基礎(chǔ)。Apache Axis2 架構(gòu)既不基于任一個消息交換模式,也不基于同步/異步行為。這篇文章解釋了消息概念和Axis2在幾種眾所周知的消息場合中怎樣被擴(kuò)展使用。

          關(guān)于Apache Axis2的Web service消息

          作者:Srinath Perera, Ajith Ranabahu

          07/27/2005

          翻譯:doomsday

          版權(quán)聲明:可以任意轉(zhuǎn)載,轉(zhuǎn)載時請務(wù)必以超鏈接形式標(biāo)明文章原始出處和作者信息及本聲明
          英文原文地址:
          http://www.onjava.com/pub/a/onjava/2005/07/27/axis2.html
          中文地址:
          http://www.matrix.org.cn/resource/article/43/43723_Apache_Axis2.html
          關(guān)鍵詞: Apache Axis2 Web service

          ??
          ???? 到目前為止,web service交互作用是獨立同步的,同時本質(zhì)上是應(yīng)答式的。不過,很顯然同步應(yīng)答類型在基于消息的應(yīng)用中只是一個很小的子集。消息在耦合松散系統(tǒng)中是非常重要的,因此這種限制很關(guān)鍵。Web service規(guī)范,例如WS-addressing和WSDL,已經(jīng)融入了消息的概念并且為包含一個相當(dāng)大范圍的消息應(yīng)用奠定了基礎(chǔ)。Apache Axis2 架構(gòu)既不基于任一個消息交換模式,也不基于同步/異步行為。這篇文章解釋了消息概念和Axis2在幾種眾所周知的消息場合中怎樣被擴(kuò)展使用。

          消息的簡單介紹

          ????貫穿計算歷史,分布式運算是其中的一個很大的挑戰(zhàn):當(dāng)資源是分布式時,進(jìn)程間的通信變得相當(dāng)困難,研究人員仍然在尋找更好的解決方案。有趣的是,幾乎所有關(guān)于分布式計算機(jī)計算能力問題的解決方案來源于兩種概念基礎(chǔ): 遠(yuǎn)程過程調(diào)用(RPC) 和消息傳遞。

          ????毫無疑問,使用RPC在開發(fā)人員中是非常流行的技術(shù),部分原因是是本地過程調(diào)用與它的類似之處。本地過程調(diào)用在程序員中很有人氣,所以在分布式系統(tǒng)中使用RPC是很自然的選擇,而另一方面,消息傳遞不是非常流行,當(dāng)它被提起時很少有開發(fā)人員關(guān)注它。不過,在某些場合使用消息相比RPC系統(tǒng)有更好的優(yōu)勢。

          RPC和消息框架的基本差異如下所示:

          ●消息完全不懂客戶端和服務(wù)器,因為一個消息框架(通常所說的面向消息的中間件,或message-oriented middleware,即MOM)集中于傳遞消息,所有接收和散發(fā)消息的節(jié)點身份平等,術(shù)語稱之為對等體。RPC始終有服務(wù)請求者 (AKA client) 和服務(wù)提供者 (AKA server)的概念。
          ●消息對于一個特定范疇是時間獨立的。沒有任何對等體希望實時接收消息--當(dāng)對等體可用時MOM關(guān)注于傳遞一個消息到相應(yīng)的對等體,然而,RPC在失去一方時立即失效。
          ●消息可被復(fù)制并且輕易的傳遞到眾多對待體。RPC本質(zhì)上是一種一對一的交流方式,而消息更靈活,并且毫不費力地傳遞同一消息的拷貝到多種對等體。

          Web service消息

          ????Web service是在XML消息的基礎(chǔ)上定義的,下面3個因素描述了一個給定的Web service的消息交互。

          ●消息交換模式
          ●同步和異步客戶端API
          ●單向和雙向傳送行為

          ????從最抽象的角度來講,,web service消息傳遞建立在發(fā)送和接收消息基礎(chǔ)上,一個給定的消息被一方發(fā)出,并且被另一方接收。消息可能相互關(guān)聯(lián),識別這些相互關(guān)聯(lián)的消息群中的最常見的應(yīng)用場合是非常重要的,這些消息群被定義為消息交換模式(message exchange patterns),簡稱MEPs.

          ????過渡時期下在兩種相關(guān)消息間的一個服務(wù)請求者的行為在客戶端API定義了消息同步/異步行為。同步場合下,客戶端請求將會阻塞,在相關(guān)消息到達(dá)目的地后前一直等待,在非阻塞場合下,客戶端請求不會阻塞,當(dāng)相關(guān)消息到達(dá)時,它與之前的消息相互聯(lián)系。

          ????傳送分類為單向或雙向,基于單方或雙方行為。類似SMTP和JMS傳送即是單向傳送的,不會阻塞,另一方面,類似HTTP和TCP即是雙向傳送,相關(guān)消息可能在回路中返回,實際上,在Web service消息中,雙向傳送可能被用作單向傳送,但是在這些場合下,它們可被有效的處理為單向方式。

          消息交換模式

          ????根據(jù)W3C建議,消息交互模式就是一個為交流雙方構(gòu)建消息交換的一個模板,一個MEP將相關(guān)消息確定為一組。MEPs根據(jù)服務(wù)請求者和服務(wù)提供者來定義,需要注意,為了清晰,MEPs以服務(wù)提供者的消息特性來命名。為方便理解,所有的命名都可以用request代替in, 用response代替out。

          例如,我們看看兩個有名的MEPS

          1.In-only/"發(fā)后不理:" 服務(wù)請求者發(fā)送消息給服務(wù)提供者但是不關(guān)心任何后繼相關(guān)消息
          2.In-out/"應(yīng)答式:" 服務(wù)請求者發(fā)送消息給服務(wù)提供者并希望返回結(jié)果

          ????MEPS概念仍在擴(kuò)展中,模式的數(shù)目是沒有限制的,所以Web service中間件應(yīng)用強(qiáng)制使用幾種選定的MEPs,"發(fā)后不理"和 "應(yīng)答式" 是被明確使用的,其它大多數(shù)的模式可由這兩種組合使用。

          客戶端API同步/異步行為

          ????同步/異步(或阻塞/非阻塞)行為是基于在web service請求的線程,同步服務(wù)將會阻塞,等待相關(guān)消息到達(dá)。另一方面,異步請求僅僅返回,等待相關(guān)消息被后臺另一個不同線程執(zhí)行。

          ????這兩種途徑有典型的用例。考慮一下銀行事務(wù),其需要一定數(shù)量的消息來來回傳遞。銀行事務(wù)本質(zhì)是連續(xù)的,當(dāng)結(jié)果到達(dá)時后執(zhí)行下一步驟,因此同步等待結(jié)果很有意義。另一方面,設(shè)想一個航班預(yù)約程序,其需要搜集多種數(shù)據(jù)來源,根據(jù)這些結(jié)果再匹配。這個案例中,異步行為發(fā)揮作用,因為程序可以提交所有結(jié)果并且當(dāng)數(shù)據(jù)到達(dá)時工作。考慮到網(wǎng)絡(luò)響應(yīng),異步方式獲得較好的結(jié)果。

          ????同步請求很簡單:請求在相關(guān)消息到達(dá)前等待,并且可以像本地過程調(diào)用一樣被編碼。但是異步消息的相互關(guān)系就比較復(fù)雜,客戶端必須處理這種復(fù)雜性。盡管如此,通過一些額外工作來處理這種復(fù)雜情況仍是必要的。

          傳輸層的行為

          ????傳輸層的行為是個關(guān)鍵因素,決定了Web service消息的發(fā)生,傳輸根據(jù)依據(jù)其行為分類為單向和雙向。
          ????單向傳送減少web service消息的復(fù)雜性,因為相關(guān)消息必須來源于各自的通道。另一方面,如果傳送是雙向的,消息有機(jī)會選擇使用單向還是雙向,例如,傳輸是HTTP時,相關(guān)消息來自HTTP連接的返回路徑,或者這么講web service提供者可以寫HTTP 200來指出沒有來自同一連接的響應(yīng),在這種案例下回應(yīng)經(jīng)由獨立的HTTP連接發(fā)送。

          Web service尋址角色

          ????webs ervice尋址框架(也被稱為WS-addressing)是為了在同一web service交互活動中交換不同信息部分,下面的5個因素定義了交互活動:

          ????1.消息交換模式
          ????2.可被訪問的服務(wù)傳送
          ????3.相關(guān)消息傳送
          ????4.傳送的行為
          ????5.客戶端API的同步/異步行為

          ????服務(wù)提供者申明了頭兩個,客戶端定義了其余因素,客戶端級別的同步/異步行為對服務(wù)提供者是完全透明的,客戶端使用WS-addressing來解釋web service消息。

          ????在其它大多數(shù)結(jié)構(gòu)中,WS-addressing定義了四種標(biāo)題:To, ReplyTo, RelatesTo, FaultTo以及一個被稱為匿名地址的特定地址,當(dāng)一個服務(wù)提供者接收到SOAP消息時,它會查找在to地址上的目標(biāo)服務(wù)并且調(diào)用服務(wù)。如果有結(jié)果,即被發(fā)送到ReplyTo地址,錯誤被發(fā)送到FaultTo地址,如果以上任一個的標(biāo)題沒有指定或具有匿名值,結(jié)果通過雙向傳送返回路徑返回(因為匿名決定雙向傳送返回路徑)。

          ????傳送和WS-addressing一起定義了查找相關(guān)消息的機(jī)制,消息是相關(guān)緣于它們共享了相同的傳送通道,也可能因為它們都共享把它們互相鏈接的公共信息。web service RelateTo標(biāo)題正好提供了這種關(guān)系。

          下面的表顯示的明確定義的消息交互活動的尋址標(biāo)題的不同值



          Axis2客戶端API概念

          ????Axis2客戶端API處理了In-Only和In-OutMEPs,所有的消息結(jié)合在下面的章節(jié)討論。MEPs的空間是無限的,因此,Axis2強(qiáng)制提供了支持任意消息交換模式的核心,并且提供了兩種常被使用的模式In-Only和In-Out的API,有兩種方法實現(xiàn)更多的復(fù)雜模式:組合In-Only和In-Out來完成希望的模式,或者對希望的模式寫新的擴(kuò)展。因為Axis2為任意MEP提供核心級別的支持,實現(xiàn)是顯而易見的。In-Only和In-OutMEPS被InOnlyMEPClient和InOutMEPClient類支持,下兩節(jié)即做具體描述。

          In-Only MEP 支持: InOnlyMEPClient

          ????InOnlyMEPClient類對發(fā)送不理消息提供了支持,所有的傳送類型作為單向傳送對待,InOnlyMEPClient和InOutMEPClient真正的差別是尋址參數(shù)起先沒有鎖定,并且尋址參數(shù)隨后被Axis2控制。作為可被控制的尋址參數(shù),InOnlyMEPClient可被用作消息API,并且在此基礎(chǔ)上構(gòu)建更復(fù)雜的消息交互。

          In-Out MEP 支持: InOutMEPClient

          ????InOutMEPClient和繼承了InOutMEPClient的調(diào)用類為應(yīng)答式消息提供了支持,Axis2關(guān)注完整的操作,除了To地址外的所有的尋址屬性都在Axis2的控制下

          ????用戶可以配置InOutMEPClient 來表現(xiàn)不同,利用以下的四個參數(shù)。

          1.發(fā)送者傳輸
          2.監(jiān)聽者傳輸
          3.是用單獨監(jiān)聽
          4.使用阻塞



          ????客戶端API當(dāng)前提供了針對HTTP和SMTP傳輸?shù)闹С郑旅娴谋砀耧@示了這些參數(shù)可能的組合以及它們怎樣結(jié)合來提供不同特效。

          舉例

          ????下面的代碼實例顯示了怎樣使用Apache Axis2做幾個定義明確的交互作用,用戶可以在客戶端API簡單的轉(zhuǎn)換屬性從而轉(zhuǎn)換不同的交互作用,客戶端Axis2 API僅僅支持XML級別的消息和代表大塊XML的OME元素。

          調(diào)用單向消息

          ????單向MEP簡單之處在于在僅有一個消息來回傳送時它能表現(xiàn)正確的單向,這些消息被異步對待并且傳送是單向的。

          應(yīng)答式消息

          ????可以表現(xiàn)四種方式的應(yīng)答式消息

          ????1.雙向In-Out 同步
          ????2.雙向In-Out 異步
          ????3.單向In-Out 同步
          ????4.單向In-Out 異步

          ????下面的代碼實例說明這些案例怎樣被Axis2尋址,注意客戶端API的四種屬性怎樣被使用。

          ????1.In-Out同步,HTTP作為雙向傳輸方式

          OMElement payload = .... 
          Call call = new Call();
          call.setTo(
          ????????new EndpointReference(AddressingConstants.WSA_TO,
          ????????????????"HTTP://...));
          call.setTransportInfo(Constants.TRANSPORT_HTTP,
          ?????? Constants.TRANSPORT_HTTP, false);
          OMElement result =
          ????????(OMElement) call.invokeBlocking(
          ????????operationName.getLocalPart(), payload);


          ????這里,SOAP消息經(jīng)由同一個HTTP連接傳播,地址屬性沒有指定,所以它們在服務(wù)器方缺省為匿名,客戶端API將被鎖定直到回復(fù)消息到達(dá)。

          ????2.In-Out異步,HTTP使用HTTP作為雙向傳送

          //this is the payload goes on the body of SOAP message 
          OMElement payload = ....
          Call call = new Call();
          call.setTo(
          ????????new EndpointReference(AddressingConstants.WSA_TO,
          ????????????????"HTTP://...));
          call.setTransportInfo(Constants.TRANSPORT_HTTP,
          ??????????????Constants.TRANSPORT_HTTP, false);

          Callback callback = new Callback() {
          ????public void onComplete(AsyncResult result) {
          ????????//what user can do to result
          ????}
          ????public void reportError(Exception e) {
          ?????? //on error
          ????}
          };
          call.invokeNonBlocking(operationName.getLocalPart(),
          ?????? payload, callback);


          ????和前面相同,SOAP消息經(jīng)由同一個HTTP連接傳輸并且不需要尋址,一旦回復(fù)消息到達(dá)客戶端API不會阻塞并且回調(diào)將被執(zhí)行。

          ????3.In-Out, 異步HTTP 作為單向傳輸

          OMElement payload = .... 
          Call call = new Call();
          call.setTo(
          ????????new EndpointReference(AddressingConstants.WSA_TO,
          ????????????????"HTTP://...));
          call.setTransportInfo(Constants.TRANSPORT_HTTP,
          ????Constants.TRANSPORT_HTTP, true);
          Callback callback = new Callback() {
          ????????public void onComplete(AsyncResult result) {
          ????????....
          ????????}

          ????????public void reportError(Exception e) {
          ????????...
          ????????}
          };
          call.engageModule(new Qname("addressing"));
          call.invokeNonBlocking(operationName.getLocalPart(), method, callback);


          ????在這個案例中,SOAP消息通過兩個HTTP連接傳輸,尋址是強(qiáng)制的,ReplyTo標(biāo)題出現(xiàn)指示服務(wù)器端經(jīng)由單獨的通道發(fā)送回應(yīng)。客戶端沒有阻塞,當(dāng)回應(yīng)消息到達(dá)時,喚起回調(diào)。

          4.In-Out, 同步 HTTP 作為單向傳送

          OMElement payload = .... 
          Call call = new Call();
          call.setTo(
          new EndpointReference(AddressingConstants.WSA_TO,
          ????????"HTTP://...));
          call.setTransportInfo(Constants.TRANSPORT_HTTP,
          ????Constants.TRANSPORT_HTTP, true);
          OMElement result =
          ????????(OMElement) call.invokeBlocking(
          ?????????? operationName.getLocalPart(), payload);


          ????在這種場合下使用"In-Out,異步HTTP作為單向傳送"類型,在結(jié)果到達(dá)第二種連接時喚起阻塞,執(zhí)行并返回結(jié)果。

          總結(jié)

          ????總而言之,web wervice消息行為建立在三種因素上:消息交互模式,客戶端同步異步模式和傳送行為。Asis2建立核心在不一定要任何MEP類型,不過為MEPs的廣泛支持:單向和應(yīng)答提供了客戶端API支持,這篇文章解釋Axis2消息支持概念和客戶端API的使用。

          資源
          ??
          Apache Axis2的官方站點
          ●W3C討論稿, "WSDL Version 2.0 Part 2: Message Exchange Patterns"
          "Why Messaging? The Mountain of Worthless Information," Ted Neward的博客, 星期三,2003年5月9日
          "Introduction to WS-Addressing,"??作者Beth Linker, dev2dev, 2005年1月31日
          "Async," Dave Orchard的博客, 2005年5月5日
          "Programming Patterns to Build Asynchronous Web Services,"??Holt Adams, IBM開發(fā)者文集, 2002年6月1日

          Srinath Perera是Apache Axis2的主要架構(gòu)師
          Ajith Ranabahu是Apache Axis2項目的成員并且在基于Web service的項目里工作了3年


          posted @ 2006-05-07 16:05 hopeshared 閱讀(730) | 評論 (0)編輯 收藏

               摘要: 深入學(xué)習(xí)Web Service系列之 異步開發(fā)模式 ——《深入學(xué)習(xí) Web Service 系列》之一 Terrylee , 2005 年 12 月 4 日 ...  閱讀全文
          posted @ 2006-05-07 15:28 hopeshared 閱讀(785) | 評論 (0)編輯 收藏

          在確定是否適合在您的應(yīng)用程序中采用異步 Web 方法時,有幾個問題需要考慮。首先,調(diào)用的 BeginXXX 函數(shù)必須返回一個 IAsyncResult 接口。IAsyncResult 是從多個異步 I/O 操作返回的,這些操作包括訪問數(shù)據(jù)流、進(jìn)行 Microsoft&reg; Windows&reg; 套接字調(diào)用、執(zhí)行文件 I/O、與其他硬件設(shè)備交互、調(diào)用異步方法,當(dāng)然也包括調(diào)用其他 Web 服務(wù)。您可以從這些異步操作中得到 IAsyncResult,以便從 BeginXXX 函數(shù)返回它。您也可以創(chuàng)建自己的類以實現(xiàn) IAsyncResult 接口,但隨后可能需要以某種方式包裝前面提到的某個 I/O 操作。

          對于前面提到的大多數(shù)異步操作,使用異步 Web 方法包裝后端異步調(diào)用很有意義,可以使 Web 服務(wù)代碼更有效。但使用委托進(jìn)行異步方法調(diào)用時除外。委托會導(dǎo)致異步方法調(diào)用占用進(jìn)程線程池中的某個線程。不幸的是,ASMX 處理程序為進(jìn)入的請求提供服務(wù)時同樣要使用這些線程。所以與對硬件或網(wǎng)絡(luò)資源執(zhí)行真正 I/O 操作的調(diào)用不同,使用委托的異步方法調(diào)用在執(zhí)行時仍將占用其中一個進(jìn)程線程。您也可以占用原來的線程,同步運行您的 Web 方法。

          下面的示例顯示了一個調(diào)用后端 Web 服務(wù)的異步 Web 方法。它已經(jīng)使用 WebMethod 屬性標(biāo)識了 BeginGetAge 和 EndGetAge 方法,以便異步運行。此異步 Web 方法的代碼調(diào)用名為 UserInfoQuery 的后端 Web 方法,以獲得它需要返回的信息。對 UserInfoQuery 的調(diào)用被異步執(zhí)行,并被傳遞到 AsyncCallback 函數(shù),后者被傳遞到 BeginGetAge 方法。這將導(dǎo)致當(dāng)后端請求完成時,調(diào)用內(nèi)部回調(diào)函數(shù)。然后,回調(diào)函數(shù)將調(diào)用 EndGetAge 方法以完成請求。此示例中的代碼比前面示例中的代碼簡單得多,并且還具有另外一個優(yōu)點,即沒有在與為中間層 Web 方法請求提供服務(wù)的相同線程池中啟動后端處理。

          [WebService]

          public class GetMyInfo : System.Web.Services.WebService
          {

          [WebMethod]
          public IAsyncResult BeginGetAge(AsyncCallback cb, Object state)
          {

          // 調(diào)用異步 Web 服務(wù)調(diào)用。
          localhost.UserInfoQuery proxy
          = new localhost.UserInfoQuery();
          return proxy.BeginGetUserInfo("用戶名",
          cb,
          proxy);
          }

          [WebMethod]
          public int EndGetAge(IAsyncResult res)
          {
          localhost.UserInfoQuery proxy
          = (localhost.UserInfoQuery)res.AsyncState;
          int age = proxy.EndGetUserInfo(res).age;
          // 在此對 Web 服務(wù)的結(jié)果進(jìn)行其他
          // 處理。
          return age;
          }
          }

          發(fā)生在 Web 方法中的最常見的 I/O 操作類型之一是對 SQL 數(shù)據(jù)庫的調(diào)用。不幸的是,目前 Microsoft&reg; ADO.NET 尚未定義一個完好的異步調(diào)用機(jī)制;而只是將 SQL 調(diào)用包裝到異步委托調(diào)用中對提高效率沒有什么幫助。雖然有時可以選擇緩存結(jié)果,但是也應(yīng)當(dāng)考慮使用 Microsoft SQL Server 2000 Web Services Toolkit(英文)將您的數(shù)據(jù)庫發(fā)布為 Web 服務(wù)。這樣您就可以利用 .NET Framework 中的支持,異步調(diào)用 Web 服務(wù)以查詢或更新數(shù)據(jù)庫。

          通過 Web 服務(wù)調(diào)用訪問 SQL 時,需要注意眾多的后端資源。如果您使用了 TCP 套接字與 Unix 計算機(jī)通信,或者通過專用的數(shù)據(jù)庫驅(qū)動程序訪問其他一些可用的 SQL 平臺,甚至具有使用 DCOM 訪問的資源,您都可以考慮使用眾多的 Web 服務(wù)工具包將這些資源發(fā)布為 Web 服務(wù)。

          使用這種方法的優(yōu)點之一是您可以利用客戶端 Web 服務(wù)結(jié)構(gòu)的優(yōu)勢,例如使用 .NET Framework 的異步 Web 服務(wù)調(diào)用。這樣您將免費獲得異步調(diào)用能力,而您的客戶端訪問機(jī)制會與異步 Web 方法高效率地配合工作。

          使用異步 Web 方法聚合數(shù)據(jù)

          現(xiàn)在,許多 Web 服務(wù)都訪問后端的多個資源并為前端的 Web 服務(wù)聚合信息。盡管調(diào)用多個后端資源會增加異步 Web 方法模型的復(fù)雜性,但最終還是能夠顯著提高效率。

          假設(shè)您的 Web 方法調(diào)用兩個后端 Web 服務(wù):服務(wù) A 和服務(wù) B。從您的 BeginXXX 函數(shù),您可以異步調(diào)用服務(wù) A 和服務(wù) B。您應(yīng)該向每個異步調(diào)用傳遞自己的回調(diào)函數(shù)。在從服務(wù) A 和服務(wù) B 接收到結(jié)果后,為觸發(fā) Web 方法的完成,您提供的回調(diào)函數(shù)將驗證所有的請求都已完成,在返回的數(shù)據(jù)上進(jìn)行所有的處理,然后調(diào)用傳遞到 BeginXXX 函數(shù)的回調(diào)函數(shù)。這將觸發(fā)對 EndXXX 函數(shù)的調(diào)用,此函數(shù)的返回將導(dǎo)致異步 Web 方法的完成。

          小結(jié)

          異步 Web 方法在 ASP.NET Web 服務(wù)中提供了一個有效的機(jī)制,可以調(diào)用后端服務(wù),而不會導(dǎo)致占用卻不利用進(jìn)程線程池中的寶貴線程。通過結(jié)合對后端資源的異步請求,服務(wù)器可以使用自己的 Web 方法使同時處理的請求數(shù)目達(dá)到最大。您應(yīng)該考慮使用此方法開發(fā)高性能的 Web 服務(wù)應(yīng)用程序。


          原文地址:http://ewebapp.cnblogs.com/articles/237372.html
          posted @ 2006-05-07 15:22 hopeshared 閱讀(533) | 評論 (0)編輯 收藏

          為舉例說明異步 Web 方法,我從一個名為 LengthyProcedure 的簡單同步 Web 方法開始,其代碼如下所示。然后我們再看一看如何異步完成相同的任務(wù)。LengthyProcedure 只占用給定的毫秒數(shù)。

          [WebService]

          public class SyncWebService : System.Web.Services.WebService
          {

          [WebMethod]
          public string LengthyProcedure(int milliseconds)
          {
          System.Threading.Thread.Sleep(milliseconds);
          return "成功";
          }
          }

          現(xiàn)在我們將 LengthyProcedure 轉(zhuǎn)換為異步 Web 方法。我們必須創(chuàng)建如前所述的 BeginLengthyProcedure 函數(shù)和 EndLengthyProcedure 函數(shù)。請記住,我們的 BeginLengthyProcedure 調(diào)用需要返回一個 IAsyncResult 接口。這里,我打算使用一個委托以及該委托上的 BeginInvoke 方法,讓我們的 BeginLengthyProcedure 調(diào)用進(jìn)行異步方法調(diào)用。傳遞到 BeginLengthyProcedure 的回調(diào)函數(shù)將被傳遞到委托上的 BeginInvoke 方法,從 BeginInvoke 返回的 IAsyncResult 將被 BeginLengthyProcedure 方法返回。

          當(dāng)委托完成時,將調(diào)用 EndLengthyProcedure 方法。我們將調(diào)用委托上的 EndInvoke 方法,以傳入 IAsyncResult,并將其作為 EndLengthyProcedure 調(diào)用的輸入。返回的字符串將是從該 Web 方法返回的字符串。下面是其代碼:

          [WebService]

          public class AsyncWebService : System.Web.Services.WebService
          {
          public delegate string LengthyProcedureAsyncStub(
          int milliseconds);

          public string LengthyProcedure(int milliseconds)
          {
          System.Threading.Thread.Sleep(milliseconds);
          return "成功";
          }

          public class MyState
          {
          public object previousState;
          public LengthyProcedureAsyncStub asyncStub;
          }

          [ System.Web.Services.WebMethod ]

          public IAsyncResult BeginLengthyProcedure(int milliseconds,
          AsyncCallback cb, object s)
          {
          LengthyProcedureAsyncStub stub
          = new LengthyProcedureAsyncStub(LengthyProcedure);
          MyState ms = new MyState();
          ms.previousState = s;
          ms.asyncStub = stub;
          return stub.BeginInvoke(milliseconds, cb, ms);
          }

          [ System.Web.Services.WebMethod ]
          public string EndLengthyProcedure(IAsyncResult call)
          {
          MyState ms = (MyState)call.AsyncState;
          return ms.asyncStub.EndInvoke(call);
          }
          }


          原文地址:http://ewebapp.cnblogs.com/articles/237375.html
          posted @ 2006-05-07 15:18 hopeshared 閱讀(309) | 評論 (0)編輯 收藏

          僅列出標(biāo)題
          共30頁: First 上一頁 8 9 10 11 12 13 14 15 16 下一頁 Last 
          主站蜘蛛池模板: 达拉特旗| 铅山县| 邵武市| 沧源| 洛南县| 栖霞市| 阳泉市| 衢州市| 托克逊县| 巨鹿县| 徐闻县| 晋州市| 清丰县| 礼泉县| 库尔勒市| 萝北县| 鄯善县| 安平县| 灵宝市| 芦溪县| 武汉市| 上蔡县| 开封县| 桦甸市| 多伦县| 道真| 庄河市| 高清| 天等县| 枣庄市| 当涂县| 女性| 洛阳市| 乌恰县| 屯昌县| 温宿县| 昌图县| 宁德市| 乐昌市| 乐东| 永吉县|