Présentation du TD⚓︎
Dans les TD5 et TD6, nous avons vu comment mettre en place une architecture 3 tiers de ce type :
Notre application est fonctionnelle, mais comme nous l'avions indiqué au tout début de ce cours, il faut toujours penser en terme de réutilisabilité. On peut imaginer qu'une autre application Web souhaite également accéder aux mêmes services métiers. De même, on pourrait souhaiter qu'un client lourd (une application Java "classique" par exemple) puisse également le faire.
De même que les Servlets permettent à un navigateur Web de se connecter à l'application JEE, il existe un autre objet JEE permettant à une application Java de se connecter à des services métiers à distance. Ce sont les EJB, pour Entreprise JavaBeans.
Ils vont nous permettre de mettre en place une architecture 3-tiers ou 4-tiers de ce type (les couches "présentation" et "métier" pourront toujours être sur le même serveur, comme précédemment, ou, ce qui est nouveaux, sur des serveurs différents) :
Cela permet à différentes applications Web et différents clients lourds Java de se connecter aux services métiers proposés :
1. Rappel sur l'architecture client/serveur⚓︎
Une architecture client serveur est constituée de 2 programmes et d'un protocole :
- Un programme client qui effectue une requête (il pose une question).
- Un programme serveur qui propose des services (il effectue des traitements pour répondre à cette question).
- Un protocole (c'est la façon dont les deux programmes vont communiquer).
Pour les Servlets
Dans le cas des servlets, on avait :
- Le programme client est le navigateur.
- Le programme serveur est la Servlet.
- Le protocole de communication est HTTP.
Pour les EJB
Dans le cas des EJB, nous allons avoir :
- Le programme client est le client lourd Java ou la couche "présentation" (i.e. la Servlet).
- Le programme serveur est l'EJB.
- Le protocole de communication est RMI, pour Remote Method Invocation (Appel de Méthodes à Distance en français) (nécessaire en fait uniquement si le client et le serveur sont sur des JVM différentes).
2. Les EJBs⚓︎
Présentation
De même que le cycle de vie des Servlets (naissance / attente de requête HTTP / destruction) était géré par le conteneur de Servlets disponible sur le serveur Web, le cycle de vie des EJBs est géré par un conteneur d'EJB.
Tomcat et WildFly
À nouveau, Tomcat fourni uniquement un conteneur de Servlets. Pour utiliser des EJBs, il faut obligatoirement utiliser un serveur d'application. Nous allons à nouveau utiliser WildFly.
Les EJBs
Il existe trois types d'EJBs :
- Les EJB entités : C'est exactement ce que nous avons utilisé, sans le dire, avec les entités JPA (ce sont des beans classiques).
On utilise l'annotation@Entity
pour les définir (ce que nous avons fait dans le TD précédent). - Les EJB sessions : C'est eux qui vous nous permettre d'appeler les services métiers depuis l'extérieur (c'est en fait de ces EJBs dont on parle depuis le début de ce TD).
On utilise 3 annotations différentes pour les définir -@Singleton
,@Stateless
et@Statefull
- Cf. ci-dessous. - Les EJB messages : Nous n'allons pas les utiliser ici. Ils permettent d'appeler des traitements asynchrones.
Les EJBs sessions
Il y trois possibilités :
@Singleton
: Cela signifie qu'il n'y a qu'un seule instance de cette classe. Tous les clients effectuant des requêtes partagent donc la même.@Stateless
: Cela signifie que les échanges (c'est-à-dire les requêtes) se feront sans état, c'est-à-dire sans mémoire. Cela ressemble beaucoup à@Singleton
, mais la différence est que le serveur peut décider de créer de nouvelles instances de la classe s'il y a trop de clients en même temps.@Statefull
: Cela signifie que les échanges se feront avec mémoire. L'historique des requêtes effectuées par un client est conservé. Concrétement, chaque client dispose de sa propre instance de la classe. On peut donc avoir des variables de classe pour conserver des données en mémoire entre les requêtes.
Cycle de vie
Voici à quoi ressemble le cycle de vie d'un EJB session, de la manière dont nous allons l'utiliser :
sequenceDiagram
participant Client (Servlet)
participant Conteneur d'EJB
participant EJB Session
participant Service de transaction (JTA)
Client (Servlet) ->> Conteneur d'EJB: 1. Appel
Conteneur d'EJB ->> Service de transaction (JTA): 2. begin Transaction
Conteneur d'EJB ->> EJB Session: 3. Appel
EJB Session ->> EJB Session: 4. Traitement
EJB Session -->> Conteneur d'EJB: 5. Résultat ou Exception
Conteneur d'EJB ->> Service de transaction (JTA): 6. commit ou rollback
Conteneur d'EJB -->> Client (Servlet): 7. Résultat ou Exception
Par rapport à ce diagramme, il nous suffit d'implémenter le point 4 : on appelle le service DAO qui convient. Tout le reste est géré par le framework.
Ce que nous avons fait dans le TD3
Ce que nous avons fait précédemment ressemblait beaucoup à cela, mais nous devions gérer les transaction en plus. Nous avions en fait implémenté ce cycle de vie :
sequenceDiagram
participant Client (Servlet)
participant Business et DAO
participant Service de transaction (JTA)
Client (Servlet) ->> Business et DAO: 1. Appel
Business et DAO ->> Service de transaction (JTA): 2. begin Transaction
Business et DAO ->> Business et DAO: 3. Traitement
Business et DAO ->> Service de transaction (JTA): 4. commit ou rollback
Business et DAO -->> Client (Servlet): 5. Résultat ou Exception
Dans ce diagramme, il fallait implémenter tous les points :
- Instanciation de l'objet
NotesBusinessImpl
depuis la méthodeinit
des Servlets. - Éxécution de
em.getTransaction().begin();
depuis le DAO. - Éxécution de la requête (avec
persist
par exemple). - Éxécution de
em.getTransaction().commit();
ouem.getTransaction().rollback();
depuis le DAO.
Création d'un EJB session
Concrètement, un EJB est une classe qui implémente deux interfaces :
- Une interface locale, qui liste les services disponibles pour un appel local de l'EJB (i.e. depuis la même JVM).
On utilise l'annotation@Local
. - Une interface distante, qui liste les services disponibles pour un appel à distance de l'EJB (i.e. depuis une autre JVM, éventuellement sur un autre serveur).
On utilise l'annotation
@Remote
.
On peut donc très facilement choisir de ne pas déployer les mêmes services pour les accès en local ou à distance, alors qu'il n'y a qu'une seule implémentation.
3 projets Java
Pour pouvoir définir des EJBs (sessions), il faut un projet Java EJB. Notre projet ne sera donc plus implémenté dans un seul projet Web dynamique, mais il va nous falloir trois projets :
- Un projet Web dynamique pour la couche présentation.
Un tel projet est déployé sur un serveur via un WAR (pour Web Application Archive). - Une projet EJB pour la couche métier.
Un tel projet est déployé sur un serveur via un JAR (pour Java Archive). - Une projet application d'entreprise qui va contenir ces deux modules.
Un tel projet est déployé sur un serveur via un EAR (pour Entreprise Application Archive).
Sur le serveur Wildfly, nous ne déploierons en fait que ce projet.
Il va en fait même nous falloir un 4e projet : - Un projet java classique, pour représenter le client lourd.
Ce projet ne sera pas déployé sur le serveur.
Nous allons maintenant implémenter cette architecture 4-tiers, plus précisément, nous allons implémenter le schéma suivant :