初めてのエクステンションの作成
Quarkus のエクステンションは、プロジェクトの依存関係がそうであるように、アプリケーションを強化します。エクステンションの役割は、Quarkus のパラダイムを活用して、ライブラリを Quarkus アーキテクチャにシームレスに統合することです。たとえば、ビルド時に、より多くのことを行います。これが、実績のあるエコシステムを利用して、Quarkus のパフォーマンスとネイティブコンパイルを活用することができる仕組みです。 code.quarkus.io にアクセスして、サポートされているエクステンションのリストを入手してください。
このガイドでは、サンプル Greeting エクステンション を開発します。このエクステンションは、ビジターに挨拶をするだけのカスタマイズ可能な HTTP エンドポイントを公開します。
免責事項
念のため、アプリケーションにサーブレットを追加するのにエクステンションは必要ないことを明記しておきます。このガイドは、エクステンション開発のコンセプトを説明するための簡略化された例であり、より詳細な情報が必要な場合は、 完全なドキュメントを参照してください。処理をビルド時に移動したり、ネイティブイメージのビルドを簡単にしたりする機能を代表するものではありませんのでご注意ください。
|
前提条件
このガイドを完成させるには、以下が必要です:
-
ざっと 30 minutes
-
IDE
-
JDK 11+ がインストールされ、
JAVA_HOME
が適切に設定されていること -
Apache Maven 3.9.3
-
使用したい場合は、 Quarkus CLI
基本概念
まず最初に、いくつかの基本的な概念から始めましょう。
-
JVM モードとネイティブモード
-
Quarkus は何よりもまずJava フレームワークです。つまり、従来の JAR アプリケーションの開発、パッケージ化、実行を行うことができます。これは、JVM モード と呼ばれます。
-
GraalVM により、Java アプリケーションをマシン固有のコード (Go や C++ のように) にコンパイルすることができます。これは、ネイティブモード と呼ばれます。
-
Java バイトコードをネイティブシステム固有のマシンコードにコンパイルする操作は、Ahead of Time Compilation (AoT) と呼ばれています。
-
従来型の Java フレームワークにおけるビルド時と実行時の比較
-
ビルド時は、Java ソースファイルを実行可能なもの (クラスファイル、jar/war、ネイティブイメージ) に変換するために Java ソースファイルに適用するすべてのアクションのことです。 通常、この段階はコンパイル、アノテーション処理、バイトコード生成などで構成されます。この時点では、すべてが開発者のスコープとコントロール下にあります。
-
実行時とは、アプリケーションを実行するときに発生するすべてのアクションのことです。 これは明らかにビジネス指向のアクションを開始することに焦点を当てていますが、ライブラリや設定ファイルのロード、アプリケーションのクラスパスのスキャン、依存性インジェクションの設定、オブジェクトリレーショナルマッピングの設定、REST コントローラのインスタンス化など、多くの技術的なアクションに依存しています。
-
通常、Javaフレームワークは、アプリケーションの "ビジネス志向のレイヤー" を実際に起動する前に、実行時中にブートストラップを行います。ブートストラップの際、フレームワークは、リフレクションによって適切なオブジェクトをインスタンス化するために、設定、エンティティー定義、依存関係の注入バインディングなどを見つけるためにクラスパスをスキャンします。これにより、動的にメタデータを収集します。主な結果は以下の通りです。
-
アプリケーションの準備が遅れる: 実際にビジネスリクエストに対応する前に数秒待つ必要があります。
-
ブートストラップでリソース消費のピークを持つ: 制約のある環境では、実際のビジネスニーズではなく、技術的なブートストラップのニーズに基づいて、必要なリソースのサイズを決定する必要があります。
Quarkus の哲学は、これらのアクションの前倒しを行い、最終的にはビルド時に実行することで、可能な限り低速でメモリー集約的な動的コードの実行を防ぐことにあります。Quarkus のエクステンションは、お気に入りのライブラリやテクノロジーのアダプターレイヤーとして機能する Java のコードです。
Quarkus のエクステンションの説明
Quarkus のエクステンションは、2 つの部分から構成されています。
-
実行時モジュール、エクステンション開発者がアプリケーション開発者に公開する機能を表します (認証フィルター、強化されたデータ層 API など)。実行時依存関係は、ユーザーがアプリケーションの依存関係として追加するものです (Maven POM または Gradle ビルドスクリプト)。
-
デプロイメントモジュール、ビルドの拡張フェーズで使用されます 。Quarkus の哲学に従ったライブラリを「デプロイ」する方法を説明しています。つまり、ビルド中にアプリケーションに Quarkus のすべての最適化を適用します。このデプロイメントモジュールは、GraalVM のネイティブコンパイルのための準備をする場所でもあります。
ユーザーは、エクステンションのデプロイメントモジュールをアプリケーションの依存関係として追加すべきではありません。デプロイメントの依存関係は、拡張フェーズの間に Quarkus によってアプリケーションの実行時依存関係から解決されます。 |
この時点で、このデプロイメントモジュールにより、多くのマジックは拡張ビルド時に起こることを理解しているはずです。
Quarkus アプリケーションブートストラップ
Quarkus アプリケーションには、3 つの異なるブートストラップフェーズがあります。
-
拡張 (Augmentation)。ビルド時に、Quarkus エクステンションはアプリケーションのバイトコード (依存関係を含む) と設定をロードしてスキャンします。 この段階で、エクステンションは設定ファイルを読み込んだり、特定のアノテーションのためにクラスをスキャンしたりすることができます。 すべてのメタデータが収集されたら、エクステンションは、ORM、DI、または REST コントローラーの設定のようなライブラリーのブートストラップアクションを前処理することができます。 ブートストラップの結果はバイトコードに直接記録され、最終的なアプリケーションパッケージの一部となります。
-
静的 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.4.1:create-extension -N
|
$ mvn io.quarkus.platform:quarkus-maven-plugin:3.4.1:create-extension -N \
-DgroupId=org.acme \ (1)
-DextensionId=greeting-extension \ (2)
-DwithoutTests (3)
[INFO] --- quarkus-maven-plugin:3.4.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 は、親 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.11.0</compiler-plugin.version>(2)
<failsafe-plugin.version>${surefire-plugin.version}</failsafe-plugin.version>
<maven.compiler.release>11</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<quarkus.version>3.4.1</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>
<compilerArgs>
<arg>-parameters</arg>(5)
</compilerArgs>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
1 | エクステンションは、2 つのサブモジュール deployment と runtime を宣言しています。 |
2 | Quarkus では、annotationProcessorPaths 設定に対応する、最新バージョンの Maven コンパイラープラグインのが必要です。 |
3 | quarkus-bom は、オーグメンテーションの段階で Quarkus が使用している依存関係を調整します。 |
4 | Quarkusは、テストを適切に実行するためにこれらの設定を必要とします。 |
5 | この方法で parameters フラグを設定すると、 MCOMPILER-413 を回避できます。 |
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 はエクステンションによって提供される機能を表します。機能の名前は、アプリケーションの起動時にログに表示されます。エクステンションは最大でも 1 つの機能を提供しなければなりません。
|
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'
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 マジックは、実行時のコード評価を待つのではなく、ビルド時のバイトコード生成に依存します。これは、エクステンションの 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>
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 は、流暢な 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.4.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・ダイクストラ
アプリケーションビルドのデバッグ
エクステンションのデプロイはアプリケーションのビルド中に行われるため、このプロセスはビルドツールによってトリガーされます。つまり、このフェーズをデバッグしたい場合は、リモートデバッグモードを 1 に切り替えてビルドツールを起動する必要があります。
新しいエクステンションの使用
最初のエクステンションを構築し終えたばかりなので、Quarkus アプリケーションで使いたいと思うことでしょう。
お約束の Maven キャッチ
前のステップでまだ行っていない場合は、ローカルリポジトリに greeting-extension
をインストールする必要があります。
cd ./greeting-extension
mvn clean install
次に、別のディレクトリから、我々のツールを使用して、新しいエクステンションを持つ新しい greeting-app
Quarkus アプリケーションを作成します。
mvn io.quarkus.platform:quarkus-maven-plugin:3.4.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 clean compile 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-clean-plugin:2.5:clean (default-clean) @ greeting-app ---
[INFO]
[INFO] --- quarkus-maven-plugin:3.4.1:generate-code (default) @ greeting-app ---
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ greeting-app ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.11.0:compile (default-compile) @ greeting-app ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- quarkus-maven-plugin:3.4.1:dev (default-cli) @ greeting-app ---
Listening for transport dt_socket at address: 5005
__ ____ __ _____ ___ __ ____ ______
--/ __ \/ / / / _ | / _ \/ //_/ / / / __/
-/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/
2021-01-27 10:28:07,240 INFO [io.quarkus] (Quarkus Main Thread) greeting-app 1.0.0-SNAPSHOT on JVM (powered by Quarkus 3.4.1) started in 0.531s. Listening on: http://localhost:8080
2021-01-27 10:28:07,242 INFO [io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated.
2021-01-27 10:28:07,243 INFO [io.quarkus] (Quarkus Main Thread) Installed features: [cdi, greeting-extension, servlet]
エクステンションの開発者の立場からすると、Maven の公開戦略は非常に便利で高速ですが、Quarkus は、エクステンションを使用する人々のためにエコシステムの信頼性も確保することで、さらに一歩進んでいきたいと考えています。考えてみてください。私たちは皆、メンテナンスされていないライブラリや依存関係間の非互換性 (法的な問題は除く) で、開発体験が著しく低下したことを経験していることでしょう。Quarkus Platform は、そのためのものです。
Quarkus Platform
Quarkusプラットフォームは、開発フレームワークとしてのQuarkusの主なユースケースをターゲットとしたエクステンションのセットであり、依存関係の競合を発生させることなく、同じアプリケーション内でどのような組み合わせでも安全に使用できます。アプリケーション開発者の視点から見ると、Quarkusプラットフォームは、1つまたは複数のMaven BOMとして表現されます。例えば、 io.quarkus.platform:quarkus-bom:3.4.1
、 io.quarkus.platform:quarkus-camel-bom:3.4.1
などです。これらのBOMは、依存関係の競合を発生させることなく、同じアプリケーションで任意の順序でインポートできるように、依存関係のバージョン制約がグローバルに調整されています。
Quarkiverse Hub
Quarkiverse Hub は、コミュニティから投稿された Quarkus エクステンションプロジェクトのリポジトリーホスティング (ビルド、CI、リリースパブリッシングのセットアップを含む) を提供する GitHub 組織です。
In case you are wondering about creating a new Quarkus extension and adding it to the Quarkus ecosystem so that the Quarkus community can discover it using the Quarkus dev tools (including the Quarkus CLI and code.quarkus.io), the Quarkiverse Hub GitHub organization will be a good home for it.
エクステンションリクエスト 投稿を作成 (こちら) で、まだ投稿されていないかどうかを最初に確認してください) し、それをリードするように依頼することから始めることができます。
我々は、新しいリポジトリのプロビジョニングを行い、以下のように設定します。
-
我々のツールでサポート。
-
エクステンションのために作成したドキュメントを Quarkiverse の Web サイトに公開します。
-
Quarkus エコシステム CI を使用して、最新の Quarkus Core の変更に対応してビルドするようにエクステンションを設定します。
-
プロジェクトを管理し、好きなように Maven Central にリリースする自由を与えます。
Quarkiverse Hubでホストされているエクステンションは、Quarkusプラットフォームに組み込まれる場合もあれば、組み込まれない場合もあります。 |
詳しくは、Quarkiverse Wiki と このブログ記事を チェックしてみてください。
まとめ
新しいエクステンションの作成は、最初は複雑な作業に見えるかもしれませんが、Quarkus の変革をもたらすパラダイム (ビルド時と実行時) を理解してしまえば、エクステンションの構造は完璧に理にかなったものになります。
いつものように、Quarkus は地道に、新機能の開発を快適にするために、Maven Mojo、バイトコード生成またはテストといった作業を簡素化するために努めています。
参考
-
完全なドキュメント: 独自のエクステンションを書く
-
エクステンションでDev UIをサポートする方法を Quarkus Dev UI で学ぶ