5. Types d'EJB

5.1. Introduction

Nous présentons ici la version 3 de la spécification EJB, qui appartient à la famille JEE5. Depuis, une version 3.1 a été publiée, dans le cadre de JEE6. Pour des raisons de compatibilité ascendantes, la spécification 3.0 inclut les spécifications des versions précédentes. Nous nous limiterons ici à ce qui est strictement de la version 3, puisque c'est cette version qui est aujourd'hui la plus utilisée, et probablement aussi la plus utilisable, dans le cadre JEE5. Cette spécification recouvre trois types d'EJB.
  • Les EJB session, qui existent en deux variantes : avec état ( stateful ) et sans état ( stateless ). Nous allons présenter ces deux variantes.
  • Les EJB messages, qui fonctionnent en tandem avec l'API JMS (Java Messaging Service). Ces EJB sont en dehors du cadre de ce document. Ils y rentreront très probablement dans l'avenir.
  • Les EJB entité. Ces EJB sont complètement obsolètes, et n'ont aucune chance d'être jamais traités dans ces pages. Les besoins qu'ils étaient censés remplir l'ont été par les spécifications JDO et JPA. En écrire plus sur le sujet serait une perte de temps.

5.2. Qu'est-ce qu'un EJB ?

Nous avons déjà écrit un EJB session sans état dans la partie introductive de ce chapitre, mais sans vraiment donner de définition précise de ce que représente cette notion. Les EJB sont des composants Java utilisables dans les applications distribuées. Ils permettent au développeur de se concentrer sur les problématiques "métier", sans avoir à se préoccuper de questions techniques de bas niveau, telles que l'ouverture de connexions sur des bases de données, ou la gestion de transactions. Le standard EJB est censé garantir qu'une application construite sur un jeu d'EJB est portable d'un serveur d'applications à l'autre. D'un côté le standard spécifie comment un EJB doit être écrit, de l'autre il propose des tests de compatibilité que les serveurs d'applications doivent passer avec succès pour obtenir le label "Serveur JEE5". Dans tous les cas, les spécifications résolvent beaucoup de problèmes, mais pas nécessairement tous les problèmes de déploiement. En particulier la configuration d'une application EJB varie en général d'un serveur à l'autre. Techniquement, un EJB est un composant managé , tout comme une servlet. On ne l'instancie pas, c'est le serveur d'application qui s'en charge. Comme tout composant managé , un EJB suit un cycle de vie. Une fois chargé et initialisé, un EJB répond à des requêtes, d'une façon définie par le standard.

5.3. Écriture d'un EJB session

Techniquement, un EJB session est composé de deux éléments :
  • Une interface Java quelconque. En version 2, cette interface devait étendre d'autres interfaces, ce n'est plus le cas en version 3.
  • Une classe qui implémente cette interface. Cette classe n'a pas besoin d'étendre d'autres classes.
Ces deux éléments doivent être annotés. On peut poser ces annotations de deux façons :
  • L'interface peut être annotée avec l'annotation @Remote ou @Local. Un EJB remote est accessible au travers du réseau (même s'il ne s'agit que de la boucle locale), alors qu'un EJB local n'est accessible que du serveur d'applications dans lequel on se trouve. Si l'on ne prévoit pas d'utiliser cet EJB de l'extérieur de l'application d'entreprise que l'on est en train de construire, alors notre EJB est local . Il est important de noter qu'il est plus performant d'utiliser un EJB local que remote , du fait que dans ce premier cas, on n'a pas à sérialiser les paramètres et éléments de retour.
  • La classe d'implémentation doit être annotée avec l'annotation @Stateless si cet EJB est sans état, @Stateful dans le cas contraire. Cette annotation peut prendre un attribut mappedName, qui précise le nom de cet EJB dans l'annuaire du serveur d'applications. Si l'interface implémentée par cet EJB ne porte pas d'annotation @Remote ou @Local, alors l'implémentation doit la porter. Dans ce cas, l'annotation choisie ( @Remote ou @Local) doit avoir en attribut la classe de l'interface implémentée.

5.4. Qu'est-ce qu'une méthode métier ?

Une méthode métier ( business method dans la documentation en anglais) est une méthode classique, déclarée dans l'interface implémentée par l'EJB. Toutes les méthodes déclarées dans cette interface sont donc des méthodes métier. Les méthodes métier sont les seules méthodes exposées par un EJB, puisque c'est par son interface que l'on y accède. Les méthodes de la classe d'implémentation qui ne sont pas déclarées dans l'interface ne peuvent pas être des méthodes métier, puisque, de ce fait, elles ne sont pas accessibles d'un client.

