The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.
このページを編集

Implementing a Custom Stork Service Registrar

プレビュー

This guide explains how to implement a custom service registrar for SmallRye Stork and use it to programmatically register service instances at startup.

Stork を初めて使用する場合は、Stork 入門ガイド をお読みください。

この技術は、previewと考えられています。

preview では、下位互換性やエコシステムでの存在は保証されていません。具体的な改善には設定や API の変更が必要になるかもしれませんが、 stable になるための計画は現在進行中です。フィードバックは メーリングリストGitHub の課題管理 で受け付けています。

とりうるステータスの完全なリストについては、 FAQの項目 を参照してください。

前提条件

このガイドを完成させるには、以下が必要です:

  • 約15分

  • IDE

  • JDK 17+がインストールされ、 JAVA_HOME が適切に設定されていること

  • Apache Maven 3.9.15

  • 使用したい場合は、 Quarkus CLI

  • ネイティブ実行可能ファイルをビルドしたい場合、MandrelまたはGraalVM(あるいはネイティブなコンテナビルドを使用する場合はDocker)をインストールし、 適切に設定していること

アーキテクチャ

In this guide, we will build an application that:

  • Implements a custom service registrar by extending Stork’s SPI

  • Programmatically registers a service instance at startup

  • Configures the registrar via application.properties

Beyond service discovery and load balancing, it also supports service registration. Service registration is the process of announcing a service instance to a registry so that other services can discover it. While Stork provides built-in registrars for Consul, Eureka, and others, you can implement your own by using the Stork SPI.

ソリューション

次の章で紹介する手順に沿って、ステップを踏んでアプリを作成することをお勧めします。ただし、完成した例にそのまま進んでも構いません。

Gitリポジトリをクローン: git clone https://github.com/quarkusio/quarkus-quickstarts.git 、または archive をダウンロードする。

The solution is located in the stork-programmatic-custom-registration-quickstart directory.

プロジェクトのブートストラップ

Create a Quarkus project importing the quarkus-rest, quarkus-smallrye-stork, and quarkus-rest-client-jackson extensions using your favorite approach:

コマンドラインインタフェース
quarkus create app org.acme:stork-programmatic-custom-registration-quickstart \
    --extension='quarkus-rest,quarkus-smallrye-stork,quarkus-rest-client-jackson' \
    --no-code
cd stork-programmatic-custom-registration-quickstart

Gradleプロジェクトを作成するには、 --gradle または --gradle-kotlin-dsl オプションを追加します。

Quarkus CLIのインストールと使用方法の詳細については、 Quarkus CLI ガイドを参照してください。

Maven
mvn io.quarkus.platform:quarkus-maven-plugin:3.35.1:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=stork-programmatic-custom-registration-quickstart \
    -Dextensions='quarkus-rest,quarkus-smallrye-stork,quarkus-rest-client-jackson' \
    -DnoCode
cd stork-programmatic-custom-registration-quickstart

Gradleプロジェクトを作成するには、 -DbuildTool=gradle または -DbuildTool=gradle-kotlin-dsl オプションを追加します。

Windowsユーザーの場合:

  • cmdを使用する場合、(バックスラッシュ \ を使用せず、すべてを同じ行に書かないでください)。

  • Powershellを使用する場合は、 -D パラメータを二重引用符で囲んでください。例: "-DprojectArtifactId=stork-programmatic-custom-registration-quickstart"

生成されたプロジェクトに、以下の依存関係を追加します:

pom.xml
<dependency>
    <groupId>io.smallrye.stork</groupId>
    <artifactId>stork-core</artifactId>
</dependency>
<dependency>
    <groupId>io.smallrye.stork</groupId>
    <artifactId>stork-configuration-generator</artifactId>
</dependency>
build.gradle
implementation("io.smallrye.stork:stork-core")
implementation("io.smallrye.stork:stork-configuration-generator")

stork-core provides the Stork API and SPI needed to implement a custom registrar. stork-configuration-generator generates configuration classes at build time based on annotations on your registrar provider.

The Custom Service Registrar Provider

Stork uses a provider model. To create a custom registrar, you need two classes:

  1. A provider implementing ServiceRegistrarProvider — the factory that creates registrar instances.

  2. A registrar implementing ServiceRegistrar — the actual registration logic.

Let’s start with the provider. Create the src/main/java/org/acme/services/CustomServiceRegistrarProvider.java file with the following content:

package org.acme.services;

import io.smallrye.stork.api.Metadata;
import io.smallrye.stork.api.ServiceRegistrar;
import io.smallrye.stork.api.config.ServiceRegistrarAttribute;
import io.smallrye.stork.api.config.ServiceRegistrarType;
import io.smallrye.stork.spi.ServiceRegistrarProvider;
import io.smallrye.stork.spi.StorkInfrastructure;
import jakarta.enterprise.context.ApplicationScoped;

@ServiceRegistrarType(value = "custom", metadataKey = Metadata.DefaultMetadataKey.class)
@ServiceRegistrarAttribute(name = "host",
        description = "Host name of the service registration server.", required = true)
@ServiceRegistrarAttribute(name = "port",
        description = "Port of the service registration server.", required = false)
@ApplicationScoped
public class CustomServiceRegistrarProvider
        implements ServiceRegistrarProvider<CustomRegistrarConfiguration, Metadata.DefaultMetadataKey> {

    @Override
    public ServiceRegistrar createServiceRegistrar(
            CustomRegistrarConfiguration config,
            String serviceName,
            StorkInfrastructure storkInfrastructure) {
        return new CustomServiceRegistrar(config);
    }

}

