Building my first extension
Quarkus のエクステンションは、プロジェクトの依存関係がそうであるように、アプリケーションを強化します。エクステンションの役割は、Quarkus のパラダイムを活用して、ライブラリを Quarkus アーキテクチャにシームレスに統合することです。たとえば、ビルド時に、より多くのことを行います。これが、実績のあるエコシステムを利用して、Quarkus のパフォーマンスとネイティブコンパイルを活用することができる仕組みです。 code.quarkus.io にアクセスして、サポートされているエクステンションのリストを入手してください。
このガイドでは、サンプル Greeting エクステンション を開発します。このエクステンションは、ビジターに挨拶をするだけのカスタマイズ可能な HTTP エンドポイントを公開します。
|
免責事項
To be sure it’s extra clear you don’t need an extension to add a Servlet to your application.
This guide is a simplified example to explain the concepts of extensions development, see the full documentation if you need more information.
Keep in mind it’s not representative of the power of moving things to build time or simplifying the build of native images.
|
前提条件
このガイドを完成させるには、以下が必要です:
-
ざっと 30 minutes
-
IDE
-
JDK 17+がインストールされ、
JAVA_HOMEが適切に設定されていること -
Apache Maven 3.9.9
-
使用したい場合は、 Quarkus CLI
|
JavaとMaven以外でエクステンションを作成することは、Quarkusチームによってテストされて いません 。 したがって、この方法から外れると、期待通りに動作しない可能性があります。 |
基本概念
まず最初に、いくつかの基本的な概念から始めましょう。
-
JVM モードとネイティブモード
-
Quarkus は最初の Java フレームワークです。つまり、従来の JAR アプリケーションの開発、パッケージ化、実行を行うことができます。これは、JVM モード と呼ばれます。
-
GraalVM により、Java アプリケーションをマシン固有のコード (Go や C++ のように) にコンパイルすることができます。これは、ネイティブモード と呼ばれます。
-
Java バイトコードをネイティブシステム固有のマシンコードにコンパイルする操作は、Ahead of Time Compilation (AoT) と呼ばれています。
-
従来型の Java フレームワークにおけるビルド時と実行時の比較
-
ビルド時は、Javaソース・ファイルを実行可能なもの(クラス・ファイル、jar/war、ネイティブ・イメージ)に変換するために適用するすべてのアクションに対応します。 通常、この段階はコンパイル、アノテーション処理、バイトコード生成などで構成されます。この時点では、すべてが開発者の範囲と制御下にあります。
-
実行時はアプリケーションを実行するときに起こるすべてのアクションです。 実行時は明らかにビジネス指向のアクションを開始することに重点を置いていますが、ライブラリや設定ファイルのロード、アプリケーションのクラスパスのスキャン、依存性注入の設定、オブジェクトリレーショナルマッピングの設定、RESTコントローラのインスタンス化など、多くの技術的なアクションに依存しています。
-
通常、Javaフレームワークは、アプリケーションの "ビジネス志向のレイヤー" を実際に起動する前に、実行時中にブートストラップを行います。ブートストラップの際、フレームワークは、リフレクションによって適切なオブジェクトをインスタンス化するために、設定、エンティティー定義、依存関係の注入バインディングなどを見つけるためにクラスパスをスキャンします。これにより、動的にメタデータを収集します。主な結果は以下の通りです。
-
アプリケーションの準備が遅れる: 実際にビジネスリクエストに対応する前に数秒待つ必要があります。
-
ブートストラップでリソース消費のピークを持つ: 制約のある環境では、実際のビジネスニーズではなく、技術的なブートストラップのニーズに基づいて、必要なリソースのサイズを決定する必要があります。
Quarkus の概念は、これらのアクションの左シフトを行い、最終的にはビルド時に実行することで、可能な限り低速でメモリー集約的な動的コードの実行を防ぐことです。Quarkus のエクステンションは、お気に入りのライブラリやテクノロジーのアダプターレイヤーとして機能する Java のコードです。
Quarkus のエクステンションの説明
Quarkus のエクステンションは、2 つの部分から構成されています。
-
エクステンション開発者がアプリケーション開発者に公開する機能を表す ランタイムモジュール (認証フィルター、強化されたデータ層 API など)。ランタイム依存関係は、ユーザーがアプリケーションの依存関係として追加するものです (Maven POM または Gradle ビルドスクリプト)。
-
ビルドの拡張フェーズで使用される デプロイモジュール で、Quarkus の概念に従ったライブラリを「デプロイ」する方法を説明しています。つまり、ビルド中にアプリケーションに Quarkus のすべての最適化を適用します。このデプロイメントモジュールは、GraalVM のネイティブコンパイルのための準備をする場所でもあります。
| Users should not be adding the deployment modules of extension as application dependencies. The deployment dependencies are resolved by Quarkus during the augmentation phase from the runtime dependencies of the application. |
この時点で、このデプロイメントモジュールにより、多くのマジックは拡張ビルド時に起こることを理解しているはずです。
Quarkus アプリケーションブートストラップ
Quarkus アプリケーションには、3 つの異なるブートストラップフェーズがあります。
-
拡張 (Augmentation)。ビルド時に、Quarkus エクステンションはアプリケーションのバイトコード (依存関係を含む) と設定をロードしてスキャンします。 この段階で、エクステンションは設定ファイルを読み込んだり、特定のアノテーションのためにクラスをスキャンしたりすることができます。 すべてのメタデータが収集されたら、エクステンションは、ORM、DI、または REST コントローラーの設定のようなライブラリーのブートストラップアクションを前処理することができます。 ブートストラップの結果はバイトコードに直接記録され、最終的なアプリケーションパッケージの一部となります。
-
静的 Init 実行時に、Quarkus は最初に、いくつかの拡張アクション/設定を含む最初の静的 init メソッドを実行します。 ネイティブパッケージングを行う場合、このスタティックメソッドはビルド時に前処理され、生成されたオブジェクトは最終的なネイティブ実行可能ファイルにシリアライズされるため、初期化コードはネイティブモードでは実行されません (このフェーズではフィボナッチ関数を実行すると想像してください。計算の結果は、ネイティブ実行可能ファイルに直接記録されます)。 JVM モードでアプリケーションを実行している場合、この静的 init フェーズはアプリケーションの開始時に実行されます。
-
ランタイム Init このフェーズでは特に目立つことはありません。従来的なランタイムコード実行を行います。 つまり、上記の 2 つのフェーズでより多くのコードを実行すればするほど、アプリケーションの起動が速くなります。
これで全てが説明されたので、さっそくコーディングに取り掛かりましょう
プロジェクトのセットアップ
エクステンションは、MavenまたはGradleのいずれかでビルドできます。お使いのビルドツールに応じて、以下のようにセットアップを行います。
| The Gradle extension plugin is still experimental and may be missing features available in the Maven plugin. |
Maven のセットアップ
Quarkus は、 create-extension Maven Mojo を提供し、エクステンションプロジェクトを初期化します。
オプションの自動検出が試行されます。
-
quarkus(Quarkus Core) またはquarkus/extensionsディレクトリからアクセスすると、'Quarkus Core' エクステンションのレイアウトとデフォルトが使用されます。 -
-DgroupId=io.quarkiverse.[extensionId]を使用すると、'Quarkiverse' エクステンションのレイアウトとデフォルトを使用します。 -
それ以外の場合は 'Standalone' エクステンションのレイアウトとデフォルトを使用します。
-
将来的には他のレイアウトタイプを導入する可能性があります。
You may call it without any parameter to use the interactive mode: mvn io.quarkus.platform:quarkus-maven-plugin:3.20.6.2:create-extension -N
|
$ mvn io.quarkus.platform:quarkus-maven-plugin:3.20.6.2:create-extension -N \
-DgroupId=org.acme \ (1)
-DextensionId=greeting-extension \ (2)
-DwithoutTests (3)
[INFO] --- quarkus-maven-plugin:3.20.6.2:create-extension (default-cli) @ standalone-pom ---
Detected layout type is 'standalone' (4)
Generated runtime artifactId is 'greeting-extension' (5)
applying codestarts...
🔠 java
🧰 maven
🗃 quarkus-extension
🐒 extension-base
-----------
👍 extension has been successfully generated in:
--> /Users/ia3andy/workspace/redhat/quarkus/demo/greeting-extension
-----------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.659 s
[INFO] Finished at: 2021-01-25T16:17:16+01:00
[INFO] ------------------------------------------------------------------------
| 1 | エクステンション groupId |
| 2 | エクステンション ID (名前空間ではない)。 |
| 3 | テスト不要を示す |
| 4 | それ以上のオプションなしで、pom.xml のないディレクトリから、ジェネレーターは自動的に 'standalone' 拡張レイアウトを選択します。 |
| 5 | 'standalone' レイアウトでは、 namespaceId はデフォルトでは空なので、計算される実行時モジュールの artifactId は extensionId です。 |
Maven は、親 pom.xml、 runtime 、 deployment モジュールから成る拡張プロジェクトを含む quarkus-greeting ディレクトリーを生成しました。
親 pom.xml
お使いのエクステンションはマルチモジュールプロジェクトです。まずは、 ./quarkus-greeting/pom.xml の親 POM から見ていきましょう。
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>org.acme</groupId>
<artifactId>greeting-extension-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Greeting Extension - Parent</name>
<modules>(1)
<module>deployment</module>
<module>runtime</module>
</modules>
<properties>
<compiler-plugin.version>3.14.0</compiler-plugin.version>(2)
<failsafe-plugin.version>${surefire-plugin.version}</failsafe-plugin.version>
<maven.compiler.release>17</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<quarkus.version>3.20.6.2</quarkus.version>
<surefire-plugin.version>3.0.0</surefire-plugin.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>(3)
<groupId>io.quarkus</groupId>
<artifactId>quarkus-bom</artifactId>
<version>${quarkus.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<plugins>
<plugin>(4)
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<configuration>
<systemPropertyVariables>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
<maven.repo>${settings.localRepository}</maven.repo>
</systemPropertyVariables>
</configuration>
</plugin>
<plugin>(4)
<artifactId>maven-failsafe-plugin</artifactId>
<version>${failsafe-plugin.version}</version>
<configuration>
<systemPropertyVariables>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
<maven.repo>${settings.localRepository}</maven.repo>
</systemPropertyVariables>
</configuration>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler-plugin.version}</version>
<configuration>
<parameters>true</parameters>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
| 1 | エクステンションは、2 つのサブモジュール deployment と runtime を宣言しています。 |
| 2 | Quarkus では、annotationProcessorPaths 設定に対応する、最新バージョンの Maven コンパイラープラグインのが必要です。 |
| 3 | quarkus-bom は、オーグメンテーションの段階で Quarkus が使用している依存関係を調整します。 |
| 4 | Quarkusは、テストを適切に実行するためにこれらの設定を必要とします。 |
Deployment モジュール
デプロイメントの ./quarkus-greeting/deployment/pom.xml を見てみましょう。
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.acme</groupId>
<artifactId>greeting-extension-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>greeting-extension-deployment</artifactId> (1)
<name>Greeting Extension - Deployment</name>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc-deployment</artifactId> (2)
</dependency>
<dependency>
<groupId>org.acme</groupId>
<artifactId>greeting-extension</artifactId> (3)
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5-internal</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-extension-processor</artifactId> (4)
<version>${quarkus.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</project>
主なポイント:
| 1 | 決まりとして、配置モジュールのサフィックスは -deployment (greeting-deployment) です。 |
| 2 | デプロイメントモジュールは quarkus-core-deployment アーティファクトに依存しています。どの依存関係を追加するのが便利かは後ほど見ていきます。 |
| 3 | デプロイメントモジュールも実行時モジュールに依存している 必要があります 。 |
| 4 | コンパイラーのアノテーションプロセッサーに quarkus-extension-processor を追加します。 |
pom.xml create-extension に加えて org.acme.quarkus.greeting.deployment.GreetingProcessor クラスも生成されました。
package org.acme.greeting.extension.deployment;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.builditem.FeatureBuildItem;
class GreetingExtensionProcessor {
private static final String FEATURE = "greeting-extension";
@BuildStep
FeatureBuildItem feature() {
return new FeatureBuildItem(FEATURE);
}
}
FeatureBuildItem represents a functionality provided by an extension.
The name of the feature gets displayed in the log during application bootstrap.
An extension should provide at most one feature.
|
Build Step Processor の概念とすべてのエクステンションのデプロイメント API については、後で説明します。この時点では、このクラスは、 greeting というエクステンションをデプロイする方法を Quarkus に説明していることを理解する必要があります。つまり、アプリケーションを拡張して、Quarkus のすべての利点 (ビルド時間の最適化、ネイティブサポートなど) とともに greeting エクステンションを使用することになります。
実行時モジュール
最後に ./greeting-extension/runtime/pom.xml を見ていきます。
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemalocation="http://maven.apache.org/pom/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/pom/4.0.0"
xmlns:xsi="http://www.w3.org/2001/xmlschema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.acme</groupId>
<artifactId>greeting-extension-parent</artifactId>
<version>0.0.1-snapshot</version>
</parent>
<artifactId>greeting-extension</artifactId> (1)
<name>Greeting Extension - Runtime</name>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc</artifactId> (2)
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-extension-maven-plugin</artifactId> (3)
<version>${quarkus.version}</version>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>extension-descriptor</goal>
</goals>
<configuration>
<deployment>${project.groupId}:${project.artifactId}-deployment:${project.version}
</deployment>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-extension-processor</artifactId> (4)
<version>${quarkus.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</project>
主なポイント:
| 1 | 決まりとして、実行時モジュールはエンドユーザーに公開されるアーティファクトであるため、接尾辞 (greeting) を持たない。 |
| 2 | 実行時モジュールは quarkus-arc アーティファクトに依存しています。 |
| 3 | Quarkus-extension-maven-plugin を追加して、ランタイムアーティファクトに含まれるQuarkusエクステンションディスクリプタを生成します。Quarkusエクステンションディスクリプタはランタイムアーティファクトを対応するデプロイメントアーティファクトとリンクさせるものです。 |
| 4 | コンパイラーのアノテーションプロセッサーに quarkus-extension-processor を追加します。 |
Gradle のセットアップ
Quarkus は、エクステンションのGradleプロジェクトを初期化する方法を提供していません。
前述したように、エクステンションは2つのモジュールで構成されています。
-
runtime -
deployment
この2つのモジュールから構成される、Gradleのマルチモジュールプロジェクトを作ってみます。これが、簡単な settings.gradle のサンプルファイルです。
pluginManagement {
repositories {
mavenCentral()
gradlePluginPortal()
}
plugins {
id 'io.quarkus.extension' version "${quarkus.version}" (1)
}
}
include 'runtime', 'deployment' (2)
rootProject.name = 'greeting-extension'
| 1 | quarkusエクステンションプラグインのバージョン設定 |
| 2 | runtime と deployment の両方のモジュールをインクルード |
以下は、ルート build.gradle ファイルのサンプルです。
subprojects {
apply plugin: 'java-library' (1)
apply plugin: 'maven-publish' (2)
group 'org.acme' (3)
version '1.0-SNAPSHOT'
}
| 1 | すべてのサブモジュールに java-library プラグインを適用 |
| 2 | アーティファクトの公開に使用する maven-publish プラグインの適用 |
| 3 | 公開に使用するグループIDをグローバルに設定 |
io.quarkus.extension プラグインは、エクステンションをビルドするために使用されます。このプラグインは、 runtime モジュールに のみ 適用されます。
deployment モジュール
deployment モジュールは、特定のプラグインを必要としません。以下は、 deployment モジュールの最小の build.gradle ファイルの例です。
name = 'greeting-extension-deployment' (1)
dependencies {
implementation project(':runtime') (2)
implementation platform("io.quarkus:quarkus-bom:${quarkus.version}")
testImplementation 'io.quarkus:quarkus-junit5-internal'
}
| 1 | 決まりとして、配置モジュールのサフィックスは -deployment (greeting-deployment) です。 |
| 2 | デプロイメントモジュールは実行時モジュールに依存してい なければなりません 。 |
実行時モジュール
実行時モジュールは quarkus-arc アーティファクトに依存しています。
-
両方のモジュールに
quarkus-extension-processをアノテーションプロセッサーとして追加します。 -
エクステンションの説明ファイルを生成します。
以下は、 runtime モジュール用の build.gradle ファイルの例です:
plugins {
id 'io.quarkus.extension' (1)
}
name = 'greeting-extension' (2)
description = 'Greeting extension'
dependencies {
implementation platform("io.quarkus:quarkus-bom:${quarkus.version}")
}
| 1 | io.quarkus.extension プラグインを適用します。 |
| 2 | 決まりとして、実行時モジュールはエンドユーザーに公開されるアーティファクトであるため、接尾辞 (greeting) を持たない。 |
サンプル Greeting エクステンションの基本バージョン
Greeting 機能の実装
ここでのエクステンションの素晴らしい機能は、ユーザーに挨拶をすることです。これを行うには、このエクステンションはユーザーアプリケーションで、平文 Hello で GET 動詞に応答する HTTP エンドポイント /greeting を公開するサーブレットを展開します。
この 実行時 モジュールは、ユーザーに提案したい機能を開発するところなので、そろそろ Web Servlet を作成しましょう。
アプリケーションでサーブレットを使用するには、 Undertow のようなサーブレットコンテナーが必要です。幸い、 pom.xml にインポートされる quarkus-bom には、すでに Undertow Quarkus エクステンションが含まれています。
必要なのは、 quarkus-undertow を依存関係として ./greeting-extension/runtime/pom.xml に追加することだけです。
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-undertow</artifactId>
</dependency>
Gradleの場合は、 ./greeting-extension/runtime/build.gradle ファイルに依存関係を追加します:
implementation 'io.quarkus:quarkus-undertow'
The dependency on quarkus-arc generated by the create-extension mojo can now be removed since
quarkus-undertow already depends on it.
|
これで、 runtime モジュールでサーブレット org.acme.quarkus.greeting.GreetingServlet を作成することができるようになりました。
mkdir -p ./greeting-extension/runtime/src/main/java/org/acme/greeting/extension
package org.acme.greeting.extension;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet
public class GreetingExtensionServlet extends HttpServlet { (1)
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { (2)
resp.getWriter().write("Hello");
}
}
| 1 | 例によって、サーブレットを定義するには、 jakarta.servlet.http.HttpServlet を拡張する必要があります。 |
| 2 | HTTP GET 動詞に応答したいので、 doGet メソッドをオーバーライドして、サーブレット応答の出力ストリームに Hello を記述します。 |
Greeting 機能のデプロイ
Quarkus マジックは、実行時のコード評価を待つのではなく、ビルド時のバイトコード生成に依存します。これは、エクステンションの deployment モジュールの役割です。落ち着いてください、バイトコードは難しいので、手動でやりたくないでしょう。 Quarkus は、作業を楽にする高レベルの API を提案しています。基本的な概念のおかげで、デプロイ時に生成するバイトコードを生成するために、生成/消費する項目と対応する手順を説明できます。
io.quarkus.builder.item.BuildItem の概念は、 @io.quarkus.deployment.annotations.BuildStep でアノテーションされたメソッドのおかげで、生成または消費 (そしてある時点でバイトコードに変換したり) するオブジェクトインスタンスを表しています。このアノテーションは、エクステンションのデプロイメントタスクを説明しています。
- 注意
-
詳細は、 コアのBuildItem実装の全リストを参照してください。
生成された org.acme.quarkus.greeting.deployment.GreetingProcessor クラスに戻ります。
package org.acme.greeting.extension.deployment;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.builditem.FeatureBuildItem;
class GreetingExtensionProcessor {
private static final String FEATURE = "greeting-extension";
@BuildStep (1)
FeatureBuildItem feature() {
return new FeatureBuildItem(FEATURE); (2)
}
}
| 1 | feature() メソッドには @BuildStep というアノテーションが付けられています。これは、Quarkus がデプロイ時に実行しなければならないデプロイタスクとして識別されます。 BuildStep メソッドは、アプリケーションを拡張するための拡張時に同時に実行されます。これらは、プロデューサー/コンシューマーモデルを使用しています。このステップは、消費しているすべての項目が生成されるまで、実行されないことが保証されます。 |
| 2 | io.quarkus.deployment.builditem.FeatureBuildItem は、エクステンションの説明を表す BuildItem の実装です。この BuildItem は、アプリケーションの起動時にユーザーに情報を表示するために Quarkus が使用します。 |
多くの BuildItem 実装があり、それぞれが展開プロセスの一面を表しています。ここではいくつかの例を紹介します。
-
ServletBuildItem: デプロイ時に生成したいサーブレット (名前、パスなど) を記述します。 -
BeanContainerBuildItem: デプロイ時にオブジェクトインスタンスを保存・取得するために使用するコンテナーについて説明します。
実現したいことに対応する BuildItem が見つからない場合は、独自の実装を作成することができます。 BuildItem は、デプロイメントの特定の部分を表すもので、できるだけ細かいものでなければならないということを覚えておいてください。 BuildItem を作成する方法:
-
io.quarkus.builder.item.SimpleBuildItemデプロイ時にアイテムのインスタンスを1つだけ必要とする場合 (例:BeanContainerBuildItem、コンテナーが 1 つのみ必要な場合)。 -
複数のインスタンスを使いたい場合は
io.quarkus.builder.item.MultiBuildItem(例:ServletBuildItem、デプロイ時に多くのサーブレットを生成することができます)。
次は、HTTP エンドポイントを宣言します。これを行うには、 ServletBuildItem を生成する必要があります。この時点では、 quarkus-undertow 依存関係が runtime モジュールの Servlet サポートを提案している場合は、 deployment モジュールの quarkus-undertow-deployment 依存関係が io.quarkus.undertow.deployment.ServletBuildItem にアクセスできるようにする必要があることをご理解いただけたと思います。
quarkus-undertow-deployment を依存関係として ./greeting-extension/deployment/pom.xml に追加してみましょう。
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-undertow-deployment</artifactId>
</dependency>
The dependency on quarkus-arc-deployment generated by the create-extension mojo can now be removed since
quarkus-undertow-deployment already depends on it.
|
Gradleの場合は、 ./greeting-extension/deployment/build.gradle ファイルに依存関係を追加します:
implementation 'io.quarkus:quarkus-undertow-deployment'
これで org.acme.quarkus.greeting.deployment.GreetingProcessor を更新できるようになりました。
package org.acme.greeting.extension.deployment;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.builditem.FeatureBuildItem;
import org.acme.greeting.extension.GreetingExtensionServlet;
import io.quarkus.undertow.deployment.ServletBuildItem;
class GreetingExtensionProcessor {
private static final String FEATURE = "greeting-extension";
@BuildStep
FeatureBuildItem feature() {
return new FeatureBuildItem(FEATURE);
}
@BuildStep
ServletBuildItem createServlet() { (1)
ServletBuildItem servletBuildItem = ServletBuildItem.builder("greeting-extension", GreetingExtensionServlet.class.getName())
.addMapping("/greeting")
.build(); (2)
return servletBuildItem;
}
}
| 1 | ServletBuildItem を返す createServlet メソッドを追加し、 @BuildStep でアノテーションを付けます。これで、Quarkus はこの新しいタスクを処理して、ビルド時にサーブレット登録のバイトコードを生成します。 |
| 2 | ServletBuildItem は、流暢な API を処理して GreetingExtensionServlet 型の greeting-extension というサーブレットをインスタンス化し (エクステンション runtime によって提供されるクラスです)、 /greeting パスにマッピングします。 |
グリーティングエクステンションのテスト
Quarkus エクステンションを開発する際には、主に機能がアプリケーションに正しくデプロイされ、期待通りに動作するかどうかをテストすることを考える必要があります。そのため、テストは deployment モジュールでホストされます。
Quarkusは、既に deployment pom.xml にある quarkus-junit5-internal アーティファクトを介してエクステンションをテストするための機能を処理します (エクステンションでアプリケーションを起動する io.quarkus.test.QuarkusUnitTest ランナー)。
RestAssured (Quarkus で非常によく使われる) を使用して HTTP エンドポイントをテストします。 rest-assured の依存関係を ./greeting-extension/deployment/pom.xml に追加しましょう。
...
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
Gradleの場合は、 ./greeting-extension/deployment/build.gradle ファイルに依存関係を追加します:
...
testImplementation 'io.rest-assured:rest-assured'
現在、 create-extension Maven Mojo はテストと統合テスト構造 (-DwithoutTests をドロップ) を作成できます。ここでは、自分たちで作成します。
mkdir -p ./greeting-extension/deployment/src/test/java/org/acme/greeting/extension/deployment
エクステンションのテストを開始するには、次の org.acme.quarkus.greeting.deployment.GreetingTest テストクラスを作成します。
package org.acme.greeting.extension.deployment;
import io.quarkus.test.QuarkusUnitTest;
import io.restassured.RestAssured;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import static org.hamcrest.Matchers.containsString;
public class GreetingExtensionTest {
@RegisterExtension
static final QuarkusUnitTest config = new QuarkusUnitTest()
.withEmptyApplication(); (1)
@Test
public void testGreeting() {
RestAssured.when().get("/greeting").then().statusCode(200).body(containsString("Hello")); (2)
}
}
| 1 | Greeting エクステンションで Quarkus アプリを起動する Junit エクステンションを登録します。 |
| 2 | アプリケーションが greeting エンドポイントから OK ステータス (200) で HTTP GET 要求に応答していることと、 Hello を含むプレーンテキスト本文があることを確認します。 |
テストしてローカルの maven リポジトリーにインストールしてみましょう。
$ mvn clean install
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO]
[INFO] Greeting Extension - Parent [pom]
[INFO] Greeting Extension - Runtime [jar]
[INFO] Greeting Extension - Deployment [jar]
[INFO]
[INFO] -----------------< org.acme:greeting-extension-parent >-----------------
[INFO] Building Greeting Extension - Parent 1.0.0-SNAPSHOT [1/3]
[INFO] --------------------------------[ pom ]---------------------------------
...
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running org.acme.greeting.extension.deployment.GreetingExtensionTest
2021-01-27 10:24:42,506 INFO [io.quarkus] (main) Quarkus 3.20.6.2 on JVM started in 0.470s. Listening on: http://localhost:8081
2021-01-27 10:24:42,508 INFO [io.quarkus] (main) Profile test activated.
2021-01-27 10:24:42,508 INFO [io.quarkus] (main) Installed features: [cdi, greeting-extension, servlet]
2021-01-27 10:24:43,764 INFO [io.quarkus] (main) Quarkus stopped in 0.018s
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 4.799 s - in org.acme.greeting.extension.deployment.GreetingExtensionTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ greeting-extension-deployment ---
[INFO] Building jar: /Users/ia3andy/workspace/redhat/quarkus/demo/greeting-extension/deployment/target/greeting-extension-deployment-1.0.0-SNAPSHOT.jar
[INFO]
[INFO] --- maven-install-plugin:2.4:install (default-install) @ greeting-extension-deployment ---
...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary for Greeting Extension - Parent 1.0.0-SNAPSHOT:
[INFO]
[INFO] Greeting Extension - Parent ........................ SUCCESS [ 0.303 s]
[INFO] Greeting Extension - Runtime ....................... SUCCESS [ 3.345 s]
[INFO] Greeting Extension - Deployment .................... SUCCESS [ 7.365 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 11.246 s
[INFO] Finished at: 2021-01-27T10:24:44+01:00
[INFO] ------------------------------------------------------------------------
問題なさそうですね。初めてのエクステンションの作成、おつかれさまでした。
エクステンションのデバッグ
デバッグ作業がバグを取り除く作業であるならば、プログラミングとは、バグを入れ込む作業ということになる。エドガー・W・ダイクストラ
アプリケーションビルドのデバッグ
エクステンションのデプロイはアプリケーションのビルド中に行われるため、このプロセスはビルドツールによって起動されます。 つまり、このフェーズをデバッグしたい場合は、リモートデバッグモードをオンにしてビルドツールを起動する必要があります。
新しいエクステンションの使用
最初のエクステンションを構築し終えたばかりなので、Quarkus アプリケーションで使いたいと思うことでしょう。
クラッシックMaven publication
前のステップでまだ行っていない場合は、ローカルリポジトリに greeting-extension をインストールする必要があります。
cd ./greeting-extension
mvn clean install
次に、別のディレクトリから、我々のツールを使用して、新しいエクステンションを持つ新しい greeting-app Quarkus アプリケーションを作成します。
mvn io.quarkus.platform:quarkus-maven-plugin:3.20.6.2:create \
-DprojectGroupId=org.acme \
-DprojectArtifactId=greeting-app \
-Dextensions="org.acme:greeting-extension:1.0.0-SNAPSHOT" \
-DnoCode
cd into greeting-app.
The greeting-extension extension has to be installed in the local Maven repository to be usable in the application.
|
アプリケーションを実行して、 Installed Features のリストに quarkus-greeting のエクステンションが含まれていることに注目してください。
$ mvn quarkus:dev
[INFO] Scanning for projects...
[INFO]
[INFO] -----------------------< org.acme:greeting-app >------------------------
[INFO] Building greeting-app 1.0.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-compiler-plugin:3.14.0:compile (default-compile) @ greeting-app ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- quarkus-maven-plugin:3.20.6.2:dev (default-cli) @ greeting-app ---
Listening for transport dt_socket at address: 5005
__ ____ __ _____ ___ __ ____ ______
--/ __ \/ / / / _ | / _ \/ //_/ / / / __/
-/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/
2022-11-20 04:25:36,885 INFO [io.quarkus] (Quarkus Main Thread) greeting-app 1.0.0-SNAPSHOT on JVM (powered by Quarkus 3.20.6.2) started in 4.591s. Listening on: http://localhost:8080
2022-11-20 04:25:36,911 INFO [io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated.
2022-11-20 04:25:36,913 INFO [io.quarkus] (Quarkus Main Thread) Installed features: [cdi, greetin-extension, resteasy-reactive, smallrye-context-propagation, vertx]
エクステンションの開発者の立場からすると、Maven の公開戦略は非常に便利で高速ですが、Quarkus は、エクステンションを使用する人々のためにエコシステムの信頼性も確保することで、さらに一歩進んでいきたいと考えています。考えてみてください。私たちは皆、メンテナンスされていないライブラリや依存関係間の非互換性 (法的な問題は除く) で、開発体験が著しく低下したことを経験していることでしょう。Quarkus Platform は、そのためのものです。
Quarkus Platform
Quarkusプラットフォームは、開発フレームワークとしてのQuarkusの主なユースケースをターゲットとしたエクステンションのセットであり、依存関係の競合を発生させることなく、同じアプリケーション内でどのような組み合わせでも安全に使用できます。アプリケーション開発者の視点から見ると、Quarkusプラットフォームは、1つまたは複数のMaven BOMとして表現されます。例えば、 io.quarkus.platform:quarkus-bom:3.20.6.2 、 io.quarkus.platform:quarkus-camel-bom:3.20.6.2 などです。これらのBOMは、依存関係の競合を発生させることなく、同じアプリケーションで任意の順序でインポートできるように、依存関係のバージョン制約がグローバルに調整されています。
Quarkiverse Hub
Quarkiverse Hub は、コミュニティから投稿された Quarkus エクステンションプロジェクトのリポジトリーホスティング (ビルド、CI、リリースパブリッシングのセットアップを含む) を提供する GitHub 組織です。
新しいQuarkusエクステンションを作成してQuarkusエコシステムに追加し、Quarkus開発ツール( Quarkus CLI や code.quarkus.io を含む)を使用してQuarkusコミュニティがそのエクステンションを発見できるようにしたいと考えている場合、 Quarkiverse Hub GitHub organizationはそのための良いホームとなるでしょう。
エクステンションリクエスト 投稿を作成 (こちら) で、まだ投稿されていないかどうかを最初に確認してください) し、それをリードするように依頼することから始めることができます。
我々は、新しいリポジトリのプロビジョニングを行い、以下のように設定します。
-
我々のツールでサポート。
-
エクステンションのために作成したドキュメントを Quarkiverse の Web サイトに公開します。
-
Quarkus エコシステム CI を使用して、最新の Quarkus Core の変更に対応してビルドするようにエクステンションを設定します。
-
プロジェクトを管理し、好きなように Maven Central にリリースする自由を与えます。
| Extensions hosted in the Quarkiverse Hub may or may not end up in the Quarkus platform. |
詳しくは、Quarkiverse Wiki と このブログ記事 をチェックしてみてください。
まとめ
新しいエクステンションの作成は、最初は複雑な作業に見えるかもしれませんが、Quarkus の変革をもたらすパラダイム (ビルド時間とランタイム) を理解してしまえば、エクステンションの構造は完璧に理にかなったものになります。
いつものように、Quarkus は地道に、新機能の開発を快適にするために、Maven Mojo、バイトコード生成またはテストといった作業を簡素化するために努めています。
さらに詳しく
-
完全なドキュメント: 独自のエクステンションを書く
-
エクステンションでDev UIをサポートする方法を知る: Quarkus Dev UI