Spring Boot : Ce qu’il ne fera jamais, mais que tu devras maîtriser quand même

🧙‍♂️ Ce que Spring Boot ne fera jamais à ta place (et pourquoi c’est une bonne nouvelle)

Spring Boot, c’est un peu comme cette voiture automatique hyper agréable à conduire.
Tu démarres sans caler, tout est fluide… jusqu’au jour où tu veux passer la marche arrière en pleine descente sans comprendre pourquoi ça couine.

Beaucoup de développeurs (moi y compris, au début) font confiance aveuglément à Spring Boot. Il faut dire qu’il rend le démarrage d’un projet diablement rapide. Mais à trop s’appuyer sur sa magie, on oublie parfois ce qu’on fait vraiment — et c’est là que les vrais problèmes commencent.

Dans cet article, je partage des cas concrets que j’ai rencontrés ou observés en mission, et qui montrent clairement que :

Spring Boot est ton allié, mais il n’est pas ton coéquipier DevOps, ton mentor Java ni ton testeur QA.

🟢 Ce que Spring Boot fait très bien pour toi

Soyons objectif, voici ce que j’adore dans l’écosystème SpringBoot :

  • spring-boot-starter-* : tu déclares ta dépendance, tu compiles, tu exécutes et ça fonctionne
  • Embedded Tomcat : fini le packaging avec des WARs
  • Auto-configuration : plus besoin de 20 fichiers XML
  • Spring Initializr : démarrer un nouveau projet n’a jamais été aussi rapide
  • Spring Actuator : endpoints de santé, metrics, logs… top pour le monitoring.

Mais c’est justement parce que ça semble si simple qu’on oublie que beaucoup de choses sont implicites.

🔥 Ce que Spring Boot ne fait pas à ta place

1. Comprendre le cycle de vie de ton application

Cas réel : un collègue utilisait @PostConstruct pour initialiser un cache, pensant que tout était prêt à ce moment-là.
Résultat : NullPointerException en production, car certains beans n’étaient pas encore complètement initialisés.

💡 Ce qu’il faut savoir :

  • @PostConstruct est exécuté juste après l’injection des dépendances, mais avant certaines phases d’initialisation des proxys ou d’autres beans dépendants
  • CommandLineRunner et ApplicationRunner sont exécutés après la création complète du contexte Spring, mais leur ordre d’exécution peut varier selon leur priorité
  • Lorsque tes services s’appellent entre eux, il faut veiller à bien gérer la dépendance et l’ordre d’initialisation des beans, notamment pour éviter les boucles ou des états partiellement initialisés

2. Gérer ta configuration de manière fiable

Contexte : une variable spring.datasource.url était bien définie dans le fichier application-dev.yml.
Mais en recette, la variable d’environnement SPRING_DATASOURCE_URL a surchargé la configuration, sans que personne ne s’en rende compte.

Ce que Spring Boot fait :

  • Il fusionne les propriétés provenant de plusieurs sources (fichiers YAML, variables d’environnement, arguments JVM…)
  • Il applique une priorité dans cette fusion, ce qui signifie qu’une valeur peut être silencieusement surchargée par une autre source

🛑Mais il ne t’avertit pas quand une valeur est surchargée

✅ Astuce : utilise l’endpoint Actuator /env pour vérifier la configuration effective en temps réel, et ajoute des logs explicites au démarrage pour les propriétés sensibles.


3. Sécuriser réellement ton application

Oui, spring-boot-starter-security ajoute une page de login par défaut.
Mais non, ça ne sécurise pas forcément ton API REST, ni tes endpoints /actuator, ni tes pages d’erreur.

Exemple :

  • Un dev pensait que ses endpoints étaient protégés car “il avait mis Spring Security”
  • Résultat : tous les endpoints étaient accessibles en GET/POST, sans restrictions ni rôles

✅ Ce que tu dois faire :

  • Configurer explicitement ta SecurityFilterChain avec les règles d’accès pour chaque endpoint
  • Gérer finement les rôles, CORS, CSRF, tokens JWT…
  • Restreindre les accès à /actuator, /swagger-ui, /h2-console selon les environnements

