Nehos Groupe

L'essentiel sur la migration Java legacy vers Spring Boot 3

Java 8 a atteint la fin de son support public Oracle en mars 2022 (le support étendu payant continue jusqu'en 2030). Java 11 est en fin de support public depuis septembre 2023. Spring Framework 5.3.x (dernière branche 5.x) est en fin de support open-source depuis décembre 2024. J2EE (Java EE 8 et antérieur) est remplacé par Jakarta EE sous la gouvernance Eclipse Foundation depuis 2019 — les applications J2EE déployées sur des serveurs d'applications traditionnels (WebSphere, JBoss EAP, WebLogic) utilisent des APIs en fin de vie. En 2026, maintenir des applications Java sur ces stacks legacy cumule des risques de sécurité (CVEs non corrigées sur les anciennes versions), des coûts d'infrastructure élevés (licences serveurs d'applications, hardware dédié), et une dette technique croissante.

Spring Boot 3 (basé sur Spring Framework 6) + Java 21 est la cible de modernisation naturelle pour les applications Java legacy. Spring Boot 3 apporte : le passage de javax.* à jakarta.* (namespace Jakarta EE 9+), la compatibilité native Java 17 à 21 (records, sealed classes, pattern matching, Virtual Threads), le support GraalVM Native Image (compilation AOT pour démarrage en millisecondes), Spring Observability intégrée (Micrometer + OpenTelemetry), et l'abandon des serveurs d'applications traditionnels au profit d'un Tomcat/Jetty/Undertow embarqué dans un JAR autonome.

Deux stratégies de migration chez Nehos. (a) Migration incrémentale : mise à jour progressive du Spring Framework (3 → 4 → 5 → 6/Spring Boot 3), de Java (8 → 11 → 17 → 21), et des dépendances, sans réécriture fonctionnelle. Adaptée aux applications bien structurées avec une séparation claire des couches. (b) Réécriture partielle guidée : réécriture des modules les plus dégradés en Spring Boot 3 natif, migration incrémentale des modules sains. Adaptée aux applications avec une dette technique concentrée dans certains modules.

Tarification selon scope : 212 k€ HT pour une application Java de 50 000 à 100 000 lignes (migration incrémentale, 4 à 6 mois), jusqu'à partir de 51 k€ HT pour un système Java distribué complexe (multiple applications J2EE, serveurs d'applications multiples, 12 à 18 mois). L'audit initial (8 à 15 jours, à partir de 1 113 € HT) est déductible du projet complet si engagement dans les 60 jours.

Migration Java Legacy → Spring Boot 3 — Modernisez votre Backend sans Réécrire depuis Zéro

Vos applications Java tournent encore sur Spring 3/4, J2EE (WebSphere, JBoss), ou Java 8/11. Les serveurs d'applications sont lourds, les déploiements manuels, les tests rares, et le recrutement de développeurs familiers avec ces stacks vieillissantes devient un défi. Nehos migre vos applications Java legacy vers Spring Boot 3 + Java 21 : migration progressive module par module, passage de WAR/EAR sur serveur d'applications vers JAR autonome, conteneurisation Docker/Kubernetes, Virtual Threads, CI/CD GitHub Actions. 0 downtime. 212 k€ HT.

Adapté à toute taille de structure

Artisan
Startup
PME / TPE
ETI
Grand Groupe

#Applications Java Legacy en 2026 — État des Lieux Technique

Le terme 'Java legacy' couvre un spectre large de situations techniques. Chez Nehos, nous intervenons sur trois profils d'applications Java legacy qui représentent la majorité des cas rencontrés chez les ETI et grands comptes français.

#Profil 1 — Applications Spring 3/4 sur Java 8

