Java用の非同期HTTP通信ライブラリ

AsyncHttpClentはJavaプログラムにおいて非同期のHTTP通信を行うためのクライアントライブラリである。Javaに標準で付属するHTTP通信用のUrlConnectionクラスは最低限の機能しか実装されていない。ApacheのJakarta Commonsプロジェクトの成果物であるApache HttpClientは高性能ではあるが、クライアントプログラムはサーバからのレスポンスを待ってから処理する同期通信を行う。また、メモリ上にバッファリングを行うため巨大なファイルの送受信に適していないことや、I/OライブラリがApache HttpClientで提供されるものしか使えないといった問題がある。

AsyncHttpClientの場合、クライアントプログラムがサーバのレスポンスを待たずに処理を続行する非同期通信を行うことができる。速度優先のゼロコピー通信や、データのバッファリングを行わない通信などをサポートしているため、大容量のデータの送受信にも利用できる。また、I/Oライブラリについてもデフォルト設定であるNetty以外にさまざまなものを利用することが可能となっている。

FutureベースのAPIで非同期HTTP通信を試す

AsyncHttpClientはGitHubのリポジトリより入手することができる。Gitクライアントを使ってリポジトリをチェックアウトするか、右上の[Downloads]ボタンからアーカイブをダウンロードして展開します。最新版はバージョン1.4.1。Mavenプロジェクト形式になっているので、mvnコマンドでビルドして利用する。

Maven実行環境がない場合、このサイトよりビルド済みのjarファイルがダウンロードできるので、これを利用するといいだろう。

そのほかに、AsyncHtpClientではデフォルトのロギングライブラリとしてSLF4Jを使用する。そのため、ダウンロードページよりアーカイブをダウンロードして解凍し、「slf4j-api-xxx.jar」と「slf4j-simple-xxx.jar」("xxx"はバージョン番号)をクラスパスに含めておく必要がある。

AsyncHttpClientの非同期HTTP通信では、FutureベースのAPIとHandlerベースのAPIの2種類がサポートされている。FutureベースのAPIは、Javaの標準ライブラリとして付属するjava.util.concurrent.Futureインタフェースを利用した実装で、Futureオブジェクトにサーバからのレスポンスが格納されたと仮定して(実際にはまだレスポンスが返ってきていなかったとしても)処理を続行するというもの。

Futureでは処理が完了したかどうかのチェックや、完了するまでのブロック、処理結果の取得などを行うことができる。すなわち、通信が完了していなくても処理が止まることはないが、Futureを利用しようとした段階でまだレスポンスが返ってきていなければ、返ってくるまでブロックされるということだ。

今回は、このFutureベースのAPIを利用した非同期通信を試してみよう。AsyncHttpClientで非同期通信を行うには、まずcom.ning.http.client.AsyncHttpClientのインスタンスを生成した上で、HTTPの各メソッドに対応したprepareXXX()メソッドを呼び出す。GETメソッドの場合は、次の例のようにprepareGet()を使用する。引数には接続先のURLを渡す。このメソッドの戻り値(AsyncHttpClient.BoundRequestBuilderオブジェクト)に対してexecute()メソッドを実行すると、レスポンスを格納するためのFuture<Response>オブジェクトが返される。

リスト1

AsyncHttpClient httpClient = new AsyncHttpClient();
String url = "http://www.mycom.co.jp";
Future<Response> future = httpClient.prepareGet(url).execute();

この段階ではまだ通信が完了しているとは限らないが、プログラムはFutureにレスポンスが格納されたと仮定して処理を続行する。レスポンスの内容を取得したい場合には、次のようにFutureのget()メソッドを実行すればよい。もしこの段階で通信が完了していない場合には、get()の処理は完了するまでブロックされる。結果はcom.ning.http.client.Responseオブジェクトとして渡されるので、そこから各種メソッドを利用して内容を取得できる。

リスト2

Response response = future.get();

以上を踏まえ、AsyncHttpClientの非同期通信を使ったサンプルプログラムを以下に示す。

リスト3

public class AsyncHttpSample {
    public void connectWithFuture(String url) {
        // AsyncHttpClientオブジェクトを生成
        AsyncHttpClient httpClient = new AsyncHttpClient();
        try {
            // GETリクエストを送信
            Future<Response> future = httpClient.prepareGet(url).execute();
            System.out.println("Requested to " + url);

            // レスポンスの取得
            Response response = future.get();
            System.out.println("Response from " + response.getUri());

            // 切断
            httpClient.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        } catch (ExecutionException ex) {
            ex.printStackTrace();
        }
    }

    public static void main(String[] args) {
        AsyncHttpSample asyncHttp = new AsyncHttpSample();
        String url = "http://www.google.co.jp";
        asyncHttp.connectWithFuture(url);
    }
}

この例ではResponseからはレスポンス元のURIしか取得していないが、getHeaders()やgetResponseBody()などのメソッドによってその他の内容も取得することが可能である。

次回は、AsyncHttpClientに用意されたもうひとつの非同期通信のAPIであるHandlerベースのAPIについて解説する。