1. 概要

Quarkusは、コアと一連の拡張機能で構成されるフレームワークです。 コアはContextandDependency Injection(CDI)に基づいており、拡張機能は通常、主要コンポーネントをCDI Beanとして公開することにより、サードパーティのフレームワークを統合することを目的としています。

このチュートリアルでは、 Quarkus の基本的な理解を前提として、Quarkus拡張機能を作成する方法に焦点を当てます。

2. Quakus拡張機能とは

Quarkus拡張機能は、Quarkusアプリケーション上で実行できる単なるモジュールです。 Quarkusアプリケーション自体は、他の一連の拡張機能を備えたコアモジュールです。

このような拡張機能の最も一般的な使用例は、Quarkusアプリケーション上でサードパーティのフレームワークを実行することです。

3. プレーンJavaアプリケーションでのLiquibaseの実行

データベース変更管理用のツールであるLiquibase、を統合するための拡張機能を実装してみましょう。

しかし、飛び込む前に、まずJavamainメソッドからLiquibase移行を実行する方法を示す必要があります。 これにより、拡張機能の実装が大幅に容易になります。

LiquibaseフレームワークのエントリポイントはLiquibaseAPIです。 これを使用するには、変更ログファイル、このファイルにアクセスするための ClassLoader 、および基になるデータベースへのConnectionが必要です。

Connection c = DriverManager.getConnection("jdbc:h2:mem:testdb", "user", "password");
ResourceAccessor resourceAccessor = new ClassLoaderResourceAccessor();
String changLogFile = "db/liquibase-changelog-master.xml";
Liquibase liquibase = new Liquibase(changLogFile, resourceAccessor, new JdbcConnection(c));

このインスタンスがある場合、変更ログファイルと一致するようにデータベースを更新する update()メソッドを呼び出すだけです。

liquibase.update(new Contexts());

目標は、LiquibaseをQuarkus拡張機能として公開することです。 つまり、Quarkus Configurationを介してデータベース構成と変更ログファイルを提供し、LiquibaseAPIをCDIBeanとして生成します。 これは、後で実行するために移行呼び出しを記録する手段を提供します。

4. Quarkus拡張機能の書き方

技術的に言えば、Quarkus拡張機能は、2つのモジュールで構成されるMavenマルチモジュールプロジェクトです。 1つ目は、要件を実装するランタイムモジュールです。 2つ目は、構成を処理してランタイムコードを生成するためのデプロイメントモジュールです。

それでは、2つのサブモジュールruntimedeploymentを含むquarkus-liquibase-parentというMavenマルチモジュールプロジェクトを作成することから始めましょう。

<modules>
    <module>runtime</module>
    <module>deployment</module>
</modules>

5. ランタイムモジュールの実装

ランタイムモジュールでは、以下を実装します。

  • Liquibase変更ログファイルをキャプチャするための設定クラス
  • LiquibaseAPIを公開するためのCDIプロデューサー
  • 呼び出し呼び出しを記録するためのプロキシとして機能するレコーダー

5.1. Mavenの依存関係とプラグイン

ランタイムモジュールは、 quarkus-core モジュールに依存し、最終的には必要な拡張機能のランタイムモジュールに依存します。 ここでは、拡張機能にデータソースが必要なためquarkus-agroal依存関係が必要です。ここにもLiquibaseライブラリが含まれます。

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-core</artifactId>
    <version>${quarkus.version}</version>
</dependency>
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-agroal</artifactId>
    <version>${quarkus.version}</version>
</dependency>
<dependency>
    <groupId>org.liquibase</groupId>
    <artifactId>liquibase-core</artifactId>
    <version>3.8.1</version>
</dependency>

また、quarkus-bootstrap-maven-pluginを追加する必要がある場合もあります。 このプラグインは、 extension-descriptor ゴールを呼び出すことにより、Quarkus拡張記述子を自動的に生成します。

または、このプラグインを省略して、記述子を手動で生成することもできます。

いずれにせよ、拡張記述子は META-INF /quarkus-extension.propertiesの下にあります。

deployment-artifact=com.baeldung.quarkus.liquibase\:deployment\:1.0-SNAPSHOT

