Helidon with Micronaut Data Repositories

原文はこちら。
The original articles were written by Tomáš Langer (Consulting Member of Technical Staff at Oracle).
https://medium.com/helidon/helidon-with-micronaut-data-repositories-daf6ddefee0b

これまで、HelidonはJakarta EEやMicroProfile仕様をHelidon MPでフォローしてきており、データベースアクセスの主要な選択肢としてJPAを使ってきました。それにもかかわらず、Micronautのリポジトリなど、データベースへのアクセスには他のアプローチがあることを理解しています。

Jakarta EE
https://jakarta.ee/
MicroProfile
https://microprofile.io/
Helidon MP
https://helidon.io/docs/v2/#/mp/introduction/01_introduction
Micronaut
https://micronaut.io/

We recognize the advantages of using Micronautのリポジトリの利用の利点やユーザーにとってのメリットを理解しています。そのため、Helidon 2.2.0からこのアプローチをサポートします。

TL;DR:

  • helidon-integrations-micronaut-cdi を使い、HelidonのCDI環境でMicronaut beanを利用できる
  • helidon-integrations-micronatu-data により、JDBC Connectionのインジェクションをサポート
  • 統合は一方向。つまり、Micronaut beanをCDIにインジェクトできるが、CDI beanをMicronaut beanにインジェクトはできない。
  • Micronaut beanのアノテーションプロセッサはランタイムが拾い上げるために引き続き利用する必要がある
  • Micronaut dataとMicronautのbean validation実装のサポートを検証済み

この記事では、Mavenをビルドツールとして利用しており、全ての構成はMavenを中心に実施しています。同じことはGradleでも可能のはずですが、これは皆さんのために残しておきます。

Helidon MPを使ってデータベースアクセスする簡単なマイクロサービスを作成するために、少なくとも以下の構成が必要です。

Helidon Parent

アプリケーションの親POMで依存関係の管理とプラグインの管理を定義し、新規プロジェクトのセットアップを簡単にします(ご自身の親モジュールを利用することも可能ですが、多くの構成が必要で、この記事の範囲ではありません)。Maven archetype、またはHelidon CLI (Command Line Interface)を使用するのが最も簡単です。

MP — Helidon MP Quickstart
https://helidon.io/docs/v2/#/mp/guides/02_quickstart
Helidon CLI
https://helidon.io/docs/v2/#/about/05_cli

<parent>
    <groupId>io.helidon.applications</groupId>
    <artifactId>helidon-mp</artifactId>
    <version>2.2.0</version>
</parent>

Helidon and Jakarta Modules

MicroProfileバンドルにより、CDIとあらゆる必要なMicroProfile仕様が追加されます。2番目のライブラリは、CDIでMicronautをサポートするための統合レイヤーです。Persistent APIを使ってエンティティを就職します(これはMicronaut dataが提供します)。

<dependency>
    <groupId>io.helidon.microprofile.bundles</groupId>
    <artifactId>helidon-microprofile</artifactId>
</dependency>
<dependency>
    <groupId>io.helidon.integrations.micronaut</groupId>
    <artifactId>helidon-integrations-micronaut-data</artifactId>
</dependency>
<dependency>
    <groupId>jakarta.persistence</groupId>
    <artifactId>jakarta.persistence-api</artifactId>
    <scope>provided</scope>
</dependency>

Database Drivers

この記事ではインメモリデータベースyのh2を使いますが、サポートされる任意のライブラリを利用できます。

H2 Database Engine
https://www.h2database.com/html/main.html

<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>runtime</scope>
</dependency>

Micronaut Modules

We will use Micronaut Dataを使ってリポジトリとランタイムを作成し、データベースにデータを入れるためのスタートアップリスナーを構成します。Hikari datasourceは接続プールとして利用できるものの一つです。

<dependency>
    <groupId>io.micronaut.data</groupId>
    <artifactId>micronaut-data-jdbc</artifactId>
</dependency>
<dependency>
    <groupId>io.micronaut</groupId>
    <artifactId>micronaut-runtime</artifactId>
</dependency>
<dependency>
    <groupId>io.micronaut.data</groupId>
    <artifactId>micronaut-data-tx</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>io.micronaut.sql</groupId>
    <artifactId>micronaut-jdbc-hikari</artifactId>
    <scope>runtime</scope>
</dependency>

次のステップはMicronaut固有のものです。Micronautはbeanの分析とメタデータの準備のためにビルドタイムアプローチを使います。そのため、一連のアノテーションプロセッサーを構成して、ランタイム用に必要なクラスを生成します。

