1概要



RxJava


は、非同期およびイベントベースのプログラムを作成するための一般的なライブラリです。http://reactivex.io/[Reactive Extensions]によって提唱された主なアイデアからヒントを得たものです。 __イニシアチブ。



Vert.x


は、

Eclipse

の傘下にあるプロジェクトで、反応パラダイムを最大限に活用するためにゼロから設計されたいくつかのコンポーネントを提供します。

一緒に使用すると、それらは反応的である必要がある

Java

プログラムのための有効な基盤であることを証明できます。

この記事では、都市名のリストを含むファイルをロードし、それぞれについて、日の出から日没までの1日の長さを出力します。

公衆から公開されたデータを使用します。https://www.metaweather.com/api/

REST API

– 日光の長さと

RxJava



Vert.x

で計算して純粋に計算します。反応的な方法です。


2 Mavenの依存関係


vertx-rx-java2

をインポートすることから始めましょう。

<dependency>
    <groupId>io.vertx</groupId>
    <artifactId>vertx-rx-java2</artifactId>
    <version>3.5.0-Beta1</version>
</dependency>

これを書いている時点では、

Vert.x

と新しい

RxJava 2

の統合はベータ版としてしか利用できませんが、私たちが構築しているプログラムにとっては十分安定しています。


io.vertx:vertx-rx-java2



io.reactivex.rxjava2:rxjava

に依存しているため、

RxJava

関連のパッケージを明示的にインポートする必要はありません。


Vert.x



RxJava

の統合の最新バージョンは、https://search.maven.org/classic/#search%7Cga%7C1%7Ca%3A%22vertx-rx-java2%22[Maven Central]で見つけることができます。


3セットアップ


Vert.xを使用するすべてのアプリケーションと同様に、

vertx

オブジェクトの作成を開始します。これは、すべての

Vert.x__機能への主要なエントリポイントです。

Vertx vertx = io.vertx.reactivex.core.Vertx.vertx();


vertx-rx-java2

ライブラリには、

io.vertx.core.Vertx



io.vertx.reactivex.core.Vertx

の2つのクラスがあります。最初のものは

Vert.x

を基にしたアプリケーションの通常のエントリポイントですが、後者は

RxJava

との統合に使用するものです。

後で使用するオブジェクトを定義します。

FileSystem fileSystem = vertx.fileSystem();
HttpClient httpClient = vertx.createHttpClient();


Vert.x

‘s

FileSystem

は反応的な方法でファイルシステムにアクセスできますが、

Vert.x

‘s

HttpClient



HTTP

についても同じです。


4反応性チェーン

反応的な状況では、いくつかの単純な反応的な演算子を連結して意味のある計算を行うのは簡単です。

私たちの例のためにそれをやろう

fileSystem
  .rxReadFile("cities.txt").toFlowable()
  .flatMap(buffer -> Flowable.fromArray(buffer.toString().split("\\r?\\n")))
  .flatMap(city -> searchByCityName(httpClient, city))
  .flatMap(HttpClientResponse::toFlowable)
  .map(extractingWoeid())
  .flatMap(cityId -> getDataByPlaceId(httpClient, cityId))
  .flatMap(toBufferFlowable())
  .map(Buffer::toJsonObject)
  .map(toCityAndDayLength())
  .subscribe(System.out::println, Throwable::printStackTrace);

それでは、それぞれの論理的なコードがどのように機能するのかを調べてみましょう。


5市の名前

最初のステップは都市名のリストを含むファイルを読むことです。

fileSystem
 .rxReadFile("cities.txt").toFlowable()
 .flatMap(buffer -> Flowable.fromArray(buffer.toString().split("\\r?\\n")))

メソッド

rxReadFile()

は、反応的にファイルを読み込み、

RxJava

s

Single <Buffer>

を返します。それで、私たちが探している統合を得ました:

RxJava

からのデータ構造における

Vert.x

の非同期性。

ファイルは1つしかないため、ファイルの全内容を含む1つの

Buffer

が1回表示されます。その入力を

RxJava

s

Flowable

に変換し、ファイルの行をフラットマップして、代わりに各都市名のイベントを発行する

Flowable

を作成します。


6. JSONシティディスクリプタ

都市名を取得したら、次のステップは

Metaweather REST API

を使用してその都市のIDコードを取得することです。この識別子は、都市の日の出と日の入り時間を取得するために使用されます。一連の呼び出しを続けましょう。

一連の呼び出しを続けましょう。

.flatMap(city -> searchByCityName(httpClient, city))
.flatMap(HttpClientResponse::toFlowable)


searchByCityName()

メソッドは最初のステップで作成した

HttpClient

を使用して、都市の識別子を与える

REST

サービスを呼び出します。次に、2番目の

flatMap()を使用して、応答を含む

Buffer__を取得します。


searchByCityName()

本体を記述して、この手順を完了しましょう。

