Préparation d'entretien 100% Gratuit angularforall.com

Entretien Spring Boot Senior : microservices et cloud

Spring-Boot Senior Quiz-Springboot-Senior Microservices Spring-Cloud Eureka Feign Oauth2 Webflux Kafka Observabilite Questions-Entretien-Spring-Senior Qcm-Springboot-Avance Java
Sénior 🔀 Mixte 20 questions ⏱ 15 min
📝

Entretien Spring Boot Senior : microservices et cloud

20 questions Spring Boot avancées : microservices, Spring Cloud, Eureka, Feign, OAuth2, reactive avec WebFlux, Kafka, observabilité et architecture pour Senior.

20 questions ⏱ ~15 min Niveau Sénior

Partager

Banque de révision : les 30 questions corrigées

Voici l'intégralité des 30 questions de « Entretien Spring Boot Senior : microservices et cloud », chacune avec sa bonne réponse et son explication. Le quiz interactif ci-dessus en tire une sélection aléatoire à chaque tentative — utilisez cette liste complète pour réviser.

  • Via spring.factories qui liste les classes @Configuration chargées conditionnellement avec @ConditionalOnClass, @ConditionalOnMissingBean, etc. (bonne réponse)
  • Par magie, sans configuration
  • Via un fichier XML central
  • Uniquement par le développeur
Explication : L'auto-configuration utilise META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports (Spring Boot 3+) qui référence des classes @AutoConfiguration. Chaque classe utilise des annotations conditionnelles : @ConditionalOnClass (classe dans le classpath), @ConditionalOnMissingBean (bean non défini), @ConditionalOnProperty.
Pour déboguer l'auto-configuration, activez debug: true dans application.properties. Spring affichera un rapport des auto-configurations appliquées et rejetées.

  • Une hiérarchie de contextes (parent-enfant) où le contexte enfant peut accéder aux beans du parent ; utile pour les architectures modulaires (bonne réponse)
  • Un diagramme de classes
  • Un type de base de données
  • Un outil de monitoring
Explication : Spring permet de créer des contextes hiérarchiques avec ApplicationContext.setParent(). Le contexte enfant peut référencer les beans du parent (l'inverse est faux). Utile pour les applications multi-modules (ex: Spring MVC dans un contexte enfant d'un contexte racine de services).
Dans Spring Boot moderne, cette hiérarchie est rarement nécessaire. Le contexte unique avec des profils et des configurations conditionnelles est privilégié.

  • Spring crée un proxy AOP autour du bean ; selon la propagation (REQUIRED, REQUIRES_NEW, etc.), il démarre une nouvelle transaction ou participe à l'existante (bonne réponse)
  • @Transactional modifie directement la base de données
  • C'est une simple annotation sans comportement
  • La transaction est gérée par le développeur manuellement
Explication : Spring crée un proxy JDK ou CGLIB autour du bean annoté. La propagation REQUIRED (défaut) rejoint la transaction existante ou en crée une nouvelle. REQUIRES_NEW suspend la transaction courante et en crée une nouvelle. NESTED crée un savepoint.
Piège : l'auto-invocation (une méthode du même service appelle une méthode @Transactional) ne passe pas par le proxy, donc la transaction n'est pas appliquée.

  • Utiliser ShedLock avec @SchedulerLock, ou Spring Integration avec un lock provider (JDBC, Redis, Zookeeper) (bonne réponse)
  • Un simple synchronized en Java
  • Un fichier de verrou sur le disque
  • Désactiver le multithreading
Explication : ShedLock est une bibliothèque légère qui utilise une table de base de données (@SchedulerLock) pour garantir qu'une tâche planifiée ne s'exécute que sur une instance. Pour des locks plus généraux, Spring Integration fournit LockRegistry avec des implémentations JDBC, Redis, Zookeeper.
Pour les tâches @Scheduled en cluster, ShedLock est indispensable. Configurez lockAtMostFor et lockAtLeastFor pour éviter les deadlocks.

  • Stratégies : URI versioning (/api/v1/), header versioning (Accept: application/vnd.api.v1+json), ou parameter versioning (?version=1) (bonne réponse)
  • Le versioning n'est pas nécessaire pour les API REST
  • Changer l'API sans préavis
  • Créer une nouvelle application pour chaque version