5.2. 構成の公開

変更ログファイルを提供するには、構成クラスを実装する必要があります。

@ConfigRoot(name = "liquibase", phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED)
public final class LiquibaseConfig {
    @ConfigItem
    public String changeLog;
}

クラスに@ConfigRootで注釈を付け、プロパティに @ConfigItem。で注釈を付けます。したがって、変更ログのキャメルケース形式であるchangeLogフィールドに注釈を付けます。 Quarkusアプリケーションのクラスパスにあるapplication.propertiesファイルのquarkus.liquibase.change-logキーを介して提供されます。

quarkus.liquibase.change-log=db/liquibase-changelog-master.xml

change-logキーをいつ解決するかを指示するConfigRoot.phase値にも注意してください。 この場合、 BUILD_AND_RUN_TIME_FIXED、キーは展開時に読み取られ、実行時にアプリケーションで使用できます。

5.3. LiquibaseAPIをCDIBeanとして公開する

mainメソッドからLiquibase移行を実行する方法を上で見てきました。

ここで、同じコードをCDI Beanとして再現し、その目的でCDIプロデューサーを使用します。

@Produces
public Liquibase produceLiquibase() throws Exception {
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    ResourceAccessor resourceAccessor = new ClassLoaderResourceAccessor(classLoader);
    DatabaseConnection jdbcConnection = new JdbcConnection(dataSource.getConnection());
    Liquibase liquibase = new Liquibase(liquibaseConfig.changeLog, resourceAccessor, jdbcConnection);
    return liquibase;
}

5.4. バイトコードの記録

このステップでは、バイトコードを記録してランタイムロジックを設定するためのプロキシとして機能するレコーダークラスを記述します。

@Recorder
public class LiquibaseRecorder {

    public BeanContainerListener setLiquibaseConfig(LiquibaseConfig liquibaseConfig) {
        return beanContainer -> {
            LiquibaseProducer producer = beanContainer.instance(LiquibaseProducer.class);
            producer.setLiquibaseConfig(liquibaseConfig);
        };
    }

    public void migrate(BeanContainer container) throws LiquibaseException {
        Liquibase liquibase = container.instance(Liquibase.class);
        liquibase.update(new Contexts());
    }

}

ここでは、2つの呼び出しを記録する必要があります。 setLiquibaseConfig は構成を設定し、migrateは移行を実行します。 次に、これらのレコーダーメソッドが、デプロイメントモジュールに実装するデプロイメントビルドステッププロセッサによってどのように呼び出されるかを見ていきます。

ビルド時にこれらのレコーダーメソッドを呼び出すと、命令は実行されませんが、起動時に後で実行するために記録されることに注意してください。

6. デプロイメントモジュールの実装

Quarkus拡張機能の中心的なコンポーネントは、ビルドステッププロセッサです。 これらは、レコーダーを介してバイトコードを生成する @BuildStep と注釈が付けられたメソッドであり、Quarkusアプリケーションで構成されたquarkus-maven-pluginのビルド目標を通じてビルド時間中に実行されます。

@BuildStep は、BuildItemのおかげで注文されました。 それらは、初期のビルドステップによって生成されたビルドアイテムを消費し、後のビルドステップ用のビルドアイテムを生成します。

アプリケーションデプロイメントモジュールにあるすべての順序付けられたビルドステップによって生成されたコードは、実際にはランタイムコードです。

6.1. Mavenの依存関係

デプロイメントモジュールは、対応するランタイムモジュールに依存し、最終的には必要な拡張機能のデプロイメントモジュールに依存する必要があります。

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-core-deployment</artifactId>
    <version>${quarkus.version}</version>
</dependency>
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-arc-deployment</artifactId>
    <version>${quarkus.version}</version>
</dependency>
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-agroal-deployment</artifactId>
    <version>${quarkus.version}</version>
</dependency>

<dependency>
    <groupId>com.baeldung.quarkus.liquibase</groupId>
    <artifactId>runtime</artifactId>
    <version>${project.version}</version>
</dependency>

Quarkus拡張機能の最新の安定バージョンは、ランタイムモジュールでも同じです。

6.2. ビルドステッププロセッサの実装

