The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.

QuarkusアプリケーションからのEclipse Vert.x APIの使用

Vert.xは、リアクティブなアプリケーションを構築するためのツールキットです。 Quarkus Reactive Architectureに記載されているように、QuarkusではVert.xを下地に使用しています。

Quarkus Reactive Core

QuarkusのアプリケーションはVert.xのAPIにアクセスして使用することができます。

このガイドでは、Quarkusのアプリケーションで次を使って構築する方法を紹介します。

  • Vert.xのマネージドインスタンス

  • Vert.x イベントバス

  • Vert.x Webクライアント

これは入門ガイドです。 Vert.xリファレンスガイドでは、バーティクルやネイティブトランスポートなど、より高度な機能について説明しています。

アーキテクチャ

ここでは、4つのHTTPエンドポイントを公開するシンプルなアプリケーションを作成します。

  1. /vertx/lorem 小さなファイルからコンテンツを返す

  2. /vertx/book 大きなファイル(本)からコンテンツを返す

  3. /vertx/hello は、Vert.x イベントバスを使用してレスポンスを生成します

  4. /vertx/web は、Vert.x Web クライアントを使用して Wikipedia からデータを取得します

Vert.xガイドのアーキテクチャ

ソリューション

次のセクションで紹介する手順に沿って、ステップを踏んでアプリを作成することをお勧めします。ただし、完成した例にそのまま進んでも構いません。

Gitリポジトリをクローン: git clone https://github.com/quarkusio/quarkus-quickstarts.git 、または archive をダウンロードする。

このソリューションは vertx-quickstart directory にあります。

Mutiny

このガイドでは、Mutiny APIを使用しています。Mutinyに慣れていない方は、 Mutiny - 直感的なリアクティブプログラミングライブラリをご覧ください。

アプリケーションの起動

このリンクをクリックして、アプリケーションを設定してください。いくつかのエクステンションが選択されます。

  • resteasy-reactive-jackson 。これは resteasy-reactive も持ち込みます。これを使って、HTTPエンドポイントを公開します。

  • vertx 、下地となるマネージドVert.xへのアクセスを提供します。

Generate your application ボタンをクリックし、ZIPファイルをダウンロードして解凍します。その後、お好きなIDEでプロジェクトを開いてください。

生成されたビルドファイルを開くと、選択されたエクステンションが表示されます:

pom.xml
<dependency>
  <groupId>io.quarkus</groupId>
  <artifactId>quarkus-resteasy-reactive-jackson</artifactId>
</dependency>
<dependency>
  <groupId>io.quarkus</groupId>
  <artifactId>quarkus-vertx</artifactId>
</dependency>
build.gradle
implementation("io.quarkus:quarkus-resteasy-reactive-jackson")
implementation("io.quarkus:quarkus-vertx")

ビルドファイルの中で、以下の依存関係を追加してください。

pom.xml
<dependency>
  <groupId>io.smallrye.reactive</groupId>
  <artifactId>smallrye-mutiny-vertx-web-client</artifactId>
</dependency>
build.gradle
implementation("io.smallrye.reactive:smallrye-mutiny-vertx-web-client")

この依存関係は、Vert.x Web クライアントを提供し、 /web エンドポイントの実装に使用されます。

Vert.xマネージドインスタンスへのアクセス

src/main/java/org/acme/VertxResource.java ファイルを作成します。このファイルには、HTTPエンドポイントが含まれます。

このファイルに、以下のコードをコピーします。

package org.acme;

import io.vertx.mutiny.core.Vertx;

import javax.inject.Inject;
import javax.ws.rs.Path;

@Path("/vertx")                        (1)
public class VertxResource {

    private final Vertx vertx;

    @Inject                             (2)
    public VertxResource(Vertx vertx) { (3)
        this.vertx = vertx;             (4)
    }
}
1 ルートHTTPパスを宣言します。
2 コンストラクタ・インジェクションを使用して、マネージドVert.xインスタンスを受け取ります。フィールド・インジェクションも有効です。
3 コンストラクタのパラメータとしてVert.xインスタンスを受け取ります。
4 マネージドVert.xインスタンスをフィールドに格納します。

これで、エンドポイントの実装を始めることができます。

Vert.x Core APIの使用

インジェクションされたVert.xインスタンスは、利用可能なAPIのセットを提供します。このセクションで使用するのはVert.x File Systemです。これは、ファイルにアクセスするためのノンブロッキングAPIを提供します。

src/main/resource ディレクトリに lorem.txt ファイルを次の内容で作成します。

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.

そして、 VertxResource ファイルに以下のメソッドを追加します。

