Java EE / Jakarta EE
Architecture Jakarta EE : conteneurs, profils et serveurs d'applications
Débutant14 min de lectureMis à jour
Cette page a été traduite de l'anglais avec l'aide de l'IA, puis vérifiée par rapport à l'original. Lire la version anglaise
Jakarta EE est un ensemble de spécifications qu'un serveur d'applications implémente pour que votre code s'appuie sur des services gérés au lieu de tout câbler lui-même. À l'issue de ce guide, vous saurez expliquer le modèle de conteneurs, citer les spécifications qui composent Jakarta EE 10 et ses profils, comprendre ce qu'a changé le passage de javax.* à jakarta.*, packager correctement un WAR ou un EAR et choisir entre GlassFish, WildFly, Open Liberty, Payara ou un simple conteneur de servlets.
Ce que vous allez apprendre
- Décrire le modèle multi-tiers et le rôle du conteneur web et du conteneur d'enterprise beans
- Citer les principales spécifications de Jakarta EE 10 et le contenu des profils Platform, Web et Core
- Retracer l'histoire de J2EE à Jakarta EE et la migration de javax.* vers jakarta.*
- Packager une application en WAR ou en EAR et comprendre les noms JNDI portables
- Choisir un serveur d'applications ou un runtime pour un projet neuf ou existant
Toute application serveur un tant soit peu sérieuse a besoin du même lot de services : une façade HTTP, un moyen de parler à une base de données dans une transaction, un modèle de sécurité, un endroit où exécuter des traitements en arrière-plan et une forme de messagerie. Jakarta EE est la réponse standardisée à cette liste sur la plateforme Java. Vous écrivez des composants en vous appuyant sur un ensemble d'API publiées ; un serveur d'applications implémente ces API et fournit les services d'exécution, si bien que votre code ne contient presque plus de plomberie d'infrastructure. Comprendre ce partage des responsabilités — ce que le conteneur fait pour vous et ce qu'il attend de vous — est la base de tout le reste de ce sujet, et éclaire aussi en bonne partie la conception de Spring et de MicroProfile.
De J2EE à Jakarta EE
La plateforme a changé de nom deux fois et ces noms sèment encore la confusion ; mieux vaut donc poser la chronologie.
| Version | Année | Contenu marquant |
|---|---|---|
| J2EE 1.2 – 1.4 | 1999 – 2003 | Servlets, JSP, EJB 1.x/2.x avec interfaces home et descripteurs XML, JMS, JTA, JAX-RPC |
| Java EE 5 | 2006 | Les annotations remplacent la plupart des descripteurs, EJB 3.0, Java Persistence API (JPA) 1.0, JSF 1.2 |
| Java EE 6 | 2009 | CDI 1.0, EJB 3.1 (vue sans interface, singletons), JAX-RS 1.1, Bean Validation, le Web Profile |
| Java EE 7 | 2013 | API simplifiée de JMS 2.0, WebSocket, JSON-P, Batch, Concurrency Utilities, @Transactional de JTA |
| Java EE 8 | 2017 | JSON-B, Java EE Security API 1.0, Servlet 4.0 avec le push HTTP/2, JAX-RS 2.1 |
| Jakarta EE 8 | 2019 | Mêmes API que Java EE 8, désormais gouvernées par la fondation Eclipse ; packages javax.* |
| Jakarta EE 9 / 9.1 | 2020 / 2021 | Espace de noms des packages changé en jakarta.* ; suppression des anciennes API élaguées ; support de Java 11 |
| Jakarta EE 10 | 2022 | Première version à apporter des nouveautés sous Eclipse : CDI 4.0 avec CDI Lite, Core Profile, Servlet 6, Faces 4, Persistence 3.1, REST 3.1 |
| Jakarta EE 11 | 2025 | Java 17 comme socle minimal, Jakarta Data 1.0, nouvel élagage d'API historiques |
Le changement de nom vient de ce qu'Oracle a transféré en 2017 les spécifications et le code de référence à la fondation Eclipse tout en conservant la marque Java. Le préfixe de package javax relevant de cette marque, la communauté n'a eu d'autre choix que de renommer tous les packages. Voilà pourquoi Jakarta EE 9 casse la compatibilité sans apporter la moindre nouveauté : javax.servlet.http.HttpServletRequest est devenu jakarta.servlet.http.HttpServletRequest, javax.persistence.Entity est devenu jakarta.persistence.Entity, et ainsi de suite pour chaque spécification. Les espaces de noms XML des descripteurs de déploiement ont changé en même temps, de http://xmlns.jcp.org/xml/ns/javaee à https://jakarta.ee/xml/ns/jakartaee.
Ce guide cible Jakarta EE 10 et utilise jakarta.* partout. Quand vous lisez des ressources plus anciennes — et la plupart du code Java d'entreprise en production a été écrit pour Java EE 6, 7 ou 8 —, remplacez mentalement le préfixe : les noms de classes et de méthodes sont par ailleurs identiques.
Le modèle en tiers et en conteneurs
Jakarta EE décrit une application comme un ensemble de composants répartis sur des tiers logiques. Ces tiers sont conceptuels : deux d'entre eux partagent souvent le même processus, et dans la plupart des déploiements modernes, tous les tiers côté serveur vivent dans une seule instance de serveur d'applications.
- Tier client — un navigateur, une application mobile, un autre service qui appelle un endpoint REST, ou un client Java de bureau. Pour ce dernier cas, la plateforme définit toujours un conteneur de client applicatif, mais il ne sert plus guère aujourd'hui.
- Tier web — servlets, pages Faces, ressources Jakarta REST et endpoints WebSocket. Ces composants reçoivent les requêtes, les traduisent en appels vers le tier métier et produisent la réponse.
- Tier métier — enterprise beans et beans CDI qui implémentent les cas d'usage, s'exécutent dans des transactions et appliquent les règles de sécurité.
- Tier du système d'information d'entreprise (EIS) — bases de données relationnelles, brokers de messages, mainframes et autres back-ends atteints via JDBC, JMS ou des resource adapters de connecteurs (JCA).
Ce qui en fait plus qu'un simple schéma d'architecture en couches, c'est le conteneur : le runtime qui héberge un type de composant et s'interpose entre ce composant et le monde extérieur. Comme votre servlet ou votre bean est instancié et invoqué par le conteneur, celui-ci peut :
- injecter les dépendances (
@Inject,@EJB,@PersistenceContext,@Resource) avant que votre code ne s'exécute ; - démarrer et valider une transaction autour de chaque méthode métier ;
- vérifier que l'appelant possède le rôle requis ;
- mettre les instances en pool, gérer l'accès concurrent des threads et passiver l'état inactif ;
- appliquer les intercepteurs et les callbacks de cycle de vie (
@PostConstruct,@PreDestroy).
Le conteneur web héberge servlets, filtres, listeners, pages JSP, vues Faces, ressources REST et endpoints WebSocket. Le conteneur d'enterprise beans héberge les session beans et les message-driven beans. Tous deux partagent le conteneur CDI pour l'injection de dépendances et les scopes contextuels, ainsi que des services de plateforme comme le nommage JNDI, les transactions JTA et le sous-système de sécurité. Conséquence pratique : n'instanciez jamais un composant géré avec new. Un new OrderService() est un objet ordinaire, sans champ injecté, sans transaction ni contexte de sécurité ; seules les instances créées par le conteneur en bénéficient.
Ce que le serveur fournit réellement
Un serveur d'applications est le produit qui implémente les spécifications. Les éditeurs se font concurrence sur l'outillage d'administration, le clustering, les performances et le support, pas sur les API avec lesquelles votre code compile. Parmi les services que tout serveur conforme doit fournir :
| Service | Spécification | À quoi il vous sert |
|---|---|---|
| Nommage | JNDI (inclus dans Java SE) | Rechercher par nom des data sources, des destinations JMS et des beans |
| Transactions | Jakarta Transactions | Frontières ACID déclaratives ou programmatiques, y compris XA sur plusieurs ressources |
| Persistance | Jakarta Persistence | Mapping objet-relationnel avec un EntityManager géré par le conteneur |
| Messagerie | Jakarta Messaging | Queues et topics, message-driven beans |
| Web | Servlet, Pages, Faces, REST, WebSocket | Traitement des requêtes HTTP et rendu |
| Injection et scopes | CDI, Dependency Injection | Assemblage des composants, scopes request/session/application, événements |
| Sécurité | Jakarta Security, Authentication, Authorization | Mécanismes d'authentification, identity stores, contrôles de rôles |
| Concurrence | Jakarta Concurrency | Executors gérés et tâches planifiées qui conservent le contexte du conteneur |
| Intégration | Connectors (JCA), Mail | Resource adapters pour les systèmes historiques, envoi d'e-mails |
Les ressources comme les data sources se configurent dans le serveur et sont exposées à votre code via des noms JNDI : le même WAR tourne ainsi en test et en production avec des identifiants différents, sans rebuild. @DataSourceDefinition permet à une application de déclarer sa propre data source, ce qui est pratique pour une démo mais place les identifiants dans le code.
import jakarta.annotation.Resource;
import jakarta.enterprise.context.ApplicationScoped;
import javax.sql.DataSource;
@ApplicationScoped
public class HealthCheck {
// Le conteneur résout ce nom JNDI au moment de l'injection.
@Resource(lookup = "java:/jdbc/OrdersDS")
DataSource dataSource;
public boolean databaseReachable() {
try (var connection = dataSource.getConnection()) {
return connection.isValid(2);
} catch (Exception e) {
return false;
}
}
}
Les profils : Platform, Web et Core
Toutes les applications n'ont pas besoin de tout cela, et imposer un serveur de plateforme complète pour une petite application web est l'une des raisons pour lesquelles Java EE a perdu du terrain face à des stacks plus légères dans les années 2000. Depuis Java EE 6, la plateforme définit des profils, et Jakarta EE 10 en compte trois :
- Jakarta EE Platform — tout.
- Web Profile — le tier web plus ce dont une application web typique a besoin derrière : Servlet, Pages, Expression Language, Faces, CDI, Bean Validation, Persistence, Transactions, REST, JSON-P/JSON-B, WebSocket, Security, Concurrency (ajoutée au profil avec EE 10) et EJB Lite : session beans locaux, transactions gérées par le conteneur, intercepteurs, sécurité déclarative et timers non persistants, mais ni interfaces distantes, ni message-driven beans, ni JMS.
- Core Profile — nouveau dans EE 10, destiné aux frameworks de microservices et à la compilation ahead-of-time : CDI Lite, REST, JSON-P, JSON-B, Annotations, Dependency Injection et Interceptors. MicroProfile s'appuie sur ce profil.
Ce choix détermine votre dépendance Maven. Compilez avec l'artefact d'API du profil visé et laissez le serveur le fournir à l'exécution :
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-web-api</artifactId> <!-- ou jakarta.jakartaee-api pour la plateforme complète -->
<version>10.0.0</version>
<scope>provided</scope>
</dependency>
Le scope provided n'est pas un détail. Si vous embarquez les classes d'API — ou pire, une implémentation comme Hibernate — dans un WAR déployé sur un serveur qui les fournit déjà, vous obtenez des conflits de chargement de classes pénibles à diagnostiquer.
Packaging et déploiement
Les applications Jakarta EE se déploient sous forme d'archives à la structure interne imposée, et le conteneur lit à la fois les annotations et d'éventuels descripteurs XML pour découvrir les composants.
- WAR (web archive) —
WEB-INF/classespour vos classes,WEB-INF/libpour les bibliothèques,WEB-INF/web.xml(facultatif depuis Servlet 3.0),WEB-INF/beans.xml(facultatif avec CDI 4, qui découvre par défaut les beans annotés),META-INF/persistence.xmldansclassespour JPA. Depuis Java EE 6, un WAR peut contenir directement des enterprise beans ; c'est de loin le packaging le plus courant aujourd'hui. - EJB JAR — uniquement des enterprise beans, avec un
META-INF/ejb-jar.xmlfacultatif. - EAR (enterprise archive) — une enveloppe contenant des WAR, des EJB JAR, des resource adapters (RAR) et des bibliothèques partagées dans
lib/, décrite parMETA-INF/application.xml. Ne l'utilisez que si plusieurs modules doivent réellement partager des bibliothèques et être déployés comme une seule unité ; il complique le chargement des classes et la plupart des équipes n'en ont plus besoin.
L'en-tête d'un web.xml Servlet 6.0 montre l'espace de noms et la version actuels :
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
version="6.0">
<session-config>
<session-timeout>30</session-timeout>
</session-config>
</web-app>
Les descripteurs priment sur les annotations : c'est la manière prévue de modifier des réglages propres à un environnement — une contrainte de sécurité, un paramètre d'initialisation de servlet, un timeout de session — sans toucher au code source.
Les noms JNDI portables
Depuis Java EE 6, chaque session bean reçoit des noms JNDI standard, ce qui permet de le rechercher depuis n'importe où sans syntaxe propre à un éditeur :
java:global/<app-name>/<module-name>/<bean-name>[!<fully-qualified-interface>]
java:app/<module-name>/<bean-name>
java:module/<bean-name>
Pour un bean OrderService dans shop.war déployé seul, le nom global est java:global/shop/OrderService. L'espace de noms java:comp/env contient les entrées d'environnement propres au composant (points d'injection @Resource), et java:comp/UserTransaction et java:comp/DefaultDataSource sont des entrées standard que tout serveur fournit. L'injection a rendu les lookups explicites rares, mais vous en croiserez encore dans du code ancien et dans les clients distants.
Choisir un serveur ou un runtime
Tous les produits compatibles Jakarta EE 10 passent le même Technology Compatibility Kit : le comportement des API est donc identique, et les différences sont d'ordre opérationnel.
| Produit | Profil | Remarques |
|---|---|---|
| Eclipse GlassFish 7 | Platform | L'implémentation compatible utilisée pour ratifier les spécifications ; pratique pour apprendre, moins répandue en production |
| WildFly (27+) | Platform | Le serveur communautaire de Red Hat, base de JBoss EAP ; propose aussi un feature pack « preview » et un packaging en bootable JAR |
| Open Liberty | Platform | Le runtime modulaire d'IBM ; les fonctionnalités s'activent par application, démarrage rapide, base de WebSphere Liberty |
| Payara Server / Micro | Platform | Dérivé de GlassFish avec support commercial ; Payara Micro exécute un WAR depuis la ligne de commande |
| Apache TomEE 10 | Variantes Web Profile / Platform | Tomcat plus OpenEJB, OpenJPA/Hibernate, ActiveMQ, CXF |
| Apache Tomcat 10.1 / Jetty 12 | Servlet, Pages, EL, WebSocket seulement | Pas des serveurs Jakarta EE ; vous apportez le reste sous forme de bibliothèques |
En pratique, le choix dépend de ce que votre équipe d'exploitation fait déjà tourner et maintient à jour, de votre besoin ou non d'un support commercial (JBoss EAP, WebSphere Liberty et Payara Enterprise sont les éditions supportées de WildFly, Open Liberty et Payara), et de votre mode de déploiement : tous ces serveurs peuvent être intégrés à une image de conteneur avec l'application, et le bootable JAR de WildFly ou Payara Micro produisent un exécutable unique, un peu comme un jar Spring Boot. Si vous n'utilisez que les servlets, JPA et REST, un runtime Web Profile — ou Tomcat accompagné de bibliothèques — peut être la réponse pragmatique.
La place de Spring et de MicroProfile
Spring est né en 2003 en réaction à EJB 2.x, dont les interfaces home, les exceptions checked obligatoires et les descripteurs XML rendaient laborieuses les choses simples. Java EE 5 et 6 ont repris l'essentiel des idées de Spring — annotations, injection de dépendances, composants en objets ordinaires — dans EJB 3 et CDI. Aujourd'hui, la relation relève de la symbiose plus que de la concurrence : Spring Framework 6 et Spring Boot 3 dépendent des API Jakarta EE 9+ pour la couche servlet, JPA, Bean Validation, JMS et JTA, et fournissent simplement leur propre conteneur au lieu de s'appuyer sur un serveur d'applications. Si vous comprenez les spécifications, vous comprenez une bonne partie de ce que Spring auto-configure ; le sujet Spring couvre ce versant.
MicroProfile est un ensemble voisin de spécifications Eclipse qui ajoute, au-dessus du Core Profile, ce dont les services cloud-native ont besoin — configuration, health checks, métriques, OpenAPI, client REST, tolérance aux pannes, propagation de JWT — et qu'implémentent Open Liberty, Payara, WildFly, Quarkus et Helidon. Ce que vous savez de CDI et de Jakarta REST vous resservira avec chacun d'eux.
Migrer de javax à jakarta
Le renommage de Jakarta EE 9 étant mécanique, l'outillage peut en faire l'essentiel :
Mettre à niveau le runtime et la dépendance d'API
Passez à un serveur Jakarta EE 9.1+ (ou Tomcat 10.1+, Jetty 11+) et faites passer la dépendancejakarta.jakartaee-api(ou les dépendances par spécification) à une version 9.1 ou 10.Réécrire les imports et les descripteurs
Lancez Eclipse Transformer ou une recette OpenRewrite sur l'arborescence des sources. Ils réécrivent les importsjavax.*des packages concernés, les espaces de noms XML et les noms de propriétés commejavax.persistence.jdbc.url, sans toucher aux packages Java SE commejavax.sqletjavax.naming, qui n'ont jamais bougé.Mettre à jour chaque bibliothèque qui touche aux API
Hibernate 6, Jersey 3, RESTEasy 6, Mojarra 4, EclipseLink 4 et Spring 6 sont les lignes basées sur l'espace de noms Jakarta. Une seule dépendance transitive qui importe encorejavax.servletéchouera à l'exécution avecNoClassDefFoundError: passez l'arbre des dépendances au crible.Traquer les API supprimées
Servlet 6.0 a supprimé des types dépréciés de longue date commeSingleThreadModeletHttpSessionContext; Faces 4.0 a supprimé@ManagedBeanet les vues JSP ; Enterprise Beans 4.0 a abandonné les entity beans EJB 2.x et les endpoints JAX-RPC. Le code qui les utilise doit être réécrit, pas simplement réimporté.
Le guide de migration de Tomcat décrit une variante de la même démarche : Tomcat 10 sait transformer à la volée les WAR historiques, ce qui fait gagner du temps mais ne doit pas devenir la solution durable.
Erreurs courantes
- Embarquer une implémentation que le serveur fournit déjà. Packager
hibernate-coreou une implémentation de Jakarta REST dans un WAR destiné à WildFly ou Liberty produit deux copies des mêmes classes dans des class loaders différents, et des erreurs commeClassCastException: OrderEntity cannot be cast to OrderEntity. Utilisez le scopeprovidedpour les API et laissez le serveur fournir les implémentations, sauf si sa documentation explique comment remplacer sa version. - Mélanger des artefacts
javaxetjakarta. Un projet à moitié migré compile, puis échoue au déploiement. Fouillez l'arbre des dépendances, pas seulement vos propres imports. - Traiter les tiers comme physiques. Séparer le tier web et le tier métier sur des serveurs distincts reliés par des appels distants d'enterprise beans était à la mode à l'époque de J2EE ; c'est presque toujours plus lent et plus difficile à exploiter qu'un seul processus. Gardez-les ensemble, sauf si des mesures justifient le contraire.
- Configurer les ressources dans l'application. Des URL de connexion codées en dur dans
persistence.xmlou@DataSourceDefinitionfonctionnent sur un poste de développement, puis font fuiter des identifiants dans le gestionnaire de versions. Définissez data sources et destinations JMS dans le serveur et référencez-les par leur nom JNDI. - Utiliser un EAR par habitude. Un WAR unique est plus simple à construire, à déployer et à déboguer. Ne recourez à un EAR que si plusieurs modules doivent être versionnés ensemble.
Points clés à retenir
- Jakarta EE est un ensemble de spécifications ; un serveur d'applications les implémente et exécute vos composants dans des conteneurs qui injectent les dépendances, gèrent les transactions et appliquent la sécurité.
- La filiation : J2EE, puis Java EE 5 à 8, puis Jakarta EE 8 (mêmes API), 9 (
javax.*devientjakarta.*, aucune nouveauté), 10 (première version à en apporter) et 11. - Jakarta EE 10 définit trois profils — Platform, Web et Core — pour ne cibler que ce dont vous avez besoin ; le Web Profile couvre la plupart des applications web.
- Compilez avec l'artefact
jakarta.jakartaee-apioujakarta.jakartaee-web-apien scopeprovidedet laissez le serveur fournir les implémentations. - Packagez en WAR dès que possible ; utilisez les noms JNDI portables
java:globalet des ressources définies côté serveur plutôt qu'une configuration codée en dur. - GlassFish, WildFly, Open Liberty, Payara et TomEE sont des implémentations compatibles ; Tomcat et Jetty n'implémentent que la famille Servlet.
- Spring et MicroProfile reposent sur les mêmes spécifications : les connaissances se transfèrent dans les deux sens.
Sources et lectures complémentaires
Questions fréquentes
- Jakarta EE, est-ce la même chose que Java EE ?
- C'est la suite de Java EE sous l'égide de la fondation Eclipse. Jakarta EE 8 est fonctionnellement identique à Java EE 8 et utilise encore les packages javax.*. À partir de Jakarta EE 9, les packages sont passés à jakarta.*, ce qui explique pourquoi les bibliothèques et serveurs écrits pour Java EE 8 ne tournent pas tels quels sur un serveur Jakarta EE 9 ou plus récent.
- Ai-je besoin d'un serveur d'applications, ou Tomcat suffit-il ?
- Tomcat et Jetty n'implémentent que les spécifications Servlet, JSP, EL et WebSocket. Si vous attendez du conteneur lui-même CDI, JPA, JTA, JMS, les enterprise beans ou Jakarta REST, prenez un serveur Web Profile ou Platform complet comme WildFly, Open Liberty, Payara, GlassFish ou TomEE. Des frameworks comme Spring Boot embarquent leurs propres implémentations de plusieurs de ces spécifications et peuvent donc tourner sur Tomcat.
- Quelle différence entre le Web Profile et la Platform complète ?
- Le Web Profile est un sous-ensemble destiné aux applications web : servlets, Faces, CDI, JPA, JTA, Bean Validation, Jakarta REST, JSON, WebSocket, Security, Concurrency et un jeu réduit de fonctionnalités d'enterprise beans appelé EJB Lite. La Platform complète y ajoute la messagerie (JMS), les connecteurs, Mail, Batch, les beans distants et message-driven, entre autres. Le Core Profile, apparu avec Jakarta EE 10, est encore plus réduit et vise les runtimes de microservices.
- Un nouveau projet doit-il partir sur Jakarta EE ou sur Spring Boot ?
- Les deux se défendent. Jakarta EE vous apporte des standards indépendants des éditeurs, un runtime géré et moins de code de framework dans votre application ; Spring Boot offre un écosystème plus large, un rythme de versions plus soutenu et un packaging autonome plus simple. Spring 6 repose lui-même sur les API Jakarta EE 9+ (Servlet, JPA, Bean Validation) : les spécifications que vous apprenez ici se transposent donc directement.