それでは、バイトコードを記録するための2つのビルドステッププロセッサを実装しましょう。 最初のビルドステッププロセッサはbuild()メソッドで、静的initメソッドで実行するためにバイトコードを記録します。 これは、STATIC_INIT値を使用して構成します。

@Record(ExecutionTime.STATIC_INIT)
@BuildStep
void build(BuildProducer<AdditionalBeanBuildItem> additionalBeanProducer,
  BuildProducer<FeatureBuildItem> featureProducer,
  LiquibaseRecorder recorder,
  BuildProducer<BeanContainerListenerBuildItem> containerListenerProducer,
  DataSourceInitializedBuildItem dataSourceInitializedBuildItem) {

    featureProducer.produce(new FeatureBuildItem("liquibase"));

    AdditionalBeanBuildItem beanBuilItem = AdditionalBeanBuildItem.unremovableOf(LiquibaseProducer.class);
    additionalBeanProducer.produce(beanBuilItem);

    containerListenerProducer.produce(
      new BeanContainerListenerBuildItem(recorder.setLiquibaseConfig(liquibaseConfig)));
}

まず、 FeatureBuildItem を作成して、拡張機能のタイプまたは名前をマークします。 次に、 AdditionalBeanBuildItem を作成して、 LiquibaseProducerbeanがQuarkusコンテナで使用できるようにします。

最後に、Quarkus BeanContainerの起動後にBeanContainerListenerを起動するために、BeanContainerListenerBuildItemを作成します。 ここで、リスナーで、設定をLiquibaseBeanに渡します。

次に、 processMigration()、は、記録用の RUNTIME_INIT パラメーターを使用して構成されているため、mainメソッドで実行するための呼び出しを記録します。

@Record(ExecutionTime.RUNTIME_INIT)
@BuildStep
void processMigration(LiquibaseRecorder recorder, 
  BeanContainerBuildItem beanContainer) throws LiquibaseException {
    recorder.migrate(beanContainer.getValue());
}

ここで、このプロセッサでは、 migrate()レコーダメソッドを呼び出しました。このメソッドは、後で実行するために update()Liquibaseメソッドを記録します。

7. Liquibase拡張機能のテスト

拡張機能をテストするには、まずquarkus-maven-pluginを使用してQuarkusアプリケーションを作成します。

mvn io.quarkus:quarkus-maven-plugin:1.0.0.CR1:create\
-DprojectGroupId=com.baeldung.quarkus.app\
-DprojectArtifactId=quarkus-app

次に、基盤となるデータベースに対応する Quarkus JDBC拡張機能に加えて、依存関係として拡張機能を追加します。

<dependency>
    <groupId>com.baeldung.quarkus.liquibase</groupId>
    <artifactId>runtime</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-jdbc-h2</artifactId>
    <version>1.0.0.CR1</version>
</dependency>

次に、pomファイルにquarkus-maven-pluginを含める必要があります。

<plugin>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-maven-plugin</artifactId>
    <version>${quarkus.version}</version>
    <executions>
        <execution>
            <goals>
                <goal>build</goal>
            </goals>
        </execution>
    </executions>
</plugin>

これは、 dev ゴールを使用してアプリケーションを実行したり、buildゴールを使用して実行可能ファイルをビルドしたりする場合に特に便利です。

次に、 src / main /resourcesにあるapplication.propertiesファイルを介してデータソース構成を提供します。

quarkus.datasource.url=jdbc:h2:mem:testdb
quarkus.datasource.driver=org.h2.Driver
quarkus.datasource.username=user
quarkus.datasource.password=password

次に、変更ログファイルの変更ログ構成を提供します。

quarkus.liquibase.change-log=db/liquibase-changelog-master.xml

最後に、開発モードでアプリケーションを起動できます。

mvn compile quarkus:dev

または本番モードの場合:

mvn clean package
java -jar target/quarkus-app-1.0-SNAPSHOT-runner.jar

8. 結論

この記事では、Quarkus拡張機能を実装しました。 例として、Quarkusアプリケーション上でLiquibaseを実行する方法を紹介しました。

完全なコードソースは、GitHubから入手できます。