Javaのasync-http-clientを使った非同期HTTP
1.概要
AsyncHttpClient
(AHC)は、リンク:/netty[Netty]の上に構築されたライブラリで、HTTP要求を簡単に実行し、応答を非同期に処理することができます。
この記事では、HTTPクライアントの構成方法と使用方法、要求の実行方法とAHCを使用した応答の処理方法について説明します。
2.セットアップ
ライブラリの最新版はhttps://mvnrepository.com/artifact/org.asynchttpclient/async-http-client[Maven repository]にあります。
com.ningのグループIDではなく、グループ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クライアントに結び付けられており、特に指定がなければ、デフォルトでその特定のクライアントの設定を使用します。
たとえば、バインドされたリクエストを作成するときはHTTPクライアント設定から
disableUrlEncoding
フラグが読み込まれますが、バインドされていないリクエストの場合はデフォルトでfalseに設定されます。 VM引数として渡されたシステムプロパティを使用することで、アプリケーション全体を再コンパイルせずにクライアント設定を変更できるため、これは便利です。
java -jar -Dorg.asynchttpclient.disableUrlEncodingForBoundRequests=true
プロパティの完全なリストは
ahc-default.properties
ファイルにあります。
4.1. バウンドリクエスト
バインドされたリクエストを作成するために、接頭辞
“ prepare”
で始まるクラス
AsyncHttpClient
からのヘルパーメソッドを使用します。また、作成済みの
Request
オブジェクトを受け取る__prepareRequest()メソッドを使用することもできます。
たとえば、
prepareGet()
メソッドはHTTP GETリクエストを作成します。
BoundRequestBuilder getRequest = client.prepareGet("http://www.baeldung.com");
4.2. 未バインド要求
RequestBuilder
クラスを使用して、バインドされていないリクエストを作成できます。
Request getRequest = new RequestBuilder(HttpConstants.Methods.GET)
.setUrl("https://www.baeldung.com")
.build();
または
Dsl
ヘルパークラスを使用して、実際にはHTTPメソッドとリクエストのURLを設定するために
RequestBuilder
を使用します。
Request getRequest = Dsl.get("http://www.baeldung.com").build()
5. HTTPリクエストを実行する
ライブラリの名前は、要求を実行する方法についてのヒントを与えてくれます。 AHCは、同期要求と非同期要求の両方をサポートしています。
要求の実行はその種類によって異なります。
バウンドリクエストを使用するときは
BoundRequestBuilder
クラスの
execute()
メソッドを使用し、
アンバウンドリクエストがあるときは
AsyncHttpClient
インターフェース
のexecuteRequest()メソッドの実装の1つを使用してそれを実行します。
5.1. 同期的に
このライブラリは非同期になるように設計されていますが、必要に応じて
Future
オブジェクトをブロックすることで同期呼び出しをシミュレートできます。
execute()
メソッドと
executeRequest()
メソッドはどちらも
ListenableFuture <Response>
オブジェクトを返します。このクラスはJavaの
Future
インタフェースを拡張し、HTTP要求が完了して応答を返すまで現在のスレッドをブロックするために使用できる__get()メソッドを継承します。
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
enumはHTTPリクエストの処理を制御することを可能にします。
State.ABORT
を返すことで、特定の瞬間に処理を停止することができます
。
-
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クライアントと同期要求と非同期要求の両方を実行する機能を構成するための非常に簡単な方法を提供します。
いつものように、この記事のソースコードはhttps://github.com/eugenp/tutorials/tree/master/libraries[over GitHub]から入手できます。