Utiliser des commutateurs de fonctionnalité App Lifecycle Manager avec Java

Ce guide explique comment intégrer vos applications Java aux indicateurs de fonctionnalité App Lifecycle Manager. Vous apprendrez à utiliser le SDK OpenFeature avec le fournisseur flagd pour évaluer les indicateurs gérés par App Lifecycle Manager. Vous pourrez ainsi 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 SaaS, les types d'unités, les unités, les indicateurs et les déploiements) 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. Vous avez terminé le guide de démarrage rapide sur les feature flags App Lifecycle Manager :
    • Vous avez terminé le guide de démarrage rapide des flags de fonctionnalité intégrés ou autonomes pour provisionner votre unité cible.
    • Vous devriez disposer de variables d'environnement ou de valeurs issues de ce 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) : l'application Java utilise les ADC pour s'authentifier auprès des services Google Cloud . Assurez-vous d'être authentifié dans votre environnement :

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

    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 par les valeurs correspondantes.

Comprendre les principales variables d'environnement

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

  • FLAGD_SOURCE_PROVIDER_ID : spécifie la configuration du flag de fonctionnalité à récupérer à partir du service App Lifecycle Manager. Il doit s'agir du nom complet de la ressource FeatureFlagConfig associé à 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éez un répertoire de projet :

    mkdir java-featureflag-app
    cd java-featureflag-app
    
  2. Ajoutez 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éez 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 FlagdProvider à l'aide de la résolution en cours.

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

    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 en local à l'aide de votre configuration autonome ou la déployer en tant que conteneur.

Exécuter de manière autonome (en local)

  1. Définissez les 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écutez 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 (conteneur)

  1. Créez 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éez et transférez 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éployez le service : mettez à jour votre plan d'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 App Lifecycle Manager.

Vérifier les modifications apportées aux signalements

Une fois votre application en cours d'exécution, vérifiez qu'elle évalue correctement les indicateurs.

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

Étapes suivantes