build/pluginsセクションでMaven compiler plugin を以下のように構成します(プロパティは親であるHelidonから継承しています)。

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
        <forceJavacCompilerUse>true</forceJavacCompilerUse>
        <annotationProcessorPaths>
            <path>
                <groupId>io.micronaut</groupId>
                <artifactId>micronaut-inject-java</artifactId>
                <version>${version.lib.micronaut}</version>
            </path>
            <path>
                <groupId>io.micronaut</groupId>
                <artifactId>micronaut-validation</artifactId>
                <version>${version.lib.micronaut}</version>
            </path>
            <path>
                <groupId>io.micronaut.data</groupId>
                <artifactId>micronaut-data-processor</artifactId>
                <version>${version.lib.micronaut.data}</version>
            </path>
            <path>
                <groupId>io.helidon.integrations.micronaut</groupId>
                <artifactId>helidon-integrations-micronaut-cdi-processor</artifactId>
                <version>${helidon.version}</version>
            </path>
        </annotationProcessorPaths>
    </configuration>
</plugin>

これで全ての必要なライブラリを含む設定ができあがりましたので、マイクロサービスを作成できます。

では構成から取りかかりましょう。src/main/resources/META-INFにある以下のファイルが必要です。

  • beans.xml : CDIのbeanアーカイブとしてモジュールを定義する
  • microprofile-config.properties : サービスの構成

データベースとサーバーを構成するため、構成ファイルをアップデートしましょう。ご覧の通り、HelidonとMicronaut dataを同じ構成ファイルを使って構成できます。この記事ではインメモリデータベースを使って必要な設定を簡略化しています。

server.port=8080datasources.default.url=jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
datasources.default.driverClassName=org.h2.Driver
datasources.default.username=sa
datasources.default.password=
datasources.default.schema-generate=CREATE_DROP
datasources.default.dialect=h2

では簡単なエンティティを作成しましょう(エンティティに関する詳細情報はMicronaut Dataのドキュメントをご覧ください)。

Micronaut Data
https://micronaut-projects.github.io/micronaut-data/latest/guide/

この例は簡単なOwner表で、Jakarta Persistence APIとMicronautアノテーションを使ってコンストラクタをマークしています。

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

import io.micronaut.core.annotation.Creator;@Entity
public class Owner {

    @Id
    @GeneratedValue
    private Long id;
    private String name;
    private int age;
@Creator
    public Owner(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
}

データベース操作でこのエンティティを使うため、リポジトリを作成する必要があります。以下のリポジトリは、次のSQLに相当するものです。

SELECT * FROM OWNER 
SELECT * FROM OWNER WHERE NAME = ?

import io.micronaut.data.jdbc.annotation.JdbcRepository;
import io.micronaut.data.model.query.builder.sql.Dialect;
import io.micronaut.data.repository.CrudRepository;

@JdbcRepository(dialect = Dialect.H2)
public interface DbOwnerRepository extends CrudRepository<Owner, Long> {
    /**
     * Get all owners from the database.
     *
     * @return all owners
     */
    @Override
    List<Owner> findAll();

    /**
     * Find an owner by name.
     *
     * @param name name of owner
     * @return owner if found
     */
    Optional<Owner> findByName(String name);
}

最後にMicronaut固有のステップですが、スタートアップ・イベント・リスナーを使ってデータベースをデータで初期化します。

import java.util.Arrays;

import javax.inject.Inject;
import javax.inject.Singleton;

import io.micronaut.context.event.StartupEvent;
import io.micronaut.core.annotation.TypeHint;
import io.micronaut.runtime.event.annotation.EventListener;

@Singleton
@TypeHint(typeNames = {"org.h2.Driver", "org.h2.mvstore.db.MVTableEngine"})
public class DbPopulateData {
    private final DbOwnerRepository ownerRepository;    @Inject
    DbPopulateData(DbOwnerRepository ownerRepository) {
        this.ownerRepository = ownerRepository;
    }

    @EventListener
    void init(StartupEvent event) {
        Owner fred = new Owner("Fred");
        fred.setAge(45);
        Owner barney = new Owner("Barney");
        barney.setAge(40);
        ownerRepository.saveAll(Arrays.asList(fred, barney));
    }
}

ではHelidonに戻り、RESTエンドポイントをJAX-RSを使って作成しましょう。このエンドポイントはCDI beanですが、統合のおかげでMicronaut beanをCDI beanにインジェクトできるため、ownerリポジトリをJAX-RSリソースにインジェクトできるようになりました。

import javax.inject.Inject;
import javax.validation.constraints.Pattern;
import javax.ws.rs.GET;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;

@Path("/owners")
public class OwnerResource {
    private final DbOwnerRepository ownerRepository;

@Inject
    public OwnerResource(DbOwnerRepository ownerRepo) {
        this.ownerRepository = ownerRepo;
    }

    /**
     * Gets all owners from the database.
     * @return all owners, using JSON-B to map them to JSON
     */
    @GET
    public Iterable<Owner> getAll() {
        return ownerRepository.findAll();
    }

@Path("/{name}")
    @GET
    public Owner owner(@PathParam("name") String name) {
        return ownerRepository.findByName(name)
                .orElseThrow(() -> new NotFoundException("Owner by name " + name + " does not exist"));
    }
}

そして、同じくらい簡単に、HelidonのCDI beanからMicronaut Dataのリポジトリを利用するようになりました。

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Google フォト

Google アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中