ヘッダーをスキップ
Oracle® Fusion Middleware Oracle WebLogic Server JAX-WS Webサービスの開発
12c (12.1.2)
E48039-03
  目次へ移動
目次

前
 
次
 

11 非同期Webサービス・クライアントを開発するためのロードマップ

この章では、Java API for XML Web Services (JAX-WS)用の非同期WebLogic Webサービス・クライアントを開発するためのベスト・プラクティスについて説明します。

表11-1では、非同期Webサービス・クライアントを開発するためのベスト・プラクティスとその例を示します。これらのガイドラインは、第7章「JAX-WS Webサービス・クライアントを開発するためのロードマップ」で示されている一般的なガイドラインと併せて使用する必要があります。

信頼性のあるWebサービス・クライアントの開発の際のベスト・プラクティスについては、第13章「信頼性のあるWebサービスとクライアントを開発するためのロードマップ」を参照してください。


注意:

次の表でクライアント・インスタンスは、ポートまたはディスパッチ・インスタンスです。


表11-1 非同期Webサービス・クライアントを開発するためのロードマップ

ベスト・プラクティス 説明

非同期およびディスパッチ・コールバック処理のためにポートベースの非同期コールバック・ハンドラAsyncClientHandlerFeatureを定義します。

拡張性があり、JVMを再起動しても維持されるため、非同期呼び出しを使用するときのベスト・プラクティスとして、AsyncClientHandlerFeatureを使用することをお薦めします。このハンドラは(持続可能かどうかに関係なく)任意のクライアントで使用できます。詳細は、「非同期ハンドラ・インタフェースの開発」を参照してください。

シングルトン・ポート・インスタンスを定義し、(デプロイメント時に)クライアント・コンテナを初期化するときに初期化します。

シングルトン・ポートの作成:

  • デプロイメント時に公開する非同期レスポンス・エンドポイントをトリガーします。

  • VMの再起動後にシングルトン・ポート・インスタンスを再初期化することで、障害リカバリをサポートします。

クラスタ内では、シングルトン・ポートを初期化すると、クラスタ内のすべてのメンバー・サーバーが非同期レスポンス・エンドポイントをパブリッシュすることが保証されます。これによって、非同期レスポンス・メッセージが任意のメンバー・サーバーに配信され、必要に応じてインプレース・クラスタ・ルーティングを介して正しいサーバーに転送されることが保証されます。詳細は、「非同期Webサービス・メッセージングのクラスタリングの考慮事項」を参照してください。

ファイアウォールの内側にあるクライアントに接続作成を使用する場合は、接続作成ポーリング間隔をシナリオに対して現実的な値に設定します。

接続作成のポーリング間隔は、不必要なポーリング・オーバーヘッドを避けることができる大きな値で、なおかつ遅れずにレスポンスを取得できる十分に小さい値に設定する必要があります。接続作成ポーリング間隔の推奨される値は、呼び出されるWebサービスの予想される平均レスポンス時間の半分です。接続作成ポーリング間隔の設定の詳細は、「ポーリング間隔の構成」を参照してください。

注意: このベスト・プラクティスは、例11-1では示されていません。

JAX-WS参照実装(RI)を使用している場合は、AsyncHandler<T>インタフェースを実装します。

AsyncHandler<T>インタフェースを使用する方が、Response<T>インタフェースを使用するより効率的です。詳細および例は、「JAX-WS参照実装の使用」を参照してください。

注意: このベスト・プラクティスは、例11-1では示されていません。

ワーク・マネージャを定義し、スレッド・プールの最小サイズ制限(min-threads-constraint)を、最低でもサービスに対して予想される同時リクエスト数または同時レスポンス数と同じ値に設定します。

たとえば、Webサービス・クライアントが20個のリクエストを立て続けに発行する場合、そのクライアントをホストするアプリケーションで推奨されるスレッド・プールの最小サイズ制約の値は20です。構成した制約値が小さすぎると、受信処理で処理スレッドの空き待ちが発生するためパフォーマンスが大幅に低下するおそれがあります。

スレッド・プールの最小サイズ制約の詳細は、『Oracle WebLogic Serverサーバー環境の管理』の制約に関する項を参照してください。


次の例では、非同期Webサービス・クライアントを開発するためのベスト・プラクティスを示します。

例11-1 非同期Webサービス・クライアントのベスト・プラクティスの例

import java.io.*;
import java.util.*;
 
import javax.servlet.*
import javax.xml.ws.*
 
import weblogic.jws.jaxws.client.ClientIdentityFeature;
import weblogic.jws.jaxws.client.async.AsyncClientHandlerFeature;
import weblogic.jws.jaxws.client.async.AsyncClientTransportFeature;
 
import com.sun.xml.ws.developer.JAXWSProperties;
 
/**
 * Example client for invoking a Web service asynchronously.
 */