Flowable<HttpClientResponse> searchByCityName(HttpClient httpClient, String cityName) {
    HttpClientRequest req = httpClient.get(
        new RequestOptions()
          .setHost("www.metaweather.com")
          .setPort(443)
          .setSsl(true)
          .setURI(format("/api/location/search/?query=%s", cityName)));
    return req
      .toFlowable()
      .doOnSubscribe(subscription -> req.end());
}


Vert.x

‘s

HttpClient

は、反応性

HTTP

応答を生成する

RxJava

‘s

Flowable

を返します。これは順番に

Buffers

に分割されたレスポンスの本体を生成します。

適切なURLへの新しいリアクティブリクエストを作成しましたが、リクエストを送信できることを通知するには**

Vert.x

を呼び出すには

HttpClientRequest.end()

メソッドが必要であり、

endの前に少なくとも1つのサブスクリプションも必要です()

を正常に呼び出すことができました。

そのための解決策は、

RxJava

のhttp://reactivex.io/documentation/operators/do.html[

doOnSubscribe()

]を使用して、消費者が購読するとすぐに

end()

を呼び出すことです。


7. 市の識別子

今度は、返された

JSON

オブジェクトの

woeid

プロパティの値を取得する必要があります。これは、カスタムメソッドを通じて都市を一意に識別します。

.map(extractingWoeid())


extractingWoeid()

メソッドは、

REST

サービス応答に含まれている

JSON

から都市の識別子を抽出する関数を返します。

private static Function<Buffer, Long> extractingWoeid() {
    return cityBuffer -> cityBuffer
      .toJsonArray()
      .getJsonObject(0)
      .getLong("woeid");
}


Buffer

が提供する便利な

toJson …​()

メソッドを使用して、必要なプロパティにすばやくアクセスすることができます。


8市の詳細

リアクティブチェーンを続けて、必要な詳細を

REST API

から取得します。

.flatMap(cityId -> getDataByPlaceId(httpClient, cityId))
.flatMap(toBufferFlowable())


getDataByPlaceId()

メソッドの詳細を見てみましょう。

static Flowable<HttpClientResponse> getDataByPlaceId(
  HttpClient httpClient, long placeId) {

    return autoPerformingReq(
      httpClient,
      format("/api/location/%s/", placeId));
}

ここでは、前の手順で設定したのと同じアプローチを使用しました。


getDataByPlaceId()

は、

Flowable <HttpClientResponse>

を返します。

HttpClientResponse

は、数バイトより長い場合は、

API

応答をまとめて送信します。


toBufferFlowable()

メソッドを使用して、応答チャンクを単一のものに縮小し、完全なJSONオブジェクトにアクセスできるようにします。

static Function<HttpClientResponse, Publisher<? extends Buffer>>
  toBufferFlowable() {
    return response -> response
      .toObservable()
      .reduce(
        Buffer.buffer(),
        Buffer::appendBuffer).toFlowable();
}


9日の入りと日の出の時間


JSON

オブジェクトから、関心のある情報を取得しながら、リアクティブチェーンに追加し続けます。

.map(toCityAndDayLength())


toCityAndDayLength()

メソッドを書きましょう。

static Function<JsonObject, CityAndDayLength> toCityAndDayLength() {
    return json -> {
        ZonedDateTime sunRise = ZonedDateTime.parse(json.getString("sun__rise"));
        ZonedDateTime sunSet = ZonedDateTime.parse(json.getString("sun__set"));
        String cityName = json.getString("title");
        return new CityAndDayLength(
          cityName, sunSet.toEpochSecond() - sunRise.toEpochSecond());
    };
}

日の出から日の入りまでの時間を単に時間単位で計算する

POJO

を作成するために

JSON

に含まれる情報をマップする関数を返します。


10購読

反応性鎖が完成する。生成された

CityAndDayLength

のインスタンスを出力するハンドラ、またはエラーが発生した場合はスタックトレースを使用して、結果の

Flowable

をサブスクライブできます。

.subscribe(
  System.out::println,
  Throwable::printStackTrace)

アプリケーションを実行すると、リストに含まれている都市とアプリケーションが実行された日付に応じて、次のような結果が表示されます。

In Chicago there are 13.3 hours of light.
In Milan there are 13.5 hours of light.
In Cairo there are 12.9 hours of light.
In Moscow there are 14.1 hours of light.
In Santiago there are 11.3 hours of light.
In Auckland there are 11.2 hours of light.


HTTP API

へのすべての要求は非同期に実行されるため、都市はファイルで指定された都市とは異なる順序で表示される可能性があります。


11結論

この記事では、

Vert.x

対応型モジュールと

RxJava

によって提供される演算子および論理構成体を混在させることがいかに簡単かを説明しました。

私たちが構築したリアクティブチェーンは、長くても、複雑なシナリオをかなり簡単に作成できることを示しています。

いつものように、完全なソースコードはhttps://github.com/eugenp/tutorials/tree/master/vertx-and-rxjava[over on GitHub]から入手可能です。