5.5. EJB avec ou sans état

Lorsqu'un client appelle une méthode business d'un EJB, le serveur d'application commence par choisir une instance disponible pour traiter cette requête. Le standard EJB impose qu'une même instance d'EJB ne peut pas servir plusieurs clients à la fois : un EJB n'est donc pas un composant multithread. Si l'EJB auquel notre client fait appel est "sans état", alors cette instance peut varier d'une requête à l'autre, au gré du serveur d'applications. Dans le cas d'un EJB "avec état", alors le standard EJB impose au serveur d'applications de nous fournir toujours la même instance. Dans le second cas, il devient possible d'utiliser des variables d'instance. On peut donner une valeur à une telle variable lors d'un premier appel de méthode, et la récupérer lors d'un appel suivant, de la même méthode ou d'une autre. Cela n'est pas possible dans le cas d'un EJB sans état. L'entretien de ce mode dit "conversationnel" entre une instance d'un EJB donné et un client particulier entraîne bien sûr un coût pour le serveur. Dans certaines applications ce coût peut être inacceptable, raison pour laquelle on préfèrera toujours utiliser les EJB sans état.

5.6. Gestion des transactions

Enfin le dernier point important est la gestion de la transaction. Il est exceptionnel qu'un EJB n'ait pas à s'adresser à une base de données, que ce soit directement via les sources de données déclarées dans le serveur d'application, ou via JPA. Dans notre exemple précédent, la transaction dans laquelle s'effectuait les opérations en base étaient directement gérée par le serveur d'application. C'est le cas le plus simple : le développeur d'EJB n'a à se préoccuper de rien, et tout fonctionne automatiquement. On dit dans ce cas que les transactions sont gérées par le serveur d'applications, elles sont container manager . Il existe un autre mode de fonctionnement, dit bean managed , dans lequel c'est l'EJB qui gère lui-même la transaction dans laquelle il travaille. Cette transaction lui est fournie par le serveur d'applications, mais il est de la responsabilité de l'EJB d'appeler correctement les méthodes begin(), commit() et rollback().

5.7. Restrictions

On ne peut pas faire ce que l'on veut dans un EJB, notamment du fait qu'il s'agit d'un composant qui vit dans un serveur d'applications. Faisons ici la liste de ce qui est interdit. La liste donnée ici n'est pas exhaustive.
  • Un EJB ne doit pas utiliser de champs statiques. S'il est autorisé à lire de tels champs, utiliser des champs statiques en écriture ne pourra pas fonctionner en général. Effectivement, certains serveurs d'applications fonctionnent en clusters, c'est-à-dire sur plusieurs machines. Les champs statiques ne sont pas transmis de machine en machine, on ne peut donc pas les utiliser pour communiquer entre instances d'une même classe.
  • Un EJB ne doit pas utiliser de mécanisme de synchronisation avec d'autres threads, pour les mêmes raisons.
  • L'accès aux classes graphiques (AWT, Swing), au clavier, à une console de sortie, au système de fichiers, l'utilisation directe de sockets (cela inclut les accès JDBC directs) sont fortement déconseillés dans le contexte de la programmation serveur en général, et pour les EJB en particulier.
  • Un EJB ne doit pas tenter d'accéder au class loader dans lequel il se trouve, ou à tout autre class loader .
  • Un EJB ne doit pas tenter de créer de threads, ou d'en fermer. Ce genre d'opération est de la responsabilité du serveur d'applications.
  • Un EJB ne doit pas utiliser de librairie native.
  • Un EJB ne doit pas passer this comme argument d'une méthode qu'il appelle.