There are a few important things to note:

  • The @ServiceRegistrarType annotation declares the registrar type. This is the value used in the quarkus.stork.<service-name>.service-registrar.type property. Here, it is custom.

  • The @ServiceRegistrarAttribute annotations declare the configuration attributes for this registrar. Stork’s annotation processor (provided by stork-configuration-generator) uses these annotations to generate the CustomRegistrarConfiguration class at compile time. You do not need to write this class yourself.

  • The @ApplicationScoped annotation makes this provider a CDI bean, so Stork can discover it automatically.

  • The createServiceRegistrar method is the factory that creates a CustomServiceRegistrar from the generated configuration.

The Custom Service Registrar

Now let’s implement the registrar itself. Create the src/main/java/org/acme/services/CustomServiceRegistrar.java file with the following content:

package org.acme.services;

import io.smallrye.mutiny.Uni;
import io.smallrye.stork.api.Metadata;
import io.smallrye.stork.api.ServiceRegistrar;

import org.jboss.logging.Logger;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class CustomServiceRegistrar implements ServiceRegistrar {

    private static final Logger LOGGER = Logger.getLogger(CustomServiceRegistrar.class.getName());

    private final String backendHost;
    private final int backendPort;
    private final Map<String, String> registeredInstances = new ConcurrentHashMap<>();

    public CustomServiceRegistrar(CustomRegistrarConfiguration configuration) {
        this.backendHost = configuration.getHost();
        this.backendPort = Integer.parseInt(configuration.getPort()!=null?configuration.getPort():"8080");
    }


    @Override
    public Uni<Void> registerServiceInstance(String serviceName, Metadata metadata, String ipAddress, int defaultPort) {
        String address = ipAddress + ":" + defaultPort;
        LOGGER.info("Registering service: " + serviceName + " with ipAddress: " + ipAddress + " and port: " + defaultPort);
        registeredInstances.put(serviceName, address);
        return Uni.createFrom().voidItem();
    }

    @Override
    public Uni<Void> deregisterServiceInstance(String serviceName) {
        LOGGER.infof("Deregistering service '%s' from backend %s:%d", serviceName, backendHost, backendPort);
        registeredInstances.remove(serviceName);
        return Uni.createFrom().voidItem();
    }
}

This registrar:

  • Receives its configuration (host and port) from the generated CustomRegistrarConfiguration class.

  • Stores registered instances in a ConcurrentHashMap.

  • Implements registerServiceInstance to add a service instance to the map.

  • Implements deregisterServiceInstance to remove a service instance on shutdown.

  • Both methods return Uni<Void>, since Stork uses Mutiny for reactive support.

Programmatic Service Registration at Startup

With the registrar in place, we can now register service instances programmatically. Create the src/main/java/org/acme/services/Registration.java file with the following content:

package org.acme.services;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.event.Observes;

import io.quarkus.runtime.StartupEvent;
import io.smallrye.stork.Stork;
import io.vertx.mutiny.core.Vertx;

@ApplicationScoped
public class Registration {

    /**
     * Register our two services using custom registrar.
     *
     * Note: this method is called on a worker thread, and so it is allowed to block.
     */
    public void init(@Observes StartupEvent ev, Vertx vertx) {
        Stork.getInstance().getService("my-service").registerInstance("my-service", "localhost",
                9000);
    }
}

When the application starts, this CDI bean observes the StartupEvent and uses the Stork API to register a service instance. The Stork.getInstance().getService("my-service") call retrieves the Stork service named my-service, and registerInstance delegates to the custom registrar we created earlier.

Stork の設定

Now we need to configure Stork to use our custom registrar.

src/main/resources/application.properties に以下を追加します:

quarkus.stork.my-service.service-registrar.type=custom
quarkus.stork.my-service.service-registrar.host=localhost

The quarkus.stork.my-service.service-registrar.type property tells Stork to use the custom registrar type. This matches the value declared in the @ServiceRegistrarType annotation on CustomServiceRegistrarProvider.

The quarkus.stork.my-service.service-registrar.host property maps to the host attribute declared with @ServiceRegistrarAttribute on the provider. This is a required attribute.

You can optionally set quarkus.stork.my-service.service-registrar.port as well, since the provider declares an optional port attribute. If omitted, the registrar defaults to port 8080.

アプリケーションの実行

Package the application:

コマンドラインインタフェース
quarkus build
Maven
./mvnw install
Gradle
./gradlew build

そして実行します:

> java -jar target/quarkus-app/quarkus-run.jar

You should see the following log message in the output, confirming that the custom registrar is invoked:

INFO  [org.acm.ser.CustomServiceRegistrar] Registering service: my-service with ipAddress: localhost and port: 9000

このアプリケーションをネイティブ実行可能ファイルにコンパイルして、起動することができます。

コマンドラインインタフェース
quarkus build --native
Maven
./mvnw install -Dnative
Gradle
./gradlew build -Dquarkus.native.enabled=true

まとめ

In this guide, we have:

  1. Implemented a custom ServiceRegistrarProvider using the @ServiceRegistrarType and @ServiceRegistrarAttribute annotations.

  2. Implemented a custom ServiceRegistrar with registerServiceInstance and deregisterServiceInstance methods.

  3. Used the Stork API to programmatically register a service instance at startup.

  4. Configured the custom registrar in application.properties.

This pattern is useful when you need to integrate Stork with a service registry that is not supported out of the box.

さらに詳しく

This guide has shown how to extend SmallRye Stork with a custom service registrar. You can find more about Stork in:

関連コンテンツ