public class BestPracticeAsyncClient
  extends GenericServlet {
 
  private static final String MY_PROPERTY = "MyProperty";
 
  private BackendServiceService _service;
  private WebServiceFeature[] _features;
  private BackendService _singletonPort;
 
  private static String _lastResponse;
  private static int _requestCount;
 
  @Override
  public void init()
    throws ServletException {
 
    // Only create the Web service object once as it is expensive to create repeatedly.
    if (_service == null) {
      _service = new BackendServiceService();
    }
 
    // Best Practice: Use a stored list of features, including client ID, to create client 
    // instances.
    // Define all features for the Web service client instance, including client ID, so that they
    // are consistent each time the client instance is created. For example: 
    // _service.getBackendServicePort(_features);
 
    List<WebServiceFeature> features = new ArrayList<WebServiceFeature>();
 
    // Best Practice: Explicitly define the client ID.
    ClientIdentityFeature clientIdFeature =
      new ClientIdentityFeature("MyBackendServiceAsyncClient");
    features.add(clientIdFeature);
 
    // Asynchronous endpoint
    AsyncClientTransportFeature asyncFeature =
      new AsyncClientTransportFeature(getServletContext());
    features.add(asyncFeature);
 
    // Best Practice: Define a port-based asynchronous callback handler,
    // AsyncClientHandlerFeature, for asynchronous and dispatch callback handling.
    BackendServiceAsyncHandler handler =
      new BackendServiceAsyncHandler() {
        // This class is stateless and should not depend on
        // having member variables to work with across restarts.
        public void onDoSomethingResponse(Response<DoSomethingResponse> res) {
          // ... Handle Response ...
          try {
            DoSomethingResponse response = res.get();
            res.getContext();
            _lastResponse = response.getReturn();
            System.out.println("Got async response: " + _lastResponse);
            // Retrieve the request property. This property can be used to 
            // 'remember' the context of the request and subsequently process
            // the response.
            Map<String, Serializable> requestProps =
              (Map<String, Serializable>)
                res.getContext().get(JAXWSProperties.PERSISTENT_CONTEXT);
            String myProperty = (String)requestProps.get(MY_PROPERTY);
            System.out.println("Got MyProperty value propagated from request: "+
                               myProperty);
          } catch (Exception e) {
            _lastResponse = e.toString();
            e.printStackTrace();
          }
        }
      };
    AsyncClientHandlerFeature handlerFeature =
      new AsyncClientHandlerFeature(handler);
    features.add(handlerFeature);
 
    // Set the features used when creating clients with
    // the client ID "MyBackendServiceAsyncClient".
 
    _features = features.toArray(new WebServiceFeature[features.size()]);

    // Best Practice: Define a singleton port instance and initialize it when 
    // the client container initializes (upon deployment).
    // The singleton port will be available for the life of the servlet.
    // Creation of the singleton port triggers the asynchronous response endpoint to be published
    // and it will remain published until our container (Web application) is undeployed.
    // Note, the destroy() method will be called before this.
    // The singleton port ensures proper/robust operation in both
    // recovery and clustered scenarios.
    _singletonPort = _service.getBackendServicePort(_features);
  }
 
  @Override
  public void service(ServletRequest req, ServletResponse res)
    throws ServletException, IOException {
 
    // TODO: ... Read the servlet request ...
 
    // For this simple example, echo the _lastResponse captured from 
    // an asynchronous DoSomethingResponse response message.
 
    if (_lastResponse != null) {
      res.getWriter().write(_lastResponse);
      _lastResponse = null; // Clear the response so we can get another
      return;
    }
 
    // Set _lastResponse to NULL to to support the invocation against
    // BackendService to generate a new response.
 
    // Best Practice: Synchronize use of client instances.
    // Create another client instance using the *exact* same features used when creating _
    // singletonPort. Note, this port uses the same client ID as the singleton port 
    // and it is effectively the same as the singleton
    // from the perspective of the Web services runtime. 
    // This port will use the asynchronous response endpoint for the client ID, 
    // as it is defined in the _features list.
    BackendService anotherPort =
      _service.getBackendServicePort(_features);
 
    // Set the endpoint address for BackendService.
    ((BindingProvider)anotherPort).getRequestContext().
      put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
          "http://localhost:7001/BestPracticeService/BackendService");
 
    // Add a persistent context property that will be retrieved on the
    // response. This property can be used as a reminder of the context of this
    // request and subsequently process the response. This property will *not*
    // be passed over the wire, so the properties can change independent of the
    // application message.
    Map<String, Serializable> persistentContext =
      (Map<String, Serializable>)((BindingProvider)anotherPort).
        getRequestContext().get(JAXWSProperties.PERSISTENT_CONTEXT);
    String myProperty = "Request " + (++_requestCount);
    persistentContext.put(MY_PROPERTY, myProperty);
    System.out.println("Request being made with MyProperty value: " +
                       myProperty);
 
    // Make the asychronous invocation. The asynchronous handler implementation (set 
    // into the AsyncClientHandlerFeature above) receives the response.
    String request = "Dance and sing";
    System.out.println("Invoking DoSomething asynchronously with request: " +
                       request);
    anotherPort.doSomethingAsync(request);
 
    // Return a canned string indicating the response was not received
    // synchronously. Client will need to invoke the servlet again to get
    // the response.
    res.getWriter().write("Waiting for response...");
 
    // Best Practice: Explicitly close client instances when processing is complete.
    // If not closed explicitly, the port will be closed automatically when it goes out of scope.
    ((java.io.Closeable)anotherPort).close();
  }
 
  @Override
  public void destroy() {
 
    try {
      // Best Practice: Explicitly close client instances when processing is complete.
      // Close the singleton port created during initialization. Note, the asynchronous
      // response endpoint generated by creating _singletonPort *remains*
      // published until our container (Web application) is undeployed.
      ((java.io.Closeable)_singletonPort).close();

      // Upon return, the Web application is undeployed, and the asynchronous
      // response endpoint is stopped (unpublished). At this point,
      // the client ID used for _singletonPort will be unregistered and will no longer be
      // visible from the Administration Console and WLST.
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}