Extending Configuration Support
1. Custom ConfigSource
MicroProfile Config で指定されたカスタム ConfigSource を作成することが可能です。
カスタム ConfigSource では、追加の設定値を読み込んで、定義された順序で Config インスタンスに追加することができます。これにより、他のソースからの値をオーバーライドしたり、他の値にフォールバックしたりすることができます。
カスタム ConfigSource には、 org.eclipse.microprofile.config.spi.ConfigSource または org.eclipse.microprofile.config.spi.ConfigSourceProvider の実装が必要です。
各実装には、 META-INF/services/org.eclipse.microprofile.config.spi.ConfigSource または META-INF/services/org.eclipse.microprofile.config.spi.ConfigSourceProvider ファイルの ServiceLoader メカニズムによる登録が必要です。
1.1. 例
単純なインメモリ ConfigSource を考えてみましょう。
package org.acme.config;
import org.eclipse.microprofile.config.spi.ConfigSource;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class InMemoryConfigSource implements ConfigSource {
private static final Map<String, String> configuration = new HashMap<>();
static {
configuration.put("my.prop", "1234");
}
@Override
public int getOrdinal() {
return 275;
}
@Override
public Set<String> getPropertyNames() {
return configuration.keySet();
}
@Override
public String getValue(final String propertyName) {
return configuration.get(propertyName);
}
@Override
public String getName() {
return InMemoryConfigSource.class.getSimpleName();
}
}
そして以下に登録します。
org.acme.config.InMemoryConfigSource
InMemoryConfigSource は、 275 の序列により、 .env ソースと、 application.properties ソースの間に順序付けられます。
| ConfigSource | 序列 |
|---|---|
システムプロパティ |
400 |
システムからの環境変数 |
300 |
|
295 |
InMemoryConfigSource |
275 |
|
260 |
アプリケーションからの |
250 |
アプリケーションからの |
100 |
この場合、 InMemoryConfigSource からの my.prop は、設定エンジンが システムプロパティ、 システムからの環境変数、 .env ファイルからの環境変数の順に値を見つけられない場合にのみ使用されます。
1.2. ConfigSource初期化
Quarkusアプリケーションの起動時に、 ConfigSource を2回初期化することができます。1回目は STATIC INIT で、2回目は RUNTIME INIT です。
1.2.1. STATIC INIT
Quarkusは静的初期化中にいくつかのサービスを開始しますが、 Config は通常、最初に作成されるものの1つです。特定の状況では、カスタムの ConfigSource を追加できない場合があります。例えば、 ConfigSource がデータベースアクセスのような他のサービスを必要とする場合、この段階では利用できず、鶏と卵の問題が発生してしまいます。このため、カスタム ConfigSource には、この段階で使用しても安全であるとソースをマークするためのアノテーション @io.quarkus.runtime.configuration.StaticInitSafe が必要です。
1.2.1.1. 例
以下だとすると、
package org.acme.config;
import org.eclipse.microprofile.config.spi.ConfigSource;
import io.quarkus.runtime.annotations.StaticInitSafe;
@StaticInitSafe
public class InMemoryConfigSource implements ConfigSource {
}
そして以下に登録します。
org.acme.config.InMemoryConfigSource
InMemoryConfigSource は、 STATIC INIT 中に利用可能になります。
A custom ConfigSource is not automatically added during Quarkus STATIC INIT. It requires to be marked with
the @io.quarkus.runtime.configuration.StaticInitSafe annotation.
|
1.2.2. RUNTIME INIT
RUNTIME INIT ステージは、 STATIC INIT の後に起こります。このステージでは、 ConfigSource を再び初期化することができます。この段階では特に制限はなく、期待通りにカスタムソースが Config インスタンスに追加されます。
2. ConfigSourceFactory
ConfigSource を作成するもう一つの方法は、 SmallRye Config io.smallrye.config.ConfigSourceFactory API を使用することです。 SmallRye Configのファクトリーと、 MicroProfile Config で指定されている ConfigSource を作成する標準的な方法との違いは、利用可能な構成にアクセスできるコンテキストを提供するファクトリーの機能です。
io.smallrye.config.ConfigSourceFactory の各実装には、 META-INF/services/io.smallrye.config.ConfigSourceFactory ファイル内の ServiceLoader メカニズムによる登録が必要です。
2.1. 例
以下だとすると、
package org.acme.config;
import java.util.Collections;
import java.util.OptionalInt;
import org.eclipse.microprofile.config.spi.ConfigSource;
import io.smallrye.config.ConfigSourceContext;
import io.smallrye.config.ConfigSourceFactory;
import io.smallrye.config.ConfigValue;
import io.smallrye.config.PropertiesConfigSource;
public class URLConfigSourceFactory implements ConfigSourceFactory {
@Override
public Iterable<ConfigSource> getConfigSources(final ConfigSourceContext context) {
final ConfigValue value = context.getValue("config.url");
if (value == null || value.getValue() == null) {
return Collections.emptyList();
}
try {
return Collections.singletonList(new PropertiesConfigSource(new URL(value.getValue())));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public OptionalInt getPriority() {
return OptionalInt.of(290);
}
}
そして以下に登録します。
org.acme.config.URLConfigSourceFactory
io.smallrye.config.ConfigSourceFactory を実装することで、 Iterable<ConfigSource> getConfigSources(ConfigSourceContext context) メソッドを介して ConfigSource のリストを提供することができます。また、 ConfigSourceFactory は、 OptionalInt getPriority() メソッドをオーバーライドすることで、優先度を割り当てることができます。優先度の値は、複数の io.smallrye.config.ConfigSourceFactory をソートするために使用されます(見つかった場合)。
io.smallrye.config.ConfigSourceFactory priority does not affect the ConfigSource ordinal. These are
sorted independently.
|
ファクトリーの初期化中、提供された ConfigSourceContext は、メソッド ConfigValue getValue(String name) を呼び出すことができます。このメソッドは、 Config インスタンスによってすでに初期化されたすべての ConfigSource の設定名を検索します。これには、 ConfigSourceFactory で定義されたものよりも低い序列のソースが含まれます。 ConfigSourceFactory によって提供された ConfigSource リストは、優先順位の低い ConfigSourceFactory によって生成された他のソースを構成するためには考慮されません。
3. Custom Converter
MicroProfile Configで指定されたカスタム Converter 型を作成することが可能です。
カスタム Converter には、 org.eclipse.microprofile.config.spi.Converter<T> の実装が必要です。
各実装には、 META-INF/services/org.eclipse.microprofile.config.spi.Converter ファイル内の ServiceLoader メカニズムを介した登録が必要です。以下の場合、
package org.acme.config;
public class MicroProfileCustomValue {
private final int number;
public MicroProfileCustomValue(int number) {
this.number = number;
}
public int getNumber() {
return number;
}
}
対応するコンバータは以下のようになります。
package org.acme.config;
import org.eclipse.microprofile.config.spi.Converter;
public class MicroProfileCustomValueConverter implements Converter<MicroProfileCustomValue> {
@Override
public MicroProfileCustomValue convert(String value) {
return new MicroProfileCustomValue(Integer.parseInt(value));
}
}
The custom converter class must be public, must have a public constructor with no arguments, and must not be
abstract.
|
カスタムコンフィグレーションタイプは、設定値を自動的に変換します。
@ConfigProperty(name = "configuration.value.name")
MicroProfileCustomValue value;
3.1. コンバーターの優先順位
jakarta.annotation.Priority アノテーションは、 Converter の優先順位を上書きし、コンバータの優先順位を変更して実行順序を微調整します。デフォルトでは、 Converter に @Priority が指定されていない場合、コンバーターは 100 の優先順位で登録されます。以下の場合、
package org.acme.config;
import jakarta.annotation.Priority;
import org.eclipse.microprofile.config.spi.Converter;
@Priority(150)
public class MyCustomConverter implements Converter<MicroProfileCustomValue> {
@Override
public MicroProfileCustomValue convert(String value) {
final int secretNumber;
if (value.startsFrom("OBF:")) {
secretNumber = Integer.parseInt(SecretDecoder.decode(value));
} else {
secretNumber = Integer.parseInt(value);
}
return new MicroProfileCustomValue(secretNumber);
}
}
同値の型 ( MicroProfileCustomValue)を変換し、優先度が 150 であるため、デフォルトの優先度が 100 である MicroProfileCustomValueConverter の代わりに使用されます。
All Quarkus core converters use the priority value of 200. To override any Quarkus specific converter, the
priority value should be higher than 200.
|
4. 設定インターセプター
SmallRye Configは、設定値の解決をフックするインターセプターチェーンを提供します。これは、 プロファイルや プロパティExpressionsのような機能を実装するのに便利で、また、設定値がどこから読み込まれたかを調べるためのロギングにも役立ちます。
インターセプターには、 io.smallrye.config.ConfigSourceInterceptor の実装が必要です。
各実装には、 META-INF/services/io.smallrye.config.ConfigSourceInterceptor ファイル内の ServiceLoader メカニズムによる登録が必要です。
io.smallrye.config.ConfigSourceInterceptor は、メソッド ConfigValue getValue(ConfigSourceInterceptorContext context, String name) で設定名の解決をインターセプトすることができます。 ConfigSourceInterceptorContext は、インターセプター・チェーンを進めるために使用されます。このチェーンは、 io.smallrye.config.ConfigValue のインスタンスを返すことで短絡させることができます。 ConfigValue オブジェクトは、キー名、値、コンフィグソースのオリジン、序列に関する情報を保持しています。
| The interceptor chain is applied before any conversion is performed on the configuration value. |
インターセプターは、 io.smallrye.config.ConfigSourceInterceptorFactory の実装で作成することもできます。
各実装には、 META-INF/services/io.smallrye.config.ConfigSourceInterceptorFactory ファイル内の ServiceLoader メカニズムによる登録が必要です。
ConfigSourceInterceptorFactory は、(インターセプターの設定や設定値の取得に使用できるように)現在のチェーンにアクセスし、インターセプターを初期化し、優先度を設定することができます。
4.1. 例
package org.acme.config;
import static io.smallrye.config.SecretKeys.doLocked;
import jakarta.annotation.Priority;
import io.smallrye.config.ConfigSourceInterceptor;
import io.smallrye.config.ConfigLogging;
@Priority(Priorities.LIBRARY + 200)
public class LoggingConfigSourceInterceptor implements ConfigSourceInterceptor {
private static final long serialVersionUID = 367246512037404779L;
@Override
public ConfigValue getValue(final ConfigSourceInterceptorContext context, final String name) {
ConfigValue configValue = doLocked(() -> context.proceed(name));
if (configValue != null) {
ConfigLogging.log.lookup(configValue.getName(), configValue.getLocation(), configValue.getValue());
} else {
ConfigLogging.log.notFound(name);
}
return configValue;
}
}
そして以下に登録します。
org.acme.config.LoggingConfigSourceInterceptor
LoggingConfigSourceInterceptor ログは、提供されたログプラットフォームで設定名を検索します。ログ情報には、設定名と値、設定ソースの出所と場所(存在する場合)が含まれます。