Utiliser des commutateurs de fonctionnalité App Lifecycle Manager avec Java

Ce guide explique comment intégrer vos applications Java aux indicateurs de fonctionnalité d'App Lifecycle Manager. Vous découvrirez comment utiliser le SDK OpenFeature avec le fournisseur flagd pour évaluer les indicateurs gérés par App Lifecycle Manager, ce qui vous permet de contrôler de manière dynamique la disponibilité et le comportement des fonctionnalités dans vos services Java.

Ce guide suppose que vous avez déjà configuré les ressources App Lifecycle Manager nécessaires (comme les offres d'applications, les types d'unités, les unités, les indicateurs et les déploiements progressifs) en suivant l'un des guides de démarrage rapide suivants :

Prérequis

Avant de commencer, assurez-vous de disposer des éléments suivants :

  1. Java installé : JDK 17 ou version ultérieure.
  2. Guide de démarrage rapide sur les indicateurs de fonctionnalité d'App Lifecycle Manager suivi
    • Vous avez suivi le guide de démarrage rapide sur les flags de fonctionnalité intégrés ou autonomes pour provisionner votre unité cible.
    • Vous devez disposer de variables ou de valeurs d'environnement issues de ce guide de démarrage rapide, telles que PROJECT_ID, LOCATION_1 (la région de votre unité), UNIT_ID et FLAG_KEY.
  3. **`gcloud` authentifié pour les Identifiants par défaut de l'application (ADC)**gcloud : l'application Java utilise les ADC pour s'authentifier auprès des Google Cloud services. Assurez-vous d'être authentifié dans votre environnement :

    gcloud auth application-default login
    
  4. Autorisations IAM : l'identité qui exécute votre application Java doit disposer du rôle IAM (Identity and Access Management) roles/saasconfig.viewer sur votre Google Cloud projet pour lire les configurations d'indicateur :

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

    Remplacez YOUR_PROJECT_ID et YOUR_EMAIL_ADDRESS en conséquence.

Comprendre les principales variables d'environnement

Votre application Java s'appuie sur des variables d'environnement pour se connecter à la configuration d'indicateur appropriée.

  • FLAGD_SOURCE_PROVIDER_ID: spécifie la configuration de flag de fonctionnalité à extraire du service App Lifecycle Manager. Il doit s'agir du nom complet de la ressource FeatureFlagConfig associée à votre unité.
    • Format: projects/PROJECT_ID/locations/LOCATION/featureFlagsConfigs/UNIT_ID
    • Exemple : projects/my-gcp-project/locations/us-central1/featureFlagsConfigs/my-app-instance-01

Configurer votre projet Java

Avant de pouvoir exécuter votre application, vous devez initialiser votre projet et configurer les dépendances nécessaires.

  1. Créer un répertoire de projet :

    mkdir java-featureflag-app
    cd java-featureflag-app
    
  2. Ajouter des dépendances : configurez votre système de compilation (Maven ou Gradle) pour inclure les bibliothèques suivantes. Assurez la compatibilité en utilisant des versions supérieures à OpenFeature 1.14.1, flagd 0.11.5 et 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. Créer le code d'initialisation : ajoutez un fichier nommé FeatureManagement.java avec le contenu suivant. Cette classe configure les intercepteurs gRPC pour associer les en-têtes ADC et de routage régional, et initialise le FlagdProvider à l'aide de la résolution en cours de processus.

    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. Créer la logique d'application : ajoutez un fichier nommé Main.java avec le contenu suivant pour exécuter l'évaluation de l'indicateur.

    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...");
        }
    
        }
    }
    

Exécuter l'application Java

Vous pouvez exécuter l'application localement à l'aide de votre configuration autonome ou déployée en tant que conteneur.

Exécuter de manière autonome (localement)

  1. Définir des variables d'environnement :

    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. Exécuter l'application : exécutez le projet à l'aide de la commande de votre outil de compilation préféré (par exemple, mvn compile exec:java ou ./gradlew run).

Exécuter de manière intégrée (conteneurisée)

  1. Créer un Dockerfile : définissez une compilation de conteneur qui regroupe le binaire 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. Créer et transférer l'image :

    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. Déployer le service : mettez à jour le plan de votre unité pour référencer gcr.io/${PROJECT_ID}/my-java-app:latest et déployez la nouvelle version à l'aide d'un déploiement progressif App Lifecycle Manager.

Vérifier les modifications d'indicateur

Une fois votre application exécutée, vérifiez qu'elle évalue correctement les indicateurs.

  1. Observer la valeur initiale : vérifiez que la sortie de la console enregistre la valeur évaluée correspondant à l'état de configuration initial.
  2. Mettre à jour l'indicateur dans App Lifecycle Manager : modifiez la charge utile de l'indicateur ou les règles de ciblage à l'aide de la console ou de Google Cloud gcloud.
  3. Vérifier la valeur mise à jour : réexécutez l'exécution locale ou observez les journaux de conteneur pour confirmer le nouvel état évalué.

Étape suivante