Ces applications ont été développées entre 2012 et 2018 avec Spring Framework 3.x ou 4.x, souvent avec Spring MVC + JSP ou Thymeleaf côté frontend, Spring Data JPA + Hibernate côté persistance, et un déploiement en WAR sur Tomcat 7/8. Elles tournent sur Java 8 (OpenJDK ou Oracle JDK) et utilisent Maven comme build tool. Le problème principal : Spring 4.3.x est en fin de support depuis décembre 2020. Spring 5.3.x (dernière branche supportée avant Spring 6) est en fin de support open-source depuis décembre 2024. Java 8 public updates par Oracle se sont arrêtées en mars 2022. Ces applications fonctionnent toujours mais ne reçoivent plus de patches de sécurité sur le framework, et sont bloquées sur des versions de Java qui ne bénéficient plus des améliorations majeures (Virtual Threads Java 21, ZGC generational, pattern matching).

#Profil 2 — Applications J2EE sur serveur d'applications

Ces applications plus anciennes (2005-2015) utilisent les APIs J2EE/Java EE : EJB (Enterprise JavaBeans), JMS (Java Message Service), JNDI (Java Naming and Directory Interface), JSF (JavaServer Faces), JPA via le serveur d'applications. Elles sont déployées en EAR sur WebSphere (IBM), JBoss EAP/WildFly (Red Hat), ou WebLogic (Oracle). Le coût de ces serveurs d'applications est significatif : licences IBM WebSphere typiquement à partir de 928 €/an par serveur, Oracle WebLogic à partir de 873 €/an, sans compter le coût d'exploitation (administrateurs spécialisés, hardware dédié, processus de déploiement lourds). La migration vers Spring Boot 3 élimine ces coûts de licence.

#Profil 3 — Systèmes distribués Java hétérogènes

Les systèmes les plus complexes combinent plusieurs applications Java de générations différentes : un backend Spring 3 ici, un batch J2EE là, une API Spring 4 ailleurs, le tout communiquant via JMS, SOAP, fichiers partagés, ou base de données partagée. La migration de ces systèmes nécessite une approche globale (cartographie des flux, priorisation des composants) avant toute intervention technique.

#De javax.* à jakarta.* — Le Changement de Namespace

Le changement le plus visible lors de la migration vers Spring Boot 3 est le passage du namespace javax.* vers jakarta.*. Ce changement, conséquence du transfert de Java EE à Jakarta EE (Eclipse Foundation), impacte l'ensemble du code : javax.persistencejakarta.persistence, javax.servletjakarta.servlet, javax.validationjakarta.validation, javax.injectjakarta.inject, javax.transactionjakarta.transaction.

Ce n'est pas un simple find-and-replace. Les dépendances tierces (Hibernate, Jersey, Jackson, etc.) doivent également être mises à jour vers des versions compatibles jakarta.. Certaines librairies anciennes n'ont pas de version jakarta. — elles doivent être remplacées. Les tests existants (si présents) doivent être adaptés. Les fichiers de configuration XML (persistence.xml, web.xml) doivent référencer les nouveaux namespaces.

Chez Nehos, nous utilisons OpenRewrite (outil d'automatisation de refactoring Java) pour effectuer ce changement de namespace de manière automatisée et sûre. Les recipes OpenRewrite org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_0 effectuent le gros du travail de migration mécanique (namespace, dépendances Maven/Gradle, propriétés application.properties). Le travail humain se concentre sur les cas non automatisables : librairies sans équivalent jakarta, code custom qui interagit directement avec les APIs J2EE, configuration XML complexe.

#Migration Java 8/11 → Java 21 — Gains Concrets

La migration de version Java est un volet technique distinct qui peut être conduit avant, pendant, ou après la migration Spring. Java 21 (LTS, sorti en septembre 2023) apporte des gains significatifs par rapport à Java 8 et 11.

#Virtual Threads (Project Loom)

Les Virtual Threads sont la fonctionnalité la plus impactante de Java 21 pour les applications serveur. Avant Java 21, chaque requête HTTP était traitée par un thread OS (lourd : ~1 Mo de stack par thread, context switching coûteux). Le pool de threads Tomcat était limité à 200-400 threads, ce qui imposait une limite de concurrence. Avec les Virtual Threads, chaque requête est traitée par un thread virtuel (léger : quelques Ko, géré par le runtime Java, pas de context switching OS). Le serveur peut traiter des dizaines de milliers de requêtes concurrentes sans augmenter la consommation mémoire. Spring Boot 3.2+ active les Virtual Threads avec une simple propriété : spring.threads.virtual.enabled=true. Sur nos migrations, le gain de throughput sous charge est typiquement de 40 à 200 % selon le profil I/O de l'application (les applications avec beaucoup d'appels externes — BDD, APIs, fichiers — bénéficient le plus).

