posts - 42,comments - 83,trackbacks - 0

                  這幾天碰到個(gè)問題:在weblogic中調(diào)用async webservice,如果客戶端不等待結(jié)果(比如服務(wù)器端因?yàn)槟承┰颍瑆eb service需要執(zhí)行很長(zhǎng)時(shí)間),直接退出的話,weblogic server是否保存調(diào)用結(jié)果,結(jié)果保存多長(zhǎng)時(shí)間? 如果這樣的異常客戶端很多,對(duì)服務(wù)器有什么負(fù)面影響,比如連接資源、內(nèi)存開銷等。

                  首先我們先闡述一下異步的概念 在weblogic webservice中,有兩處異步的概念:
                  1:Synchronous request-response (the default behavior) means that every time a client application invokes a Web Service operation, it receives a SOAP response, even if the method that Choosing RPC-Oriented or Document-Oriented Web Services Programming WebLogic Web Services 4-3 implements the operation returns void. Asynchronous one-way means that the client never receives a SOAP response, even a fault or exception.
                  默認(rèn)情況下,weblogic webservice是請(qǐng)求-應(yīng)答模式的,即客戶端會(huì)block當(dāng)前線程,直到server端處理完該請(qǐng)求(即使該請(qǐng)求沒有任何返回值,void)。當(dāng)web service不返回結(jié)果,客戶端只是提交請(qǐng)求,不需要知道執(zhí)行結(jié)果的時(shí)候,可以采用異步單向模式。這種情況下,客戶端線程為非阻塞的,它只負(fù)責(zé)提交請(qǐng)求,而不需要返回結(jié)果。定義這樣的異步web service時(shí),需要遵循如下的兩個(gè)原則:
                    1.1:The back-end component that implements the operation must explicitly return void.
                    1.2:You cannot specify out or in-out parameters to the operation, you can only specify inparameters.

                  2:This section describes how to invoke an operation asynchronously. In this context, asynchronously means you invoke an operation and then optionally get the results of the invoke in a later step.
                  這種情況下雖然也是異步調(diào)用的,但這種調(diào)用方式客戶端需要返回值。需要返回結(jié)果,但客戶端又不樂意阻塞在服務(wù)器端請(qǐng)求處理上(可能服務(wù)器端處理該請(qǐng)求需要很長(zhǎng)時(shí)間)。客戶端希望繼續(xù)執(zhí)行它的其他業(yè)務(wù)邏輯,需要執(zhí)行結(jié)果的時(shí)候,我在過來取這個(gè)結(jié)果。這樣可以提高客戶端的響應(yīng)速度。

                  這篇文章,我們主要看看2這種情況。

                  2.1: web service開發(fā)
                  開發(fā)web service不存在任何區(qū)別,但在build client jar的時(shí)候,需要在調(diào)用clientgen的時(shí)候加上generateAsyncMethods = true, 這樣clientgen生成的JAX-RPC stub中會(huì)多出兩個(gè)方法,如下:
                  FutureResult startMethod (params, AsyncInfo asyncInfo);
                  result endMethod (FutureResult futureResult);
          其中:Method對(duì)應(yīng)于web service中的方法名,如sayHello---->startSayHello(params, AsyncInfo asyncInfo)。這兩個(gè)方法就是我們客戶端代碼中異步調(diào)用的時(shí)候需要的。

                  2.2:客戶端代碼
                  客戶端代碼有兩種寫法,一種是客戶端線程主動(dòng)調(diào)用FutuerResult.isCompleted()來檢查web service請(qǐng)求是否執(zhí)行完成,另一種方式是通過Listenter來處理服務(wù)器端的返回結(jié)果。

          //client thread checking

           1     public void runUnblock(){
           2         initializeEnv();
           3         try{
           4             System.out.println(port.getClass().getName());
           5             FutureResult result = port.startSayHello(3"test"null);
           6             //you other business logic here
           7             if(result.isCompleted())
           8             {
           9                 String ret = port.endSayHello(result);
          10                 System.out.println("result from remote HelloWorld web service: ");
          11                 System.out.println(ret);
          12             }
          13         }catch(Exception e){
          14             e.printStackTrace();
          15         }
          16     }
          17 
          18     public void initializeEnv(){
          19         try{
          20             helloService = new HelloWorld_Impl();
          21             port = helloService.getHelloWorldPort();
          22         }catch(Exception e){
          23             e.printStackTrace();
          24         }
          25     }


          //listener

           1 AsyncInfo asyncInfo = new AsyncInfo();
           2 asyncInfo.setResultListener( new ResultListener(){
           3     public void onCompletion( InvokeCompletedEvent event ){
           4         SimpleTestSoap source = (SimpleTestSoap)event.getSource();
           5         try{
           6             String result = source.endEchoString ( event.getFutureResult() );
           7         } catch ( RemoteException e ){
           8             e.printStackTrace ( System.out );
           9         }
          10     }
          11 });
          12 echoPort.startEchoString( "94501", asyncInfo );

           

                  現(xiàn)在回頭看看開篇的問題,客戶端線程退出時(shí),如果服務(wù)器端還沒有處理完,請(qǐng)求結(jié)果會(huì)怎么辦?是否會(huì)保存下來?如果這樣的客戶端很多,服務(wù)器內(nèi)存開銷豈不是很大?

                  要解釋這個(gè)問題,我們先來看看這種調(diào)用方式的流程。對(duì)于服務(wù)器而言,異步、同步調(diào)用是一樣的,它只負(fù)責(zé)接收、處理請(qǐng)求,web service的處理,在服務(wù)器端是由weblogic.webservice. server.servlet. WebServiceServlet .serverSideInvoke(WebService webservice, Binding binding, HttpServletRequest request, HttpServletResponse response)。同步、異步的處理完全是在客戶端完成的,下面就看看客戶端的調(diào)用流程。

          FutureResult result = port.startSayHello(3"test"null);
          //it's a JAX-RPC stub, and it extends StubImpl.java
          ====>
          weblogic.webservice.core.rpc.StubImpl._startAsyncInvoke( String method, Map args, AsyncInfo wsAsyncContext )
          //in this method, Operation is retrieved from Port
          ====>
          weblogic.webservice.core.DefaultOperation.asyncInvoke( Map outParams, Object[] args, AsyncInfo wsContext, PrintStream logStream )
          //a ClientDispatcher is created here and then we dispatch our requst with this dispatcher
          ====>
          weblogic.webservice.core.ClientDispatcher.asyncDispatch(final Object[] args, final AsyncInfo async)
          //in this method, FutureResultImpl is created and it will be returned to client. It's responsible to send message and
          //receive response from server in another. For receiving response, it's will be discussed later.
          ====>
          weblogic.webservice.core.ClientDispatcher.send(Object[] args)
          //MessageContext is set(for example, BindInfo is set) here and the request will be handle by a handler chain.
          ====>
          weblogic.webservice.core.handler.ClientHandler.handleRequest(MessageContext ctx)
          //it check bind info and the delegate the request to binding
          ====>
          weblogic.webservice.binding.http11.Http11ClientBinding.send(MessageContext ctx)
          //it retrieve endpoint from bindinfo and then open a HttpURLConnection with the URL created basing on endpoint.
          //Reqeust is sent to server with this HttpURLConnection.

          1 connection = (HttpURLConnection)url.openConnection();
          2 
          3 outputStream = connection.getOutputStream();
          4 request.writeTo( outputStream );


                  請(qǐng)求發(fā)送完了,交給服務(wù)器去執(zhí)行,下面我們?cè)賮砜纯纯蛻舳耸侨绾翁幚韗esponse的。weblogic.webservice. core.ClientDispatcher.asyncDispatch()中,請(qǐng)求發(fā)送結(jié)束后,weblogic將啟用一個(gè)新線程來接受服務(wù)器的response,如下:

          1       getThreadPool().addTask(new Runnable() {
          2         public void run() {
          3           callReceive(messageContext);
          4         }
          5       });

          注意:這個(gè)線程是在客戶端啟動(dòng)的。該接收線程啟動(dòng)后,F(xiàn)utureResultImpl實(shí)例會(huì)返回給客戶端,客戶端由此可以繼續(xù)他的業(yè)務(wù)邏輯,而不必block在等待response上。response由接收線程負(fù)責(zé)處理,收到response,處理后的結(jié)果會(huì)被植入FutureResultImpl,客戶端執(zhí)行它的其他邏輯,需要處理處理該結(jié)果時(shí),只需要檢查請(qǐng)求是否處理結(jié)束,如果結(jié)束,處理請(qǐng)求結(jié)果,如果請(qǐng)求依然沒有結(jié)束,則由客戶端決定繼續(xù)等待,還是放棄(主線程退出),如下:

          1 //you other business logic here
          2 if(result.isCompleted())
          3 {
          4     String ret = port.endSayHello(result);
          5     System.out.println(ret);
          6  }


                  客戶端接受流程:

          weblogic.webservice.core.ClientDispatcher.asyncDispatch(final Object[] args, final AsyncInfo async)
          ====>
          weblogic.webservice.core.ClientDispatcher.callReceive(WLMessageContext ctx)
          //call receive() here, and if response was received, set it to FutureResultImpl that owned by the client and if Listener is configured, trigger the listner.

          1       if (listener != null) {
          2         InvokeCompletedEvent event = new InvokeCompletedEvent(
          3             async.getCaller());
          4 
          5         event.setFutureResult(futureResult);
          6         listener.onCompletion(event);
          7       }

          ====>
          weblogic.webservice.core.ClientDispatcher.receive(WLMessageContext ctx)
          //resoponse is handled by a handler chain
          ====>
          weblogic.webservice.core.handler.ClientHandler.handleResponse(MessageContext ctx)
          ====>
          weblogic.webservice.binding.http11.Http11ClientBinding.receive( MessageContext context )
          //read response from the input stream of connect that we send request with, and the thread will be blocked in
          //waiting data from server.


                  好了,基本流程都列出來了。下面據(jù)此回答開篇的問題:

          1:如果客戶端不等待結(jié)果(比如服務(wù)器端因?yàn)槟承┰颍瑆eb service需要執(zhí)行很長(zhǎng)時(shí)間),直接退出的話,weblogic server是否保存調(diào)用結(jié)果,結(jié)果保存多長(zhǎng)時(shí)間? 
               不會(huì)。如果客戶端退出前,請(qǐng)求已處理,保存在FutureResultImpl將會(huì)因?yàn)榭蛻舳说耐顺龆N毀。如果沒有處理結(jié)束,服務(wù)器端回寫response的時(shí)候,雖然指向客戶端的連接已經(jīng)因?yàn)榭蛻舳送顺龆鴆lose了,但服務(wù)器端從該connection中拿到的output stream還在,服務(wù)器仍然會(huì)將response寫入到該output stream中(這是寫入的數(shù)據(jù)是沒有接收者的),response寫完后,weblogic會(huì)關(guān)閉output stream, 并close socket。

          2:如果這樣的異常客戶端很多,對(duì)服務(wù)器有什么負(fù)面影響,比如連接資源、內(nèi)存開銷等。
                  不會(huì)。如果客戶端退出前,請(qǐng)求已處理,則連接已經(jīng)釋放。如果連接保持的時(shí)間略大于web service請(qǐng)求在服務(wù)器段的處理時(shí)間。請(qǐng)求處理結(jié)束后,服務(wù)器會(huì)在回寫完response后,主動(dòng)斷開連接(可以看到客戶端至server端的連接為TIME_WAIT)。如果客戶端退出時(shí),請(qǐng)求依然在服務(wù)器端上處理,客戶端的退出會(huì)導(dǎo)致連接的CLOSE。兩種情形都不會(huì)因?yàn)楫惓?蛻舳硕鴮?dǎo)致連接浪費(fèi)。至于內(nèi)存開銷,服務(wù)器不會(huì)保存執(zhí)行結(jié)果,請(qǐng)求處理結(jié)束后,直接回寫客戶端,所以也不會(huì)造成內(nèi)存資源leak。

                  對(duì)于那些web service執(zhí)行時(shí)間較長(zhǎng),客戶端又希望其他業(yè)務(wù)并行的應(yīng)用,這種異步調(diào)用是個(gè)不錯(cuò)的選擇。

          posted on 2008-11-24 22:38 走走停停又三年 閱讀(2798) 評(píng)論(1)  編輯  收藏 所屬分類: Weblogic

          FeedBack:
          # re: 關(guān)于在weblogic中異步調(diào)用webservice
          主站蜘蛛池模板: 始兴县| 琼海市| 蚌埠市| 西盟| 黄冈市| 农安县| 惠水县| 延边| 广德县| 宝山区| 黄山市| 定南县| 花莲县| 西安市| 高清| 色达县| 岳阳县| 高青县| 金溪县| 乐东| 津市市| 盐城市| 祁连县| 湘潭市| 墨江| 磐安县| 若尔盖县| 靖远县| 三门峡市| 包头市| 南雄市| 巧家县| 泾源县| 达拉特旗| 临桂县| 丽江市| 开阳县| 施甸县| 临潭县| 长白| 德令哈市|