JPA & EJB
Retour au blog Java le soir
Cours & Tutoriaux
Table des matières
Introduction
1. Objet du mapping objet / relationnel
2. Un peu d'histoire
Un premier exemple
1. Introduction
2. Création de l'environnement technique
2.1. Introduction
2.2. Création de la base Derby
2.3. Création du projet NetBeans et d'une première entité
2.4. Structure d'un projet persistant
2.5. Une première classe persistante
2.6. Un premier fichier persistence.xml
3. Utilisation de ce premier exemple
3.1. Écriture du code d'utilisation
3.2. Exécution de notre premier exemple
3.3. Modification de la class Marin
3.4. Opérations CRUD
Mettre un jeu de classes en base
1. Introduction
2. Définition d'une entité JPA
2.1. Écriture de l'entité
2.2. Annotation de l'entité
2.3. Annotations des champs
2.4. Exemple d'utilisation
3. Opérations sur les entités
3.1. Introduction
3.2. Opération PERSIST
3.3. Opération REMOVE
3.4. Opération REFRESH
3.5. Opération DETACH
3.6. Opération MERGE
4. Mise en relation d'entités
4.1. Introduction
4.2. Relations unidirectionnelles et bidirectionnelles
4.3. Relation 1:1
4.4. Relation 1:p
4.5. Relation p:1
4.6. Relation n:p
4.7. Comportement cascade
4.8. Effacement des entités orphelines
5. Charger des entités et leurs relations
6. Objets inclus
6.1. Introduction
6.2. Déclaration d'un objet inclus
6.3. Utilisation d'objets inclus
6.4. Cas où l'objet inclus est nul
6.5. Renommer les colonnes incluses
6.6. Collections d'objets inclus
L'API Collection en base
1. Introduction
2. Enregistrer une collection d'entités
2.1. Enregistrement d'une collection simple
2.2. Enregistrement d'un Set
2.3. Enregistrement d'une List
3. Enregistrer une collection de types de base
4. Enregistrement d'une Map
4.1. Table de hachage de type (type de base, entité)
4.2. Cas où la clé est un champ de la valeur
4.3. Cas d'une table (entité, entité)
Héritage
1. Introduction
2. Enregistrement d'une hiérarchie de classes
2.1. Entité et super-classe non enregistrée
2.2. Position du problème
2.3. Trois façons de faire
3. Stratégie SINGLE_TABLE
3.1. Fonctionnement
3.2. Mise en place
3.3. Limitations
4. Stratégie JOINED
4.1. Fonctionnement
4.2. Mise en place
4.3. Limitations
5. Stratégie TABLE_PER_CLASS
5.1. Fonctionnement
5.2. Mise en place
5.3. Limitations
Requêtes
1. Introduction
2. Un premier exemple
2.1. Écriture d'une première requête
2.2. Exécution d'une première requête
2.3. Exécution d'une première requête d'agrégation
3. Définition de requêtes
3.1. Requêtes dynamiques
3.2. Requêtes paramétrées
3.3. Requêtes nommées
3.4. Requêtes natives
4. Exécution, analyse du résultat
4.1. Exécution d'une requête dynamique
4.2. Exécution d'une requête nommée
4.3. Analyse du résultat
4.4. Cas des résultats de grande taille
4.5. Remarques
5. Clause From
5.1. Définition des entités
5.2. Jointures dans la clause From
5.3. Remarque finale sur les jointures en JPQL
6. Clause Where
6.1. Variables et chemins dans une clause where
6.2. Expressions conditionnelles et opérateurs
6.3. Requêtes imbriquées
6.4. Opérateurs any, all et some
6.5. Expressions fonctionnelles
7. Clauses Group By et Having
8. Opérations Update et Delete
EJB
1. Introduction
2. Un premier exemple
2.1. Introduction
2.2. Installation dans Glassfish à l'aide de Netbeans
2.3. Création d'un premier EJB
2.4. Déploiement de notre premier EJB
2.5. Création d'un client
3. Mise en oeuvre du pattern session facade
3.1. Introduction
3.2. Modèle objet
3.3. Définition de l'unité de persistance
3.4. Assemblage de notre application
3.5. Assemblage et déploiement
3.6. Utilisation du client
4. Opération de persistance en façade
4.1. Introduction
4.2. Enrichissement du service
4.3. Création de la méthode findMarinById(long)
4.4. Ajout de la méthode findAllMarins()
4.5. Utilisation dans un code client
5. Types d'EJB
5.1. Introduction
5.2. Qu'est-ce qu'un EJB ?
5.3. Écriture d'un EJB session
5.4. Qu'est-ce qu'une méthode métier ?
5.5. EJB avec ou sans état
5.6. Gestion des transactions
5.7. Restrictions
6. Cycle de vie d'un EJB
6.1. Cas des EJB sans état
6.2. Cas des EJB avec état
6.3. Injection de dépendances
7. Transaction gérée par l'EJB
7.1. Introduction
7.2. Déclaration du mode transactionnel
7.3. Gestion de la transaction
7.4. Fonctionnement de la transaction
7.5. Cas des EJB avec état
8. Transaction gérée par le serveur
8.1. Introduction
8.2. Déclaration du mode transactionnel
8.3. Gestion de la transaction
8.4. Fonctionnement de la transaction
8.5. Remarques
9. Intercepteurs
9.1. Introduction
9.2. Aperçu général
9.3. Cycle de vie d'un intercepteur
9.4. Object InvocationContext
9.5. Interception d'un EJB ou d'une méthode métier
9.6. Exemple de mise en œuvre d'un intercepteur