Spring-Boot
Senior
Quiz-Springboot-Senior
Microservices
Spring-Cloud
Eureka
Feign
Oauth2
Webflux
Kafka
Observabilite
Questions-Entretien-Spring-Senior
Qcm-Springboot-Avance
Java
📝
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.
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.
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.
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é.
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.
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.
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).
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.
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).
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>.
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.
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.
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.
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.
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.
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.
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.
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.
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é.
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.
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.
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.
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).
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.
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.
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.
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).
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.
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.
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.
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.
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).