Java で App Lifecycle Manager の機能フラグを使用する

このガイドでは、Java アプリケーションを App Lifecycle Manager の機能フラグと統合する方法について説明します。OpenFeature SDK を flagd プロバイダとともに使用して、App Lifecycle Manager で管理されるフラグを評価し、Java サービスで機能の可用性と動作を動的に制御する方法について説明します。

このガイドでは、次のいずれかのクイックスタートを完了して、必要な App Lifecycle Manager リソース(SaaS サービス、ユニットの種類、ユニット、フラグ、ロールアウトなど)がすでに設定されていることを前提としています。

前提条件

始める前に、次の準備をしてください。

  1. Java がインストールされている: JDK 17 以降。
  2. App Lifecycle Manager の機能フラグのクイックスタートを完了している:
    • 統合またはスタンドアロンの機能フラグのクイックスタートを正常に完了して、ターゲット ユニットをプロビジョニングしている。
    • そのクイックスタートの環境変数または値(PROJECT_IDLOCATION_1(ユニットのリージョン)、UNIT_IDFLAG_KEY など)がある。
  3. アプリケーションのデフォルト認証情報(ADC)の gcloud を認証している: Java アプリケーションは ADC を使用して Google Cloud サービスを認証します。環境で認証されていることを確認します。

    gcloud auth application-default login
    
  4. IAM の権限: Java アプリケーションを実行する ID には、 プロジェクトに対する roles/saasconfig.viewer Identity and Access Management ロールが必要です。これにより、フラグ構成を読み取ることができます。 Google Cloud

    gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \
        --member="user:YOUR_EMAIL_ADDRESS" \
        --role="roles/saasconfig.viewer"
    

    YOUR_PROJECT_IDYOUR_EMAIL_ADDRESS は適宜置き換えてください。

重要な環境変数について

Java アプリケーションは、環境変数を使用して正しいフラグ構成に接続します。

  • FLAGD_SOURCE_PROVIDER_ID: App Lifecycle Manager サービスから取得するフィーチャー トグル構成を指定します。ユニットに関連付けられた FeatureFlagConfig の完全なリソース名である必要があります。
    • 形式: projects/PROJECT_ID/locations/LOCATION/featureFlagsConfigs/UNIT_ID
    • : projects/my-gcp-project/locations/us-central1/featureFlagsConfigs/my-app-instance-01

Java プロジェクトを設定する