Explication : Trois stratégies principales : 1) URI versioning (/api/v1/users), le plus simple et visible. 2) Header versioning (Accept: application/vnd.company.v1+json), URI propre mais moins découvrable. 3) Parameter versioning (/api/users?version=1), flexible mais pollue les paramètres.
L'URI versioning est recommandé pour les API publiques (simplicité, découvrabilité). Le header versioning est préféré pour les API internes (HATEOAS).

  • WebFlux est non-bloquant et asynchrone (basé sur Reactor/Netty) ; Spring MVC est synchrone et bloquant (basé sur Servlet API) (bonne réponse)
  • WebFlux est plus lent que Spring MVC
  • Les deux sont identiques
  • WebFlux remplace complètement Spring MVC
Explication : Spring WebFlux est un framework réactif utilisant Mono/Flux (Project Reactor) et Netty par défaut. Il est non-bloquant et peut gérer plus de requêtes concurrentes avec moins de threads. Spring MVC reste le choix par défaut pour les applications classiques.
Adoptez WebFlux si vous avez besoin de haute concurrence (milliers de connexions simultanées) ou si tout votre stack est réactive (R2DBC, Reactive Redis). Sinon, Spring MVC est plus simple.

  • Utiliser Spring Cloud Function, GraalVM Native Image, lazy initialization, et exclure les auto-configurations inutiles (bonne réponse)
  • Ajouter plus de RAM
  • Utiliser un serveur plus puissant
  • Le serverless n'est pas compatible avec Spring Boot
Explication : Pour le serverless (cold starts) : Spring Cloud Function adapte Spring au modèle fonctionnel, GraalVM Native Image compile en binaire natif (démarrage quasi-instantané), spring.main.lazy-initialization=true retarde l'initialisation des beans, et exclure les auto-configurations non nécessaires.
GraalVM Native Image peut réduire le temps de démarrage de 2-3 secondes à 50-100ms, au prix d'une compilation plus longue et de certaines limitations (reflection, proxies).

  • Un JAR organisé en couches (dependencies, spring-boot-loader, snapshot-dependencies, application) pour optimiser les builds Docker (bonne réponse)
  • Un format de fichier compressé
  • Un type de base de données en couches
  • Un outil de déploiement
Explication : Le JAR Spring Boot est structuré en couches séparant les dépendances (qui changent rarement) du code applicatif (qui change souvent). Avec un Dockerfile multi-stage qui copie d'abord les dépendances, on exploite le cache Docker : les dépendances ne sont re-téléchargées que si elles changent.
Activez l'extraction des couches avec spring-boot-maven-plugin configuration <layers><enabled>true</enabled></layers>.

  • Écrire les messages dans une table outbox dans la même transaction que la mise à jour métier ; un processus séparé lit et publie les messages (bonne réponse)
  • Envoyer le message directement après la transaction
  • Utiliser un système de fichier
  • Ignorer la cohérence
Explication : Le pattern Outbox résout le problème de la double écriture (BDD + message broker). Dans une transaction unique, on écrit à la fois la donnée métier ET le message dans une table outbox. Un processus (polling ou CDC - Change Data Capture) lit cette table et publie les messages.
Des bibliothèques comme Debezium (CDC avec Kafka Connect) ou Spring Cloud Stream avec des modules transactionnels simplifient l'implémentation du pattern Outbox.

  • Scopes standard : singleton, prototype, request, session ; le scope "thread" personnalisé via SimpleThreadScope ou un scope custom (bonne réponse)
  • Uniquement singleton et prototype
  • Les scopes sont définis dans web.xml
  • Les scopes n'existent pas dans Spring
Explication : Scopes standards : singleton (un par contexte), prototype (nouveau à chaque injection), request/session/application (web). Pour des besoins avancés, on peut créer un scope personnalisé en implémentant org.springframework.beans.factory.config.Scope (ex: scope "thread", "tenant").
Le scope custom le plus courant en multi-tenant : un scope "tenant" qui retourne un bean différent selon le tenant courant.

  • Remplacer javax.* par jakarta.*, migrer Spring Security, vérifier les dépréciations, et utiliser Java 17 minimum (bonne réponse)
  • Aucune migration nécessaire
  • Réécrire toute l'application
  • Rester sur Spring Boot 2.x
Explication : La migration majeure : javax → jakarta (Servlet, Validation, Persistence), Java 17 requis, Spring Security 6 (nouvelles API), suppression de dépréciations (WebSecurityConfigurerAdapter), et adaptation aux nouvelles auto-configurations. Des outils comme OpenRewrite automatisent une grande partie.
Utilisez OpenRewrite avec le recipe org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_0 pour automatiser 80% de la migration.

  • Compilation anticipée qui pré-calcule les proxies, les conditions et les réflexions pour réduire le temps de démarrage (bonne réponse)
  • Un outil de test
  • Un framework concurrent
  • Une base de données