4. Optimiser les performances au démarrage

Un microservice démarrait en 18 secondes, ce qui faisait planter Kubernetes à cause d’un timeout.

Analyse :

  • Trop de classes scannées automatiquement, incluant des packages inutiles
  • Présence de starters inadaptés (spring-boot-starter-jdbc dans un projet MongoDB)
  • Aucun profil actif défini, donc la conf par défaut s’appliquait partout

✅ Astuces :

  • Limite le scan des composants via @ComponentScan(basePackages = {"com.ton.projet"})
  • Exclue les auto-configurations non utilisées avec @SpringBootApplication(exclude = ...)
  • Active un profil par défaut en développement (par exemple spring.profiles.active=dev dans application.properties) pour éviter les comportements imprévus

⚠️ En production, ne mets jamais un profil de développement actif ! Utilise plutôt des profils prod adaptés, avec leurs propres configurations (exemple : application-prod.yml et variables d’environnement associées). Cette séparation claire évite les erreurs de configuration et garantit des performances optimales.

5. Maîtriser les effets des annotations Spring

Spring est un royaume d’annotations, mais elles ne fonctionnent pas toujours comme on l’imagine.

Voici un exemple classique, avec des noms génériques :

@Service
public class OrderService {
    @Transactional
    public void processOrder() {
        // traitement principal
        this.updateInventory(); // pas de rollback si exception ici !
    }

    @Transactional
    public void updateInventory() {
        // mise à jour du stock
    }
}

⚠️ Problème : l’appel interne à updateInventory() ne passe pas par le proxy Spring, donc la gestion transactionnelle annotée n’est pas activée. En cas d’exception dans updateInventory(), la transaction globale ne sera pas annulée.

✅ Bonnes pratiques :

  • Ne pas invoquer à l’intérieur d’une même classe des méthodes annotées @Transactional, car cela contourne la gestion des transactions par Spring
  • Découpler avec des appels externes ou via un événement
  • Vérifier le proxy Spring (via AopContext ou utilitaires Spring)

6. Écrire du code maintenable

Spring Boot permet un développement rapide. Mais ce n’est pas une carte blanche pour faire n’importe quoi.

J’ai vu un projet avec :

  • 4 000 lignes dans la classe principale Application.java
  • Des services qui font aussi office de DAO
  • Des contrôleurs qui manipulent directement du JSON sans sérialisation

Spring ne t’empêche pas cela. Il t’encourage presque, si tu ne mets pas en place toi-même des règles.

✅ Ce que je recommande :

  • Séparer clairement les couches : contrôleurs, services, repositories
  • Documenter ta configuration (README.md, diagrammes d’architecture, fichiers application-example.yml)
  • Documenter aussi tes APIs avec Swagger/OpenAPI ou autre outil adapté
  • Écrire des tests automatisés (unitaires et d’intégration) dès le début

🧩 Checklist personnelle avant livraison

Avant de livrer une appli Spring Boot, je vérifie systématiquement :

  • Tous les endpoints sensibles sont correctement protégés
  • La configuration effective est loggée clairement au démarrage
  • Aucun starter ou auto-configuration inutile n’est présent
  • Les annotations transactionnelles et asynchrones sont bien testées et comprises
  • Un profil prod est défini avec une configuration dédiée
  • L’application démarre en moins de 5 secondes, même en production

🤝 Conclusion

Spring Boot est un excellent outil. Mais ce n’est pas un raccourci vers la qualité.

C’est comme un bon couteau de cuisine : il coupe très bien… mais il faut savoir s’en servir.
En tant que développeur, tu n’as pas le luxe de “faire confiance à la magie”.
Tu dois livrer du code :

  • que tu comprends
  • que tu peux maintenir
  • et que ton client pourra faire évoluer sans toi (car oui, un bon code doit pouvoir être repris par n’importe quel développeur de l’équipe, tu n’es pas indispensable)

💬 Et toi ?

Quels sont les pièges Spring Boot que tu as rencontrés ?
Tu préfères faire quoi “à la main” pour garder le contrôle ?

#java #softwarearchitecture #webdevelopment #springboot #bestpractices

Publications similaires