アプリケーションを実行する前に、プロジェクトを初期化して必要な依存関係を構成する必要があります。

  1. プロジェクト ディレクトリを作成します。

    mkdir java-featureflag-app
    cd java-featureflag-app
    
  2. 依存関係を追加します。 次のライブラリを含めるようにビルドシステム(Maven または Gradle)を構成します。OpenFeature 1.14.1、flagd 0.11.5、gRPC 1.71.0 より大きいバージョンを使用して互換性を確保してください。

    • dev.openfeature:javasdk:1.14.1+
    • dev.openfeature.contrib.providers:flagd:0.11.5+
    • io.grpc:grpc-netty-shaded:1.71.0+
    • io.grpc:grpc-auth:1.71.0+
    • com.google.auth:google-auth-library-oauth2-http
  3. 初期化コードを作成します。 次の内容で FeatureManagement.java という名前のファイルを追加します。このクラスは、ADC とリージョン ルーティング ヘッダーをアタッチする gRPC インターセプタを設定し、インプロセス解決を使用して FlagdProvider を初期化します。

    import com.google.auth.oauth2.GoogleCredentials;
    import dev.openfeature.contrib.providers.flagd.Config;
    import dev.openfeature.contrib.providers.flagd.FlagdOptions;
    import dev.openfeature.contrib.providers.flagd.FlagdProvider;
    import dev.openfeature.sdk.OpenFeatureAPI;
    import io.grpc.*;
    import io.grpc.auth.MoreCallCredentials;
    import java.util.ArrayList;
    import java.util.List;
    
    public class FeatureManagement {
        public static void initialize() throws Exception {
            // Read the full Unit resource name
            String flagConfigId = System.getenv("FLAGD_SOURCE_PROVIDER_ID");
            if (flagConfigId == null || flagConfigId.isEmpty()) {
                throw new IllegalStateException("FLAGD_SOURCE_PROVIDER_ID environment variable is not set.");
            }
    
            // Configure gRPC Security and Routing
            GoogleCredentials credentials = GoogleCredentials.getApplicationDefault();
            CallCredentials callCredentials = MoreCallCredentials.from(credentials);
    
            List<ClientInterceptor> interceptors = new ArrayList<>();
    
            // Interceptor to inject the Unit name into headers for regional routing
            interceptors.add(new ClientInterceptor() {
                @Override
                public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {
                    return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(next.newCall(method, callOptions)) {
                        @Override
                        public void start(Listener<RespT> responseListener, Metadata headers) {
                            headers.put(Metadata.Key.of("x-goog-request-params", Metadata.ASCII_STRING_MARSHALLER), "name=" + flagConfigId);
                            super.start(responseListener, headers);
                        }
                    };
                }
            });
    
            // Interceptor to attach ADC to the gRPC calls
            interceptors.add(new ClientInterceptor() {
                @Override
                public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {
                    return next.newCall(method, callOptions.withCallCredentials(callCredentials));
                }
            });
    
            // Initialize the flagd provider with In-Process resolution
            FlagdProvider provider = new FlagdProvider(
                FlagdOptions.builder()
                    .resolverType(Config.Resolver.IN_PROCESS)
                    .host("saasconfig.googleapis.com").port(443)
                    .tls(true)
                    .providerId(flagConfigId)
                    .clientInterceptors(interceptors)
                    .syncMetadataDisabled(true)
                    .deadline(10000)
                    .build()
            );
    
            // Set the global provider
            OpenFeatureAPI.getInstance().setProviderAndWait(provider);
        }
    }
    
  4. アプリケーション ロジックを作成します。 次の内容で Main.java という名前のファイルを追加して、フラグ評価を実行します。

    import dev.openfeature.sdk.OpenFeatureAPI;
    import dev.openfeature.sdk.MutableContext;
    
    public class Main {
        public static void main(String[] args) throws Exception {
    
        // 1. Get Client
        var client = OpenFeatureAPI.getInstance().getClient("simple-api");
    
        // 2. Create Evaluation Context 
        var context = new dev.openfeature.sdk.MutableContext();
    
        // 3. Evaluate Flag
        // Default to false if evaluation fails or service is unreachable
        boolean isEnhanced = client.getBooleanValue("enhanced-search", false, context);
    
        // 4. Execute business logic based on result
        if (isEnhanced) {
            System.out.println("Executing enhanced search algorithm...");
        } else {
            System.out.println("Standard search algorithm...");
        }
    
        }
    }
    

Java アプリケーションを実行する

アプリケーションは、スタンドアロン構成を使用してローカルで実行することも、コンテナとしてデプロイすることもできます。

スタンドアロン(ローカル)で実行する

  1. 環境変数を設定します。

    export PROJECT_ID="your-gcp-project-id"
    export LOCATION_1="us-central1"
    export UNIT_ID="my-app-instance-01"
    export FLAGD_SOURCE_PROVIDER_ID="projects/${PROJECT_ID}/locations/${LOCATION_1}/featureFlagsConfigs/${UNIT_ID}"
    
  2. アプリケーションを実行します。 任意のビルドツール コマンド(mvn compile exec:java./gradlew run など)を使用してプロジェクトを実行します。

統合(コンテナ化)を実行する

  1. Dockerfile を作成します。 Java バイナリをパッケージ化するコンテナビルドを定義します。

    FROM maven:3.9-eclipse-temurin-17 AS builder
    WORKDIR /app
    COPY pom.xml .
    COPY src ./src
    RUN mvn clean package
    
    FROM eclipse-temurin:17-jre
    WORKDIR /app
    COPY --from=builder /app/target/java-featureflag-app.jar app.jar
    ENTRYPOINT ["java", "-jar", "app.jar"]
    
  2. イメージをビルドして push します。

    export PROJECT_ID="your-gcp-project-id"
    docker build -t gcr.io/${PROJECT_ID}/my-java-app:latest .
    docker push gcr.io/${PROJECT_ID}/my-java-app:latest
    
  3. サービスをデプロイします。 ユニット ブループリントを更新して gcr.io/${PROJECT_ID}/my-java-app:latest を参照し、App Lifecycle Manager のロールアウトを使用して新しいリリースをデプロイします。

フラグの変更を確認する

アプリケーションが実行されたら、フラグが正しく評価されることを確認します。

  1. 初期値を観察します。 コンソール出力で、初期構成の状態に対応する評価値がログに記録されていることを確認します。
  2. App Lifecycle Manager でフラグを更新します: コンソールまたは gcloud を使用して、フラグのペイロードまたはターゲティング ルールを変更します。 Google Cloud
  3. 更新された値を確認します。 ローカル実行を再実行するか、コンテナログを観察して、新しい評価状態を確認します。

次のステップ