原文はこちら。
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のリポジトリを利用するようになりました。