初めてのエクステンションの作成
Quarkus のエクステンションは、プロジェクトの依存関係がそうであるように、アプリケーションを強化します。エクステンションの役割は、Quarkus のパラダイムを活用して、ライブラリを Quarkus アーキテクチャにシームレスに統合することです。たとえば、ビルド時に、より多くのことを行います。これが、実績のあるエコシステムを利用して、Quarkus のパフォーマンスとネイティブコンパイルを活用することができる仕組みです。 code.quarkus.io にアクセスして、サポートされているエクステンションのリストを入手してください。
In this guide, we are going to develop the Sample Greeting Extension. The extension will expose a customizable HTTP endpoint that simply greets the visitor.
|
免責事項
To be sure it’s extra clear that 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.12
-
使用したい場合は、 Quarkus CLI
|
Writing extension with any other than Java and Maven has not been tested by the Quarkus team, so your mileage may vary if you stray off this path |
基本概念
まず最初に、いくつかの基本的な概念から始めましょう。
-
JVM モードとネイティブモード
-
Quarkus is first and foremost a Java framework, that means you can develop, package, and run classic JAR applications, that’s what we call JVM mode.
-
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 ビルドスクリプト)。
-
The deployment module, which is used during the augmentation phase of the build, describes how to "deploy" a library following the Quarkus philosophy. In other words, it applies all the Quarkus optimizations to your application during the build. The deployment module is also where we prepare things for GraalVM’s native compilation.
| ユーザーは、エクステンションのデプロイメントモジュールをアプリケーションの依存関係として追加すべきではありません。デプロイメントの依存関係は、拡張フェーズの間に Quarkus によってアプリケーションの実行時依存関係から解決されます。 |
At this point, you should have understood that most of the magic will happen at the Augmentation build time, thanks to the deployment module.
Quarkus アプリケーションブートストラップ
Quarkus アプリケーションには、3 つの異なるブートストラップフェーズがあります。
-
Augmentation. During the build time, the Quarkus extensions will load and scan your application’s bytecode (including the dependencies) and configuration. At this stage, the extension can read configuration files, scan classes for specific annotations, etc. Once all the metadata has been collected, the extensions can pre-process the libraries bootstrap actions like your ORM, DI, or REST controllers configurations. The result of the bootstrap is directly recorded into bytecode and will be part of your final application package.
-
静的 Init 実行時に、Quarkus は最初に、いくつかの拡張アクション/設定を含む最初の静的 init メソッドを実行します。 ネイティブパッケージングを行う場合、このスタティックメソッドはビルド時に前処理され、生成されたオブジェクトは最終的なネイティブ実行可能ファイルにシリアライズされるため、初期化コードはネイティブモードでは実行されません (このフェーズではフィボナッチ関数を実行すると想像してください。計算の結果は、ネイティブ実行可能ファイルに直接記録されます)。 JVM モードでアプリケーションを実行している場合、この静的 init フェーズはアプリケーションの開始時に実行されます。
-
ランタイム Init このフェーズでは特に目立つことはありません。従来的なランタイムコード実行を行います。 つまり、上記の 2 つのフェーズでより多くのコードを実行すればするほど、アプリケーションの起動が速くなります。
これで全てが説明されたので、さっそくコーディングに取り掛かりましょう
プロジェクトのセットアップ
エクステンションは、MavenまたはGradleのいずれかでビルドできます。お使いのビルドツールに応じて、以下のようにセットアップを行います。
| Gradleエクステンションプラグインはまだ実験的なもので、Mavenプラグインで利用できる機能が欠けている可能性があります。 |
Maven のセットアップ
Quarkus は、 create-extension Maven Mojo を提供し、エクステンションプロジェクトを初期化します。
オプションの自動検出が試行されます。
-
quarkus(Quarkus Core) またはquarkus/extensionsディレクトリからアクセスすると、'Quarkus Core' エクステンションのレイアウトとデフォルトが使用されます。 -
-DgroupId=io.quarkiverse.[extensionId]を使用すると、'Quarkiverse' エクステンションのレイアウトとデフォルトを使用します。 -
それ以外の場合は 'Standalone' エクステンションのレイアウトとデフォルトを使用します。
-
将来的には他のレイアウトタイプを導入する可能性があります。
パラメーターなしで呼び出し、インタラクティブ・モードを使用することも出来ます: mvn io.quarkus.platform:quarkus-maven-plugin:3.32.1:create-extension -N
|
$ mvn io.quarkus.platform:quarkus-maven-plugin:3.32.1:create-extension -N \
-DgroupId=org.acme \ (1)
-DextensionId=greeting-extension \ (2)
-DwithoutTests (3)
[INFO] --- quarkus-maven-plugin:3.32.1: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 has generated a greeting-extension directory containing the extension project, which consists of the parent pom.xml, the runtime, and the deployment modules.
親 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.15.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.32.1</quarkus.version>
<surefire-plugin.version>3.5.4</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-junit-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 はエクステンションによって提供される機能を表します。機能の名前は、アプリケーションの起動時にログに表示されます。エクステンションは最大でも 1 つの機能を提供しなければなりません。
|
Be patient, we will explain the Build Step Processor concept and all the extension deployment API later on.
At this point, you just need to understand that this class explains to Quarkus how to deploy a feature named greeting, which is your extension.
In other words, you are augmenting your application to use the greeting extension with all the Quarkus benefits (build time optimization, native support, etc.).
実行時モジュール
最後に ./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 | We add the quarkus-extension-maven-plugin to generate the Quarkus extension descriptor included into the runtime artifact, which links it with the corresponding deployment artifact. |
| 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-junit-internal'
}
| 1 | 決まりとして、配置モジュールのサフィックスは -deployment (greeting-deployment) です。 |
| 2 | デプロイメントモジュールは実行時モジュールに依存してい なければなりません 。 |
実行時モジュール
実行時モジュールは quarkus-arc アーティファクトに依存しています。
-
Add
quarkus-extension-processas an annotation processor to both modules. -
エクステンションの説明ファイルを生成します。
以下は、 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 を作成しましょう。
To use Servlets in your applications, you need to have a Servlet Container such as Undertow.
Luckily, quarkus-bom imported by our parent pom.xml already includes the Undertow Quarkus extension.
All we need to do is add quarkus-undertow as a dependency to our ./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'
create-extension mojo で生成された quarkus-core-deployment への依存関係は、 quarkus-undertow-deployment が既に依存しているため削除できます。
|
これで、 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 magic relies on bytecode generation at build time rather than waiting for the runtime code evaluation, that’s the role of your extension’s deployment module.
Calm down, we know, bytecode is hard, and you don’t want to do it manually. Quarkus proposes a high level API to make your life easier.
Thanks to basic concepts, you will describe the items to produce/consume and the corresponding steps in order to generate the bytecode to produce during the deployment time.
io.quarkus.builder.item.BuildItem の概念は、 @io.quarkus.deployment.annotations.BuildStep でアノテーションされたメソッドのおかげで、生成または消費 (そしてある時点でバイトコードに変換したり) するオブジェクトインスタンスを表しています。このアノテーションは、エクステンションのデプロイメントタスクを説明しています。
| See the complete list of BuildItem implementations in core for more information. |
生成された 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>
create-extension mojo で生成された quarkus-core-deployment への依存は、 quarkus-undertow-deployment が既に依存しているので、これで削除できます。
|
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 proposes a fluent API to instantiate a Servlet named greeting-extension of type GreetingExtensionServlet (it’s our class provided by our extension runtime module), and map it to the /greeting path. |
グリーティングエクステンションのテスト
When developing a Quarkus extension, you mainly want to test that your feature is properly deployed in an application and works as expected.
That’s why the tests will be hosted in the deployment module.
Quarkus proposes facilities to test extensions via the quarkus-junit-internal artifact (which should already be in the deployment pom.xml), in particular the io.quarkus.test.QuarkusUnitTest runner, which starts an application with your extension.
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.32.1 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・ダイクストラ
アプリケーションビルドのデバッグ
エクステンションのデプロイはアプリケーションのビルド中に行われるため、このプロセスはビルドツールによって起動されます。 つまり、このフェーズをデバッグしたい場合は、リモートデバッグモードをオンにしてビルドツールを起動する必要があります。
新しいエクステンションの使用
Now that you just finished building your first extension, you should be eager to use it in a Quarkus application!
クラッシックMaven publication
前のステップでまだ行っていない場合は、ローカルリポジトリに greeting-extension をインストールする必要があります。
cd ./greeting-extension
mvn clean install
次に、別のディレクトリから、我々のツールを使用して、新しいエクステンションを持つ新しい greeting-app Quarkus アプリケーションを作成します。
mvn io.quarkus.platform:quarkus-maven-plugin:3.32.1:create \
-DprojectGroupId=org.acme \
-DprojectArtifactId=greeting-app \
-Dextensions="org.acme:greeting-extension:1.0.0-SNAPSHOT" \
-DnoCode
cd into greeting-app.
quarkus-greeting エクステンションをアプリケーションで使用できるようにするには、ローカルの Maven リポジトリにインストールする必要があります。
|
アプリケーションを実行して、 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.15.0:compile (default-compile) @ greeting-app ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- quarkus-maven-plugin:3.32.1: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.32.1) 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]
From an extension developer standpoint, the Maven publication strategy is very handy and fast, but Quarkus wants to go one step further by also ensuring a reliability of the ecosystem for the people who will use the extensions. Think about it, we all had a poor Developer Experience with an unmaintained library, an incompatibility between dependencies (and we don’t even talk about legal issues). That’s why there is the Quarkus Platform.
Quarkus Platform
Quarkusプラットフォームは、開発フレームワークとしてのQuarkusの主なユースケースをターゲットとしたエクステンションのセットであり、依存関係の競合を発生させることなく、同じアプリケーション内でどのような組み合わせでも安全に使用できます。アプリケーション開発者の視点から見ると、Quarkusプラットフォームは、1つまたは複数のMaven BOMとして表現されます。例えば、 io.quarkus.platform:quarkus-bom:3.32.1 、 io.quarkus.platform:quarkus-camel-bom:3.32.1 などです。これらの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 にリリースする自由を与えます。
| Quarkiverse Hubでホストされているエクステンションは、Quarkusプラットフォームに組み込まれる場合もあれば、組み込まれない場合もあります。 |
詳しくは、Quarkiverse Wiki と このブログ記事 をチェックしてみてください。
まとめ
Creating new extensions may appear to be an intricate task at first, but once you understand the Quarkus game-changer paradigm (build time vs runtime) the structure of an extension makes perfectly sense.
As usual, along the path, Quarkus simplifies things under the hood (Maven Mojo, bytecode generation, or testing) to make it pleasant to develop new features.
参考
-
完全なドキュメント: 独自のエクステンションを書く
-
エクステンションでDev UIをサポートする方法を知る: Quarkus Dev UI