@GET                                                                                   (1)
@Path("/lorem")
public Uni<String> readShortFile() {                                                   (2)
    return vertx.fileSystem().readFile("lorem.txt")                                    (3)
            .onItem().transform(content -> content.toString(StandardCharsets.UTF_8));  (4)
}
1 このエンドポイントは、パス /lorem に対する HTTP GET リクエストを処理します(そのため、フルパスは vertx/lorem となります)。
2 Vert.x APIは非同期なので、このメソッドは Uni を返却します。Uniで表される非同期操作が完了すると、その内容がHTTPレスポンスに書き込まれます。
3 Vert.xのファイルシステムAPIを使用して、作成されたファイルを読み取ります。
4 ファイルが読み込まれると、その内容がメモリ内のバッファに格納されます。このバッファをStringに変換します。

ターミナルで、プロジェクトのルートに移動して次を実行します。

CLI
quarkus dev
Maven
./mvnw quarkus:dev
Gradle
./gradlew --console=plain quarkusDev

別の端末で、次を実行します。

> curl http://localhost:8080/vertx/lorem

コンソールにファイルの内容が表示されるはずです。

Quarkusは、静的ファイルを提供する他の方法を提供しています。これはガイドのために作られた例です。

Vert.x stream の能力の使用

ファイルを読み込んで内容をメモリに保存する方法は、小さなファイルには有効ですが、大きなファイルには使えません。このセクションでは、Vert.xのストリーミング機能をどのように使用するかを説明します。

まず、 戦争と平和をダウンロードして、 src/main/resources/book.txt に保存します。これは3.2Mbのファイルで、巨大ではありませんが、ストリームの目的を説明しています。今回は、ファイルの内容をメモリに蓄積して一括して書き込むのではなく、チャンクごとに読み込んで、そのチャンクを1つずつHTTPレスポンスに書き込んでいきます。

そこで、プロジェクト内に以下のファイルを用意しておきます。

.
├── mvnw
├── mvnw.cmd
├── pom.xml
├── README.md
├── src
│  └── main
│     ├── docker
│     │  ├── ...
│     ├── java
│     │  └── org
│     │     └── acme
│     │        └── VertxResource.java
│     └── resources
│        ├── application.properties
│        ├── book.txt
│        └── lorem.txt

VertxResource クラスに以下のメソッドを追加します。

@GET
@Path("/book")
public Multi<String> readLargeFile() {                                               (1)
    return vertx.fileSystem().open("book.txt",                                       (2)
                    new OpenOptions().setRead(true)
            )
            .onItem().transformToMulti(file -> file.toMulti())                       (3)
            .onItem().transform(content -> content.toString(StandardCharsets.UTF_8) (4)
                    + "\n------------\n");                                           (5)
}
1 今回は、チャンクをストリーミングしたいので、Multiを返します。
2 open メソッドを使ってファイルを開きます。このメソッドは Uni<AsyncFile> を返却します。
3 ファイルが開かれると、チャンクを含む Multi が取得できます。
4 各チャンクは、String を生成します。
5 レスポンス内のチャンクを視覚的に確認するために、セパレーターを追加します。

そして、ターミナルで、次を実行します。

> curl http://localhost:8080/vertx/book

ブックの内容を取得します。出力には次のようなセパレータが表示されるはずです。

...
The little princess had also left the tea table and followed Hélène.

“Wait a moment, I’ll get my work.... Now then, what
------------
 are you
thinking of?” she went on, turning to Prince Hippolyte. “Fetch me my
workbag.”
...

イベントバスの使用

Vert.xのコア機能の1つは、 イベントバス です。 これは、アプリケーションにメッセージベースのバックボーンを提供します。 したがって、非同期メッセージパッシングを使用してコンポーネントを相互作用させることができるため、コンポーネントを切り離すことができます。 単一のコンシューマーにメッセージを送信したり、複数のコンシューマーにディスパッチしたり、メッセージ(要求)を送信して応答を期待する要求と応答の対話を実装したりできます。 これは、このセクションで使用するものです。 VertxResource は、名前を含むメッセージを greetings アドレスに送信します。 別のコンポーネントがメッセージを受信し、 "hello$name" 応答を生成します。 VertxResource は応答を受信し、HTTP応答として返します。

では、以下の内容で VertxResource クラスを拡張してください。

@Inject
EventBus bus;                                                   (1)

@GET
@Path("/hello")
public Uni<String> hello(@QueryParam("name") String name) {     (2)
    return bus.<String>request("greetings", name)               (3)
            .onItem().transform(response -> response.body());   (4)
}
1 イベントバスを注入します。 または、 vertx.eventBus() を使用することもできます。
2 クエリパラメータとして name を受け取ります
3 request メソッドを使用して、要求と応答の相互作用を開始します。 名前を "greetings" アドレスに送信します。
4 応答を受信すると、本文を抽出してHTTP応答として返します