#Records, Sealed Classes, Pattern Matching

Java 21 apporte des fonctionnalités de langage qui améliorent la lisibilité et la maintenabilité du code. Les Records remplacent les POJOs verbeux (plus besoin de getters, setters, equals, hashCode, toString — un record est déclaré en une ligne). Les Sealed Classes permettent de restreindre les implémentations d'une interface (utile pour les types algébriques et le Domain-Driven Design). Le Pattern Matching simplifie les switch statements et les instanceof checks. Ces fonctionnalités ne sont pas juste du confort syntaxique — elles réduisent le boilerplate de 30 à 50 % sur le code métier et les DTOs.

#Performance du runtime

Chaque version LTS de Java apporte des améliorations de performance du runtime. De Java 8 à Java 21, les gains cumulés sont significatifs : G1 garbage collector amélioré (pauses GC réduites de 40 à 60 %), ZGC generational (pauses GC sub-milliseconde, adapté aux applications à faible latence), JIT compiler optimisé (throughput amélioré de 10 à 20 % sur du code computationnel), startup time réduit avec CDS (Class Data Sharing). Sans toucher une ligne de code applicatif, la migration de Java 8 vers Java 21 améliore les performances du runtime.

#De WAR/EAR sur Serveur d'Applications → JAR Autonome Spring Boot

Le passage d'un déploiement WAR/EAR sur serveur d'applications (WebSphere, JBoss, WebLogic, Tomcat standalone) vers un JAR autonome Spring Boot est un changement architectural structurant.

Avec un WAR sur serveur d'applications, le cycle de déploiement implique de packager l'application en WAR/EAR, de la déployer sur le serveur d'applications via une console d'administration (souvent manuelle), de configurer les datasources, les pools de connexions, les JMS queues, les JNDI resources dans le serveur d'applications, de gérer les mises à jour du serveur d'applications lui-même (patches, versions majeures). Les serveurs d'applications sont des logiciels complexes qui nécessitent des administrateurs spécialisés.

Avec un JAR Spring Boot, l'application est un exécutable autonome qui embarque son propre serveur (Tomcat, Jetty, ou Undertow). Le déploiement est un java -jar application.jar. La configuration est dans application.yml et les variables d'environnement. Le packaging est reproductible via Maven/Gradle. Le JAR peut être conteneurisé dans une image Docker de 100 à 200 Mo (vs une installation WebSphere de plusieurs Go). Le déploiement peut être automatisé via CI/CD (GitHub Actions → Docker build → push registry → deploy Kubernetes). Plus besoin de licences serveur d'applications. Plus besoin d'administrateurs WebSphere/WebLogic dédiés.

#Conteneurisation Docker/Kubernetes

La migration vers Spring Boot 3 est l'occasion naturelle de conteneuriser l'application. Un JAR Spring Boot est trivial à conteneuriser : un Dockerfile de 10 lignes avec un JRE Java 21 slim comme image de base, le JAR copié, un ENTRYPOINT java -jar. Spring Boot 3 offre aussi la construction d'images OCI via Buildpacks (./gradlew bootBuildImage ou ./mvnw spring-boot:build-image) — sans Dockerfile.

