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()
.
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.