Explication : Le Spring AOT (introduit dans Spring 6/Spring Boot 3) analyse le code à la compilation pour générer à l'avance ce que Spring faisait au runtime : proxies, évaluation des conditions @ConditionalOn*, réflexion. Essentiel pour GraalVM Native Image mais bénéfique même pour la JVM.
Activez le mode AOT avec mvn spring-boot:process-aot. Le résultat est utilisé par spring-boot:build-image pour GraalVM.

  • Stratégies : DATABASE_PER_TENANT (une base par client), SCHEMA_PER_TENANT (un schéma par client), ou DISCRIMINATOR (colonne tenant_id) (bonne réponse)
  • Une seule base pour tous les clients
  • Créer une instance d'application par client
  • Le multi-tenancy n'est pas supporté
Explication : Trois approches : DATABASE_PER_TENANT (isolation maximale, coût élevé), SCHEMA_PER_TENANT (bon équilibre), DISCRIMINATOR (colonne partagée, isolation faible). Spring fournit AbstractRoutingDataSource et Hibernate a MultiTenantConnectionProvider.
Combinez avec un TenantContext (ThreadLocal) qui stocke le tenant courant, extrait d'un header HTTP ou d'un JWT.

  • Utiliser Micrometer Tracing (successeur de Spring Cloud Sleuth) avec Brave/OpenTelemetry et exporter vers Zipkin ou Jaeger (bonne réponse)
  • Des logs manuels dans chaque service
  • Un outil externe sans intégration
  • Le tracing distribué n'est pas supporté
Explication : Spring Boot 3 intègre Micrometer Tracing (remplace Sleuth). Il génère automatiquement des traceId et spanId, les propage via les headers HTTP (B3 ou W3C). Export vers Zipkin, Jaeger, ou OpenTelemetry Collector.
Ajoutez spring-boot-starter-actuator et micrometer-tracing-bridge-brave avec zipkin-reporter-brave. Les traces apparaissent automatiquement dans Zipkin.

  • Configurer un Resource Server avec spring-boot-starter-oauth2-resource-server, valider les JWT via un provider (Keycloak, Auth0) (bonne réponse)
  • Stocker les mots de passe dans la base de données
  • Utiliser une authentification basique HTTP
  • La sécurité OAuth2 n'est pas supportée
Explication : Spring Security 6 supporte OAuth2 Resource Server. Configurez spring.security.oauth2.resourceserver.jwt.issuer-uri. Spring valide automatiquement la signature JWT via le JWKS (JSON Web Key Set) du provider. Utilisez @PreAuthorize pour les autorisations fines.
Pour extraire les rôles d'un JWT Keycloak, configurez un JwtAuthenticationConverter qui mappe les realm_access.roles vers les GrantedAuthority.

  • Un outil pour structurer les monolithes modulaires avec des modules faiblement couplés, testables et documentés (bonne réponse)
  • Un framework de microservices
  • Un générateur de code
  • Un outil de build
Explication : Spring Modulith (officiel Spring, 2023) aide à construire des monolithes modulaires bien structurés. Il vérifie les violations de dépendances entre modules, permet des tests d'intégration par module, documente l'architecture, et facilite l'extraction ultérieure en microservices.
Idéal pour les applications qui commencent en monolithe mais pourraient évoluer en microservices. Les modules sont isolés logiquement, sans la complexité des déploiements distribués.

  • Combiner @Async avec un job store (Quartz, JobRunr), ou utiliser un message broker (RabbitMQ, Kafka) avec Spring Cloud Stream (bonne réponse)
  • Augmenter le timeout HTTP
  • Utiliser des threads simples
  • Faire exécuter la tâche par l'utilisateur
Explication : Pour les tâches longues (rapports, exports), @Async avec un TaskExecutor configuré est une base. Pour la résilience (redémarrage, monitoring), utilisez JobRunr (stockage en base, dashboard, retry) ou un message broker avec Spring Cloud Stream (asynchrone, durable, scalable).
JobRunr s'intègre facilement avec Spring Boot, stocke les jobs en base, et fournit un dashboard de monitoring intégré.

  • Activer les endpoints /actuator/startup (buffered) pour collecter les événements de démarrage et identifier les beans lents (bonne réponse)
  • Un outil externe
  • Regarder les logs
  • Deviner
