Javaのasync-http-clientを使った非同期HTTP

Javaのasync-http-clientを使用した非同期HTTP

1. 概要

AsyncHttpClient(AHC)は、Nettyの上に構築されたライブラリであり、HTTP要求を簡単に実行し、応答を非同期で処理することを目的としています。

この記事では、HTTPクライアントを構成して使用する方法、リクエストを実行する方法、AHCを使用してレスポンスを処理する方法について説明します。

2. セットアップ

ライブラリの最新バージョンはMaven repositoryにあります。 com.ning:の依存関係ではなく、グループIDorg.asynchttpclientの依存関係を使用するように注意する必要があります。


    org.asynchttpclient
    async-http-client
    2.2.0

3. HTTPクライアントの構成

HTTPクライアントを取得する最も簡単な方法は、Dslクラスを使用することです。 静的なasyncHttpClient()メソッドは、AsyncHttpClientオブジェクトを返します。

AsyncHttpClient client = Dsl.asyncHttpClient();

HTTPクライアントのカスタム構成が必要な場合は、ビルダーDefaultAsyncHttpClientConfig.Builderを使用してAsyncHttpClientオブジェクトをビルドできます。

DefaultAsyncHttpClientConfig.Builder clientBuilder = Dsl.config()

これにより、タイムアウト、プロキシサーバー、HTTP証明書などを設定できます。

DefaultAsyncHttpClientConfig.Builder clientBuilder = Dsl.config()
  .setConnectTimeout(500)
  .setProxyServer(new ProxyServer(...));
AsyncHttpClient client = Dsl.asyncHttpClient(clientBuilder);

an instance of the HTTP client we can reuse it across out applicationを構成して取得したら。 内部的には新しいスレッドと接続プールが作成され、パフォーマンスの問題が発生するため、リクエストごとにインスタンスを作成する必要はありません。

また、once we’ve finished using the client we should call to close() method to prevent any memory leaksまたはハングしているリソースに注意することが重要です。

4. HTTPリクエストの作成

AHCを使用してHTTP要求を定義できる2つの方法があります。

  • バウンド

  • バインドされていない

パフォーマンスの点で、2つの要求タイプに大きな違いはありません。 これらは、リクエストを定義するために使用できる2つの別個のAPIのみを表します。 A bound request is tied to the HTTP client it was created from and will, by default, use the configuration of that specific client if not specified otherwise.

たとえば、バインドされたリクエストを作成する場合、disableUrlEncodingフラグはHTTPクライアント構成から読み取られますが、バインドされていないリクエストの場合、これはデフォルトでfalseに設定されます。 これは、VM引数として渡されるシステムプロパティを使用して、アプリケーション全体を再コンパイルせずにクライアント構成を変更できるため便利です。

java -jar -Dorg.asynchttpclient.disableUrlEncodingForBoundRequests=true

プロパティの完全なリストは、ahc-default.propertiesファイルにあります。

4.1. バインドされたリクエスト

バインドされたリクエストを作成するには、プレフィックス“prepare”で始まるクラスAsyncHttpClientのヘルパーメソッドを使用します。 また、作成済みのRequestオブジェクトを受け取るprepareRequest()メソッドを使用することもできます。

たとえば、prepareGet()メソッドはHTTPGETリクエストを作成します。

BoundRequestBuilder getRequest = client.prepareGet("http://www.example.com");

4.2. 非バインド要求

バインドされていない要求は、RequestBuilderクラスを使用して作成できます。

Request getRequest = new RequestBuilder(HttpConstants.Methods.GET)
  .setUrl("http://www.example.com")
  .build();

または、Dslヘルパークラスを使用します。これは、実際にはRequestBuilderを使用してリクエストのHTTPメソッドとURLを構成します。

Request getRequest = Dsl.get("http://www.example.com").build()

5. HTTPリクエストの実行

ライブラリの名前は、リクエストの実行方法に関するヒントを提供します。 AHCは、同期要求と非同期要求の両方をサポートしています。

要求の実行は、そのタイプによって異なります。 bound request we use the execute() method from the BoundRequestBuilderクラスを使用している場合、およびunbound request we’ll execute it using one of the implementations of the executeRequest() method from the AsyncHttpClient interfaceがある場合。

5.1. 同期して

ライブラリは非同期になるように設計されていますが、必要に応じて、Futureオブジェクトをブロックすることで同期呼び出しをシミュレートできます。 execute()メソッドとexecuteRequest()メソッドはどちらも、ListenableFuture<Response>オブジェクトを返します。 このクラスはJavaFutureインターフェースを拡張し、get()メソッドを継承します。このメソッドは、HTTP要求が完了して応答を返すまで、現在のスレッドをブロックするために使用できます。

Future responseFuture = boundGetRequest.execute();
responseFuture.get();
Future responseFuture = client.executeRequest(unboundRequest);
responseFuture.get();

同期呼び出しを使用すると、コードの一部をデバッグするときに役立ちますが、非同期実行によってパフォーマンスとスループットが向上する本番環境で使用することはお勧めしません。

5.2. 非同期的に

非同期実行について話すとき、結果を処理するためのリスナーについても話します。 AHCライブラリは、非同期HTTP呼び出しに使用できる3種類のリスナーを提供します。

  • AsyncHandler

  • AsyncCompletionHandler

  • ListenableFutureリスナー

AsyncHandlerリスナーは、HTTP呼び出しが完了する前に制御および処理する可能性を提供します。 これを使用すると、HTTP呼び出しに関連する一連のイベントを処理できます。

request.execute(new AsyncHandler() {
    @Override
    public State onStatusReceived(HttpResponseStatus responseStatus)
      throws Exception {
        return null;
    }

    @Override
    public State onHeadersReceived(HttpHeaders headers)
      throws Exception {
        return null;
    }

    @Override
    public State onBodyPartReceived(HttpResponseBodyPart bodyPart)
      throws Exception {
        return null;
    }

    @Override
    public void onThrowable(Throwable t) {

    }

    @Override
    public Object onCompleted() throws Exception {
        return null;
    }
});


State列挙型を使用すると、HTTPリクエストの処理を制御できます。 特定の瞬間にState.ABORT we can stop the processingを返し、State.CONTINUEを使用して、処理を終了します。

AsyncHandler isn’t thread-safe and shouldn’t be reused when executing concurrent requests.に言及することが重要です

AsyncCompletionHandlerは、AsyncHandlerインターフェイスからすべてのメソッドを継承し、呼び出しの完了を処理するためのonCompleted(Response)ヘルパーメソッドを追加します。 他のすべてのリスナーメソッドはオーバーライドされてState.CONTINUEを返すため、コードが読みやすくなります。

request.execute(new AsyncCompletionHandler() {
    @Override
    public Object onCompleted(Response response) throws Exception {
        return response;
    }
});


ListenableFutureインターフェースを使用すると、HTTP呼び出しが完了したときに実行されるリスナーを追加できます。

また、別のスレッドプールを使用して、リスナーからコードを実行しましょう。

ListenableFuture listenableFuture = client
  .executeRequest(unboundRequest);
listenableFuture.addListener(() -> {
    Response response = listenableFuture.get();
    LOG.debug(response.getStatusCode());
}, Executors.newCachedThreadPool());

さらに、リスナーを追加するオプションであるListenableFutureインターフェースを使用すると、Future応答をCompletableFutureに変換できます。

7. 結論

AHCは非常に強力なライブラリであり、多くの興味深い機能を備えています。 HTTPクライアントを構成する非常に簡単な方法と、同期要求と非同期要求の両方を実行する機能を提供します。

いつものように、記事のソースコードはover on GitHubで入手できます。