ここで、もう一方の側が必要です。名前を受け取って応答するコンポーネントです。 次の内容で src/main/java/org/acme/GreetingService.java ファイルを作成します。

package org.acme;

import io.quarkus.vertx.ConsumeEvent;

import javax.enterprise.context.ApplicationScoped;

@ApplicationScoped                          (1)
public class GreetingService {

    @ConsumeEvent("greetings")              (2)
    public String hello(String name) {      (3)
        return "Hello " + name;             (4)
    }
}
1 アプリケーションスコープでCDIBeanを宣言します。 Quarkusは、このクラスの単一のインスタンスを作成します。
2 @ ConsumeEvent アノテーションを使用して、コンシューマーを宣言します。 Vert.x APIを 直接 使用することも可能です。
3 メソッドパラメータとしてメッセージペイロードを受信します。 返されるオブジェクトは応答になります。
4 応答を返します。 この応答は `VertxResource`クラスに返送されます

これを試してみましょう。 ターミナルで、次の手順を実行します。

> curl "http://localhost:8080/vertx/hello?name=bob"

期待される Hello bob メッセージを返す必要があります。

Vert.x クライアントの使用

これまで、Vert.x Core APIを使用してきました。 Vert.xはさらに多くの機能、広大なエコシステムを提供します。 このセクションでは、リアクティブHTTPクライアントであるVert.x Webクライアントの使用方法を説明します。

一部のQuarkusエクステンションはVert.xクライアントをラップし、それらを管理していることに注意してください。 これは、リアクティブデータソース、Redis、メールの場合です…​ Webクライアントの場合はそうではありません。

ガイドの冒頭で、 smallrye-mutiny-vertx-web-client 依存関係を pom.xml ファイルに追加したことを思い出して下さい。 それを使用する時が来ました。

まず、 WebClient のインスタンスを作成する必要があります。 VertxResource クラスを client フィールドで拡張し、コンストラクターでWebクライアントを作成します。

private final Vertx vertx;
private final WebClient client;            (1)

@Inject
public VertxResource(Vertx vertx) {
    this.vertx = vertx;
    this.client = WebClient.create(vertx); (2)
}
1 WebClient を保存して、HTTPエンドポイントで使用できるようにします
2 WebClient を作成します。 必ず `io.vertx.mutiny.ext.web.client.WebClient`クラスを使用してください

次に、Wikipedia APIにクエリを実行してQuarkusに関するページをさまざまな言語で取得する新しいHTTPエンドポイントを実装しましょう。 次のメソッドを `VertxResource`クラスに追加します。

private static final String URL = "https://en.wikipedia.org/w/api.php?action=parse&page=Quarkus&format=json&prop=langlinks";

@GET
@Path("/web")
public Uni<JsonArray> retrieveDataFromWikipedia() {                     (1)
    return client.getAbs(URL).send()                                    (2)
            .onItem().transform(HttpResponse::bodyAsJsonObject)         (3)
            .onItem().transform(json -> json.getJsonObject("parse")     (4)
                                        .getJsonArray("langlinks"));
}
1 このエンドポイントはJSON配列を返します。 Vert.xは、JSONオブジェクトと配列を操作するための便利な方法を提供します。 これらの詳細については、リファレンスガイド をご覧ください。
2 GET リクエストをWikipedia APIに送信します
3 応答を受信したら、それをJSONオブジェクトとして抽出します
4 応答から langlinks 配列を抽出します。

そして、エンドポイントを呼び出します。

> curl http://localhost:8080/vertx/web
[{"lang":"de", "url", :"https://de.wikipedia.org/wiki/Quarkus", "langname", :"German", "autonym", :"Deutsch", "*", :"Quarkus"}, {"lang":"fr", "url", :"https://fr.wikipedia.org/wiki/Quarkus", "langname", :"French", "autonym", :"français", "*", :"Quarkus"}]

応答は、英語のページに加えて、ウィキペディアにQuarkusに関するドイツ語とフランス語のページがあることを示しています。

さらに詳しく

このガイドでは、QuarkusアプリケーションからVert.xAPIを使用する方法を紹介しました。 簡単な概要ですので、詳細については、QuarkusにおけるVert.xのリファレンスガイドを参照してください。

イベントバスは、Vert.xアプリケーションの接続組織です。Quarkusはこれを統合しているので、様々なBeanが非同期メッセージと対話できます。この部分は、 イベントバスのドキュメント でカバーされています。

Reactive SQLクライアント を使用して、Quarkus上に高パフォーマンスで低オーバーヘッドのデータベースアプリケーションを実装する方法をご紹介しています。