Pour les organisations qui opèrent sur Kubernetes, la conteneurisation apporte : le scaling horizontal automatique (HPA basé sur CPU, mémoire, ou métriques custom), les health checks natifs Spring Actuator (/actuator/health, /actuator/readiness, /actuator/liveness) mappés sur les probes Kubernetes, le déploiement blue/green ou canary via les Deployments et Services Kubernetes, la gestion des secrets via Kubernetes Secrets ou Vault, le logging centralisé via stdout (pattern 12-factor) capturé par Fluentd/Loki.

Pour les organisations qui ne sont pas prêtes pour Kubernetes, la conteneurisation Docker seule (Docker Compose en production, ou Docker sur VM) apporte déjà la reproductibilité des environnements, l'isolation des applications, et la simplification du déploiement.

#Observabilité — Spring Boot Actuator + Micrometer + OpenTelemetry

Les applications Java legacy sont typiquement opaques en termes d'observabilité : pas de métriques exposées, logs en fichiers texte sur le filesystem du serveur, pas de traces distribuées. Spring Boot 3 intègre nativement une stack d'observabilité complète.

Spring Boot Actuator expose des endpoints HTTP pour le health check, les métriques JVM (heap, threads, GC), les métriques custom applicatives, et les informations de build. Micrometer (intégré dans Spring Boot 3) est une façade de métriques compatible avec Prometheus, Grafana, Datadog, New Relic. OpenTelemetry (supporté nativement depuis Spring Boot 3.2 via Micrometer Tracing) ajoute les traces distribuées — indispensable pour debugger les systèmes distribués (microservices, appels inter-services).

La mise en place de l'observabilité pendant la migration est stratégique : elle permet de comparer les performances avant/après migration, de détecter les régressions de performance pendant la migration, et de donner aux équipes ops une visibilité sur le système qu'elles n'avaient jamais eue avec la stack legacy.

#Migration de la Couche Persistance — JPA/Hibernate Upgrade

La couche persistance (JPA + Hibernate) évolue significativement entre les versions legacy et Spring Boot 3. Hibernate 5 (utilisé avec Spring 4/5) → Hibernate 6 (utilisé avec Spring Boot 3) apporte un nouveau query parser (SQM — Semantic Query Model), une gestion améliorée des types SQL, et des changements dans la gestion du cache de second niveau.

Points d'attention lors de la migration Hibernate 5 → 6. Le type GenerationType.AUTO change de comportement (passage de SEQUENCE à TABLE sur certaines bases). Les requêtes HQL/JPQL peuvent retourner des types différents (Integer vs Long dans certains cas). Le cache de second niveau nécessite une reconfiguration. Les named queries avec des paramètres positionnels doivent être converties en paramètres nommés. OpenRewrite gère automatiquement une partie de ces changements, le reste nécessite des tests d'intégration approfondis.

Pour les applications qui utilisent encore JDBC brut ou iBatis/MyBatis, la migration est l'occasion d'évaluer le passage à Spring Data JPA — mais pas systématiquement. Si le modèle de données est complexe (requêtes SQL optimisées manuellement, procédures stockées, vues matérialisées), garder du SQL natif via JdbcTemplate ou JdbcClient (nouveau dans Spring 6.1) est pragmatique.

#Méthodologie Nehos — Phases et Calendrier

Phase 0 — Audit codebase Java (8 à 15 jours, à partir de 1 113 € HT déductibles). Inventaire des applications Java (versions Java, Spring, serveurs d'applications, bases de données). Cartographie des dépendances (Maven/Gradle dependency tree, BOM analysis). Analyse de la complexité de migration (utilisation des APIs J2EE, extensions propriétaires serveur d'applications). Mesure de la couverture de tests existante. Évaluation de l'infrastructure actuelle vs cible. Output : plan de migration application par application, estimation T-shirt, recommandation d'approche (incrémentale vs réécriture partielle).

Phase 1 — Socle Spring Boot 3 (3 à 4 semaines). Initialisation du projet Spring Boot 3 (Java 21, Gradle ou Maven, Spring Initializr). Configuration CI/CD (GitHub Actions : build, tests JUnit/Mockito, analyse SonarQube, build Docker, deploy staging). Mise en place de l'observabilité (Actuator + Micrometer + Grafana). Configuration des environnements (dev, staging, production) avec profils Spring.

