6. Cycle de vie d'un EJB

6.1. Cas des EJB sans état

Un EJB session sans état est annoté avec @Stateless. Le cycle de vie d'un EJB sans état comporte deux états :
  • does not exist : dans cet état l'EJB ne peut répondre à des requêtes de la part d'un client.
  • method-ready : dans cet état l'EJB peut répondre aux requêtes de clients.
Le passage du premier état vers le second se fait en trois temps :
  • construction de l'EJB proprement dit ;
  • injection des dépendances déclarées par cet EJB ;
  • appel de la méthode callback PostConstruct, cette méthode doit être annotée par @PostConstruct.
Le passage du second état vers le premier commence par l'appel d'une méthode annotée @PreDelete, si elle existe.

6.2. Cas des EJB avec état

6.2.1. Passivation d'un EJB avec état

Le cycle de vie d'une instance d'EJB avec état est un peu plus complexe, du fait qu'une telle instance est attachée à un client donné. Dès qu'un EJB avec état répond aux requêtes d'un client, il devient dépendant de ce client et ne peut plus servir d'autres clients. Le serveur d'applications peut mettre en œuvre deux stratégies en cas d'inactivité d'un client.
  • Il peut tout d'abord passiver l'instance inutilisée. Cela consiste à sauvegarder l'état de cette instance (typiquement ses variables d'instance) dans un espace mémoire particulier, qui peut être un cache disque. Il vaut mieux que ces variables d'instances soient alors sérializables, si ce n'est pas le cas il faut les déclarer transient et utiliser une forme ad hoc de sauvegarde. Lorsque le client revient, son instance peut être sortie de sa passivation, et continuer à servir ses requêtes.
  • Une instance passivée depuis longtemps peut enfin être détruite. Cela met un terme à la conversation. Si le client revient, c'est une nouvelle instance d'EJB qui servira ses requêtes.

6.2.2. États du cycle de vie

Le cycle de vie d'un EJB avec état comporte quatre états.
  • does not exist : de même que pour un EJB sans état, il n'est pas possible de répondre aux requêtes d'un client dans cet état.
  • method ready : cet état est l'état nominal d'un EJB. Dans cet état, un EJB peut répondre aux requêtes d'un client.
  • method ready in TX : cet état n'existe que dans le cas d'un EJB avec état, et lors de l'appel à une méthode qui s'exécute dans une transaction. Dans ce cas, au moment du démarrage de la transaction, l'EJB passe dans cet état. Il en sort lorsque cette transaction est terminée.
  • passive : cet état désigne un EJB qui a été passivé. Un EJB est passivé suite à une période d'inactivité jugée trop longue par le serveur d'application.

6.2.3. Transitions entre ces états, interface SynchronizationTransaction

Comme pour les EJB sans état, un EJB qui passe de l'état does not exist à l'état method ready se voit injecté toutes les valeurs qui doivent l'être. Lors de cette transition, la méthode annotée @PostConstruct est invoquée, si elle existe. Le passage de l'état method ready à does not exist s'accompagne également de l'appel à la méthode annotée @PreDestroy, si elle existe. La passivation et le réveil d'un EJB (transitions entre les états method ready et passivate ) s'accompagne également de l'appel de deux méthodes, annotées @PrePassivate et @PostActivate respectivement, si elles existent. Un EJB dans l'état passivate peut passer dans l'état does not exist, mais dans ce cas aucune méthode n'est appelée. Ce qui est assez logique, puisque que dans l'état passivate notre pauvre EJB n'est probablement qu'un amas informe d'octets rangés dans un tableau. Rappelons que l'état method ready in TX n'est utilisé que si la méthode métier est déclarée transactionnelle. Si tel est le cas, le passage de l'état method ready à method ready in TX peut s'accompagner de l'appel à plusieurs callbacks . Ces callbacks sont appelés si l'EJB session implémente l'interface SessionSynchronization, qui définit les trois méthodes suivantes :
  • afterBegin() : appelée une fois que la transaction a démarré.
  • beforeCompletion() : appelée juste avant l'appel à la méthode commit() de la transaction.
  • afterCompletion(boolean) : appelée une fois que la méthode commit() a fini de s'exécuter. Si la transaction est un succès, cette méthode est appelée avec l'argument true. Dans le cas contraire, elle est appelée avec l'argument false.
