<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    精彩的人生

    好好工作,好好生活

    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 標準規(guī)范中包括了提供異步服務(wù)的內(nèi)容,但客戶端應(yīng)用程序前景的細節(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 進行交互。由客戶端發(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 上進行異步 Web service 調(diào)用的過程已經(jīng)詳細地 記錄在軟件文檔中了 ,因此在本文中不作進一步的討論。

      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 又由特定的操作來標識消息流的始末,這種 Web services 就是 會話式 的。提供回調(diào)的 Web services 也定義為會話式的。這是因為正常情況下如果 Web services 能夠?qū)蛻舳诉M行回調(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)建適當?shù)目蛻舳藛?SOAP 消息,以及處理回調(diào)操作。

      當客戶端啟動有回調(diào)的 Web service 操作時,它需要以某種方式包含回調(diào)端點的 URI ,使其在請求消息中監(jiān)聽。 Web Services Addressing SOAP Conversation Protocol 規(guī)范都定義了 SOAP 頭部元素,允許您實現(xiàn)這一目標。從理論上說,用于規(guī)定回調(diào)端點的規(guī)范并不重要。但是大多數(shù) Web services 容器(包括 BEA WebLogic Server 8.1 )都還沒有包含 Web services Addressing 規(guī)范的實現(xiàn)形式。當前, 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)操作,主要問題是它們的代理不生成所需的頭部。在能提供這種支持以前,通過擴展它們對回調(diào)操作的支持來利用這些框架(例如復(fù)雜類 XML 映射),這種益處還是很需要的。一種用來達到這種效果的技術(shù)就是應(yīng)用 SOAP 消息處理程序

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

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

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

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

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

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

      通過 WebLogic Workshop Service Control 訪問 Web services 在 軟件文檔 中已經(jīng)做了詳細描述。如果客戶端實體能夠使用控件(也就是 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 提供的操作允許客戶端注冊股票接收機并設(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)用相比,這段代碼唯一強調(diào)的就是,在方法一開始就實例化和注冊了客戶端 SOAP 消息處理程序。這個處理程序截取了發(fā)出的 SOAP 消息,并加上必要的會話頭部。每當客戶端過程發(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 消息,用客戶端的當前會話 ID 取代消息會話 ID ,最后生成實際調(diào)用。當使用 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 就是一種合適的選擇。進一步說,我們非常需要一個 servlet ,它能夠從輸入的 HTTP 請求中提取 SOAP 消息,并以一種容易使用的方式提供給我們。 javax.xml.messaging 程序包里的 ReqRespListener 接口和 JAXMServlet 類提供給我們這個功能。只要安排合理,應(yīng)用了這種接口和類的 servlet 將把所有的目標 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() 方法所接收,客戶端就從股票接收機中提取參數(shù),將它輸出到標準設(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 進程中。 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)完成了對例子客戶端的分析,該例子客戶端可作為本文的一部分下載。當您運行客戶端和股票通知 Web services 的時候,客戶端和 Web service 都將把消息顯示在標準輸出設(shè)備上,用以描述會話的不同階段,包括對回調(diào)操作的處理。

    結(jié)束語

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

    下載

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

    參考資料

    原文出處

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

    posted on 2006-05-07 16:19 hopeshared 閱讀(1329) 評論(0)  編輯  收藏 所屬分類: Web Service
    主站蜘蛛池模板: 免费人成激情视频在线观看冫| 亚洲一区二区三区偷拍女厕| 久久夜色精品国产嚕嚕亚洲av| 亚洲国产av美女网站| av永久免费网站在线观看| 99久久亚洲综合精品成人网| 国产成人精品无码免费看| 亚洲熟妇无码八AV在线播放| 中文字幕天天躁日日躁狠狠躁免费| 久久精品国产亚洲综合色| 中文字幕看片在线a免费| 亚洲中文字幕久久精品无码喷水| 一级有奶水毛片免费看| 亚洲中文字幕无码一区二区三区| 99在线观看精品免费99| 亚洲国产亚洲片在线观看播放| 免费国产成人高清在线观看麻豆 | 免费一级毛片在级播放| 鲁丝片一区二区三区免费| 久久精品国产亚洲香蕉| 浮力影院第一页小视频国产在线观看免费 | 精品久久免费视频| 国产成人无码区免费内射一片色欲| 久久精品国产亚洲αv忘忧草| 国产乱码免费卡1卡二卡3卡| 国产精品亚洲午夜一区二区三区| 皇色在线视频免费网站| 亚洲精品女同中文字幕| 免费人成无码大片在线观看| 亚洲毛片在线免费观看| 亚洲综合色区中文字幕| 中文字幕亚洲一区二区三区| 18禁在线无遮挡免费观看网站| 亚洲精品久久久久无码AV片软件| 亚洲一区精品中文字幕| 亚洲精品97久久中文字幕无码| 日韩电影免费在线观看| 美女黄频免费网站| 亚洲高清无在码在线无弹窗 | 内射无码专区久久亚洲 | 国产免费怕怕免费视频观看|