Phase 2 — Migration incrémentale (8 à 40 semaines selon complexité). Sprints de 2 semaines. Migration Java version par version si nécessaire (8 → 11 → 17 → 21 — chaque saut est testable indépendamment). Migration Spring (remplacement namespace javax → jakarta via OpenRewrite, mise à jour des dépendances). Migration de la couche persistance (Hibernate upgrade, test des requêtes). Migration des modules applicatifs (controllers, services, repositories). Conteneurisation progressive (Dockerfile, Docker Compose, puis Kubernetes si applicable).

Phase 3 — Décommission infrastructure legacy (2 à 4 semaines). Bascule des flux de production vers Spring Boot 3. Arrêt des serveurs d'applications legacy. Tests de charge et validation performance. Documentation architecture et formation équipes.

#ROI — Cas ETI Assurance Java J2EE → Spring Boot 3

Cas client de référence : ETI assurance, système de gestion des sinistres en Java EE (EJB 3 + JSF + JPA sur JBoss EAP 7), 120 000 lignes de code, en production depuis 2012, 400 utilisateurs internes. Enjeux initiaux : coût licence JBoss EAP2 12 800 €/an, déploiements manuels (1 release par mois, 4 heures de downtime par déploiement), Java 11 bloqué (incompatibilités JBoss EAP), temps de démarrage application 4 minutes, aucune métrique d'observabilité.

Mission Nehos : migration vers Spring Boot 3 + Java 21 sur 10 mois. Audit Phase 0 (12 jours). Socle Spring Boot 3 + CI/CD (4 semaines). Migration incrémentale 8 modules en 16 sprints (8 mois). Conteneurisation Docker + déploiement Kubernetes (inclus dans la phase 2). Décommission JBoss EAP (2 semaines). Investissement total : à partir de 24 k€ HT. Résultats à 6 mois post-bascule : licence JBoss EAP éliminée (-2 12 800 €/an), déploiements automatisés CI/CD (de 1 release/mois à 3 releases/semaine, 0 downtime), temps de démarrage application de 4 minutes à 12 secondes (JAR Spring Boot), throughput sous charge +85 % (Virtual Threads Java 21), observabilité complète (Grafana dashboards, alertes Prometheus), couverture de tests de 8 % à 62 %.

#Tarification — 212 k€ HT

Application Java simple (50 000 à 100 000 lignes, Spring 4/5, migration incrémentale vers Spring Boot 3) : 40 à 611 k€ HT sur 4 à 6 mois.

