1. 概要

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

この記事では、HTTPクライアントを構成して使用する方法、AHCを使用して要求を実行し、応答を処理する方法を紹介します。

2. 設定

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

<dependency>
    <groupId>org.asynchttpclient</groupId>
    <artifactId>async-http-client</artifactId>
    <version>2.2.0</version>
</dependency>

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);

HTTPクライアントのインスタンスを構成して取得したら、アプリケーション全体で再利用できます。 内部的には新しいスレッドと接続プールが作成され、パフォーマンスの問題が発生するため、リクエストごとにインスタンスを作成する必要はありません。

また、クライアントの使用が終了したら、メモリリークやリソースのハングを防ぐためにclose()メソッドを呼び出す必要があることに注意してください。

4. HTTPリクエストの作成

AHCを使用してHTTPリクエストを定義できる方法は2つあります。

  • バウンド
  • アンバウンド

パフォーマンスの点では、2つのリクエストタイプに大きな違いはありません。 これらは、リクエストを定義するために使用できる2つの別個のAPIのみを表しています。 バインドされたリクエストは、作成元のHTTPクライアントに関連付けられており、特に指定されていない限り、デフォルトでその特定のクライアントの構成を使用します。

たとえば、バインドされたリクエストを作成する場合、 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.baeldung.com");

4.2. アンバウンドリクエスト

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

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

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

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

5. HTTPリクエストの実行

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

リクエストの実行は、そのタイプによって異なります。 バウンドリクエストを使用する場合は、BoundRequestBuilder クラスのexecute()メソッドを使用し、アンバウンドリクエストを使用する場合は、からのexecuteRequest()メソッドの実装の1つを使用して実行します。 AsyncHttpClientインターフェイス

5.1. 同期的に

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

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

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

5.2. 非同期

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

  • AsyncHandler
  • AsyncCompletionHandler
  • ListenableFutureリスナー

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

request.execute(new AsyncHandler<Object>() {
    @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を返すことで、特定の瞬間に処理を停止でき、 State.CONTINUE を使用して、処理を終了します。

AsyncHandlerはスレッドセーフではないため、同時リクエストを実行するときに再利用しないでください。

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

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

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

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

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

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

7. 結論

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

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