Explication : Activez l'endpoint startup avec management.endpoint.startup.enabled=true et configurez spring.application.startup. L'endpoint /actuator/startup retourne un arbre détaillé du démarrage (beans, temps d'initialisation) pour identifier les goulots.
Pour Spring Boot 3+, le ApplicationStartup est basé sur les Flight Recorder Events (JFR). Utilisez BufferingApplicationStartup ou JFR pour l'analyse.

  • Séparer les modèles de lecture (Query) et d'écriture (Command) ; utiliser Axon Framework ou des services Spring distincts (bonne réponse)
  • Utiliser une seule base de données pour tout
  • CQRS n'est pas compatible avec Spring
  • Ignorer la séparation des responsabilités
Explication : Le CQRS sépare les opérations de lecture (Query, optimisées pour l'affichage) des opérations d'écriture (Command, optimisées pour la cohérence). Axon Framework est l'implémentation de référence sur Spring. On peut aussi le faire manuellement avec des services et repositories séparés.
CQRS est souvent associé à l'Event Sourcing (Axon). Sans Event Sourcing, une simple séparation des services Command et Query peut suffire.

  • Un module Spring qui expose une API GraphQL via @Controller avec @QueryMapping, @MutationMapping, @SubscriptionMapping (bonne réponse)
  • Un remplacement de REST
  • Un outil de documentation
  • Un framework concurrent de Spring
Explication : Spring for GraphQL (spring-boot-starter-graphql) permet de créer des APIs GraphQL. On définit des @Controller avec @QueryMapping (lecture), @MutationMapping (écriture), @SubscriptionMapping (temps réel). Le schéma GraphQL est auto-généré ou défini en SDL.
Spring GraphQL s'intègre avec Spring Security pour sécuriser les champs. Utilisez @PreAuthorize sur les méthodes de votre contrôleur GraphQL.

  • Utiliser Bucket4j avec un filtre ou un intercepteur, stocker l'état dans Redis pour le distribué, et combiner avec Resilience4j @RateLimiter (bonne réponse)
  • Compter les requêtes dans un fichier
  • Désactiver l'API quand elle est trop utilisée
  • Le rate limiting n'est pas supporté
Explication : Bucket4j implémente l'algorithme Token Bucket et s'intègre avec Spring (filtre HTTP, intercepteur). Pour le distribué, le bucket est stocké dans Redis. Resilience4j fournit @RateLimiter pour limiter les appels à une méthode spécifique.
Pour une API Gateway déjà présente, déléguez le rate limiting à celle-ci (Spring Cloud Gateway + Redis Rate Limiter).

  • Utiliser @DataJpaTest avec Testcontainers pour une base de données éphémère identique à la production (bonne réponse)
  • Toujours utiliser H2 en mémoire
  • Ne pas tester les repositories
  • Mocker tous les appels à la base
Explication : @DataJpaTest configure une slice de test pour JPA. Avec Testcontainers, on démarre une vraie instance PostgreSQL/MySQL dans un conteneur Docker pour le test, garantissant un comportement identique à la production.
Testcontainers + @ServiceConnection (Spring Boot 3.1+) simplifient énormément : Spring démarre automatiquement le conteneur et configure la datasource.

  • Spring Cloud Gateway est réactif (WebFlux/Netty), plus performant que Zuul (bloquant) ; il supporte le routing, les filtres, et le rate limiting (bonne réponse)
  • Les deux sont identiques
  • Zuul est plus récent que Gateway
  • Spring Cloud Gateway est un framework concurrent
Explication : Spring Cloud Gateway est le successeur réactif de Zuul (déprécié). Basé sur WebFlux + Netty, il est non-bloquant. Il offre : routing dynamique, filtres (pré/post), rate limiting (Redis), circuit breaker (Resilience4j), et load balancing (Spring Cloud LoadBalancer).
Remplacez Zuul par Spring Cloud Gateway pour toute nouvelle application. Si vous avez Zuul, migrez vers Gateway.

  • Un module (spring-boot-docker-compose) qui démarre automatiquement les services définis dans docker-compose.yml au lancement de l'application (bonne réponse)
  • Un outil pour construire des images Docker
  • Un remplacement de Docker
  • Un éditeur de fichiers YAML
Explication : Introduit dans Spring Boot 3.1, spring-boot-docker-compose lit le docker-compose.yml et démarre automatiquement les services (bases de données, Redis, Kafka) au lancement de l'application en développement. Plus besoin de scripts séparés.
Ajoutez la dépendance spring-boot-docker-compose (runtime) et définissez vos services dans docker-compose.yml. Ils démarreront et s'arrêteront avec l'application.

  • Chorégraphie (événements entre services) avec Spring Cloud Stream/Kafka ; ou Orchestration (un coordinateur central) avec Axon, Camunda, ou Temporal (bonne réponse)
  • Utiliser des transactions 2PC (Two-Phase Commit)
  • Les transactions distribuées sont impossibles
  • Ignorer la cohérence entre services
Explication : Le pattern SAGA gère les transactions distribuées sans 2PC. Chorégraphie : chaque service publie des événements, les autres réagissent (Eventual Consistency). Orchestration : un coordinateur central gère les étapes et les compensations. Outils : Axon, Camunda, Temporal, ou Kafka + Outbox pattern.
Préférez la chorégraphie pour des workflows simples (faible couplage). Utilisez l'orchestration pour des processus métier complexes (visibilité, compensation explicite).

  • Interface permettant de modifier les beans avant/après initialisation ; cas avancé : créer des proxies dynamiques, injecter des comportements transversaux (bonne réponse)
  • Un outil de build
  • Un type de base de données
  • Un framework de test
Explication : BeanPostProcessor (et son sous-type InstantiationAwareBeanPostProcessor) intercepte la création des beans. Cas avancés : génération de proxies (transactions, cache, AOP), injection de dépendances personnalisées, wrapping de beans avec des décorateurs.
Exemple avancé : créer un BeanPostProcessor qui enveloppe tous les beans annotés @Monitored avec un proxy de métriques automatique.

  • Ajouter Hibernate Envers, annoter les entités avec @Audited, et interroger les tables d'audit (_AUD) pour l'historique (bonne réponse)
  • Logger manuellement chaque changement
  • Stocker les changements dans des fichiers
  • L'audit n'est pas supporté
Explication : Hibernate Envers (intégré à Hibernate) audite automatiquement les entités annotées @Audited. Il crée des tables _AUD pour chaque entité auditée, avec les révisions. On peut interroger l'historique via AuditReader.
Envers stocke automatiquement le numéro de révision, le type de modification (ADD, MOD, DEL) et un snapshot complet de l'entité à chaque changement.

  • JRebel et DCEVM permettent le rechargement à chaud du code sans redémarrage, y compris les changements de structure de classe (bonne réponse)
  • Un simple redémarrage automatique
  • Un outil de build
  • Un framework concurrent
Explication : Spring Boot DevTools redémarre le contexte (rapide mais redémarre). JRebel (commercial) et DCEVM (Dynamic Code Evolution VM, gratuit) permettent de modifier le code (y compris ajout/suppression de méthodes, champs) sans redémarrer la JVM, préservant l'état de l'application.
DCEVM est gratuit et open-source. Installez-le comme un patch sur votre JDK et combinez-le avec l'agent HotswapAgent pour une expérience proche de JRebel.

  • Blue-Green : deux environnements identiques, bascule du trafic via le load balancer. Canary : déploiement progressif (5%, 20%, 100%) avec métriques (bonne réponse)
  • Un seul déploiement pour tout
  • Arrêter l'ancienne version puis démarrer la nouvelle
  • Le déploiement avancé n'est pas compatible avec Spring Boot
Explication : Blue-Green : deux environnements complets, le load balancer bascule tout le trafic vers le vert après validation. Canary : le nouveau déploiement reçoit un pourcentage croissant de trafic, surveillé par des métriques (erreurs, latence). Kubernetes + Istio ou Spring Cloud Gateway facilitent ces stratégies.
Pour le Canary, exposez des métriques Actuator (/actuator/health, /actuator/metrics) à votre service mesh (Istio, Linkerd) pour qu'il décide automatiquement du rollback.

  • @SpringBootTest avec Testcontainers, MockMvc pour les appels HTTP, et awaitility pour tester les flux asynchrones de bout en bout (bonne réponse)
  • Un simple test unitaire
  • Un test manuel
  • Un test Postman
Explication : Pour un test complet : @SpringBootTest(webEnvironment = RANDOM_PORT) avec Testcontainers (base réelle), TestRestTemplate ou MockMvc pour les appels HTTP, et Awaitility pour tester les comportements asynchrones (messages, événements) sans Thread.sleep().
Awaitility est indispensable pour tester les flux asynchrones : await().atMost(5, SECONDS).until(() -> repository.count() == expectedCount).