Application J2EE intermédiaire (100 000 à 200 000 lignes, J2EE/Java EE sur serveur d'applications, migration avec refactoring partiel) : 161 k€ HT sur 6 à 10 mois.

Système Java distribué complexe (200 000+ lignes, multiple applications, multiples serveurs d'applications, intégrations lourdes) : 23,5 k€ HT sur 10 à 18 mois.

Tous les tarifs incluent l'audit initial Phase 0. Estimation précise en 30 minutes via RDV : Calendly migration Java.

Questions & Réponses

Questions fréquentes sur la migration Java legacy vers Spring Boot 3

La migration peut être conduite en saut direct, mais nous recommandons une approche par étapes pour réduire le risque. En pratique, chaque saut de version majeure (Spring 3 → 4, Spring 4 → 5, Spring 5 → 6/Boot 3) apporte son lot de breaking changes. En passant par étapes, chaque version intermédiaire est testable indépendamment — si un test échoue, on sait exactement quel changement de version l'a causé. Les outils comme OpenRewrite automatisent une grande partie des migrations mécaniques (namespaces, APIs dépréciées, configuration), ce qui accélère les étapes intermédiaires. Pour une application bien structurée avec une couverture de tests existante, la migration complète Spring 3 → Spring Boot 3 prend typiquement 8 à 12 semaines de travail effectif.
Oui — et c'est l'un des gains majeurs. Spring Boot 3 embarque son propre serveur HTTP (Tomcat, Jetty, ou Undertow) dans le JAR applicatif. Vous n'avez plus besoin de WebSphere, JBoss EAP, WebLogic, ou d'un Tomcat standalone. L'application se lance avec un simple `java -jar`. Cela élimine les coûts de licence (souvent à partir de 928 €/an par serveur pour les serveurs d'applications commerciaux), simplifie le déploiement (plus besoin d'administrateurs serveur d'applications spécialisés), et ouvre la porte à la conteneurisation Docker/Kubernetes. Pour les organisations attachées à un serveur d'applications spécifique pour des raisons de conformité ou d'architecture, Spring Boot 3 peut techniquement être déployé en WAR sur Tomcat externe — mais on perd la plupart des avantages.
Dans la majorité des cas, oui. Les Virtual Threads sont compatibles avec l'écosystème Java existant — les librairies qui utilisent des appels bloquants (JDBC, HTTP clients, file I/O) bénéficient automatiquement des Virtual Threads sans modification de code. Quelques cas d'attention : les librairies qui utilisent des `synchronized` blocks longs (pinning du thread porteur), les pools de connexions qui doivent être dimensionnés différemment (HikariCP avec Virtual Threads peut gérer plus de connexions concurrentes), et les librairies natives (JNI) qui ne supportent pas le pinning. Spring Boot 3.2+ gère ces cas via une configuration adaptée. L'audit Phase 0 identifie les librairies problématiques dans votre stack.
Les gains de performance sont significatifs et mesurables. Trois facteurs se cumulent. (1) Java 21 vs Java 8/11 : améliorations du garbage collector (G1 amélioré, ZGC generational), du JIT compiler, et des APIs standard — gain de throughput typique de 10 à 25 % sans toucher au code applicatif. (2) Virtual Threads : gain de throughput sous charge de 40 à 200 % pour les applications I/O-bound (appels BDD, APIs externes, fichiers). (3) Spring Boot 3 : temps de démarrage réduit (Spring AOT processing), empreinte mémoire optimisée, auto-configuration plus efficace. Sur le cas ETI assurance, le throughput sous charge a augmenté de 85 % et le temps de démarrage est passé de 4 minutes à 12 secondes. Les gains exacts dépendent du profil de l'application — l'audit Phase 0 inclut un benchmark préliminaire.
Techniquement, oui — n'importe quelle application Java peut être conteneurisée dans un Docker. Mais en pratique, conteneuriser une application J2EE sur WebSphere dans un Docker revient à embarquer un serveur d'applications complet dans un container de plusieurs Go, avec des temps de démarrage de plusieurs minutes et une complexité de configuration préservée. Le vrai gain de la conteneurisation vient avec Spring Boot : un JAR autonome dans une image Docker de 100-200 Mo, démarrage en secondes, configuration par variables d'environnement, health checks Actuator natifs. La migration Spring Boot 3 et la conteneurisation sont deux chantiers complémentaires que nous conduisons en parallèle. Voir [Monolithe → Microservices](/services/legacy-modernization/monolithe-microservices) pour les architectures distribuées.
Les procédures stockées et le SQL natif ne sont pas un blocage — Spring Boot 3 les supporte pleinement. Spring Data JPA permet d'appeler des procédures stockées via l'annotation `@Procedure` et d'exécuter du SQL natif via `@Query(nativeQuery = true)`. Le nouveau `JdbcClient` de Spring 6.1 offre une API fluide pour le SQL natif sans ORM. Notre recommandation : ne pas forcer la migration des procédures stockées vers du JPA/Hibernate si elles fonctionnent et sont optimisées. On migre l'enveloppe applicative (framework, build, déploiement) et on garde le SQL optimisé tel quel. La réécriture des procédures stockées en logique applicative Java n'est envisagée que si elles posent des problèmes de maintenance ou de testabilité.
Réserver un audit