La méthode afterBegin() est appelée par le serveur d'applications au moment du démarrage de la transaction. Cette méthode est appelée une fois que la transaction a démarré (l'appel à sa méthode begin() a rendu la main). Il est donc possible de faire des opérations en base, qui seront menées à bien dans la transaction de la méthode métier. Lorsque cette méthode rend la main, alors l'EJB passe dans l'état method ready in TX . Lorsque la méthode métier termine son exécution, le gestionnaire de transactions fait un appel à la méthode commit() de la transaction dans laquelle cette méthode s'est exécutée. L'appel de cette méthode peut se terminer de deux façons : un succès ou un échec. En cas de succès, le retour de la méthode métier est envoyé au client, il s'agit du cas nominal. En cas d'échec, une exception est envoyée au client. La méthode beforeCompletion() est appelée par le serveur d'applications avant l'appel à la méthode commit() de la transaction. La méthode afterCompletion(boolean) est appelée par le serveur d'application une fois la transaction validée. Si cette validation est un succès, cette méthode est appelée avec le paramètre true, et false dans le cas contraire. L'EJB est donc informé du succès ou non de la transaction, et peut mettre à jour son état dans ces deux cas.

6.3. Injection de dépendances

L'injection de dépendances est un mécanisme qui consiste à demander au serveur d'applications (ou à tout autre containeur d'objets) d'initialiser certains champs, marqués comme correspondant à des ressources gérées par ce containeur. La façon la plus simple de marquer ces champs est de les annoter, mais il en existe d'autres. Les annotations utilisées dans les EJB sont les suivantes.
  • @Resource : permet d'injecter toutes les ressources disponibles auprès de l'annuaire du serveur d'application. Cette annotation prend entre autres un attribut mappedName, que l'on fixe au nom de cette ressource. Dans certains cas ce nom est facultatif, s'il n'y a pas d'ambiguïté sur le champ injecté. C'est le cas pour UserTransaction.
  • @EJB : permet d'injecter directement un autre EJB. Si un unique EJB implémente l'interface du champ injecté, cette annotation s'utilise sans attribut. S'il y a ambiguïté, on peut la lever en donnant le nom de l'EJB dans le paramètre mappedName.
  • @PersistenceContext : permet d'injecter un entity manager . On doit préciser le nom de l'unité de persistance dans l'attribut unitName.
Voyons tout ceci sur un exemple.

Exemple 67. Éléments injectés dans un EJB

@Stateless(mappedName="MarinService")
 @Remote(MarinService.class)
 public  class MarinServiceImpl  implements MarinService {

     // il n'y a qu'une seule transaction, pas besoin
     // de fixer de nom pour la ressource injectée
     @Resource
     private UserTransaction transaction ;

     // la source de données injectée doit être précisée 
     // par son nom
     @Resource(mappedName="jdbc/CoursEJBDS")
     private DataSource datasource ;

     // le contexte de persistance injecté doit être précisé 
     // par son nom
     @PersistenceContext(unitName="cours-ear-pu")
     private EntityManager em ;

     // injection d'un EJB : si l'interface BateauService
     // n'est implémentée qu'une fois, pas besoin
     // de fixer de nom pour la ressource injectée
     @EJB
     private BateauService bateauService ;
    
     // suite de la classe
}

Les champs injectés voient leur valeur fixée avant l'appel à la méthode callback @PostConstruct. Elles peuvent varier d'une invocation de méthode à une autre, c'est notamment le cas de UsertTransaction.
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