I. Historique▲
Un premier jet des spécifications EJB 3.1 a été mis en ligne fin mars 2008 par le groupe d'experts de la JCP. Elles feront partie de la plate-forme Java EE 6.
Les EJBs ont 10 ans. Les dates correspondent aux spécifications (releases) finalisées.
- EJB 1.0 : 21 mars 1998
- EJB 1.1 : 12 décembre 1999
- EJB 2.0 : 14 août 2001
- EJB 2.1 : 12 novembre 2003
- EJB 3.0 : 18 décembre 2005 (JSR 220, plate-forme Java EE 5)
-
EJB 3.1 : 21 février 2008, la JSR 318 non finalisée (disponible avec la plate-forme Java EE 6, prévu fin 2008)
Jusqu'à la version 2.1, les EJB bénéficiaient d'une mauvaise réputation à cause de leur complexité. Depuis la version 3.0, leur mise en place est grandement simplifiée: plus besoin de descripteur de déploiement, plus de Home interface, plus besoin de faire un lookup via JNDI pour récupérer des EJBs, il suffit de passer par l'annotation @EJB, etc ...
La version 3.1 va vers encore plus de simplicité et de portabilité. Il faut espérer que les vendeurs de serveurs d'application implémentent rapidement cette nouvelle spécification pour pouvoir l'utiliser dès que possible.
Cet article n'est pas exhaustif, les spécifications finales étant encore en cours d'écriture mais il permettra au lecteur d'avoir un aperçu rapide des nouveautés dans les EJB 3.1, par rapport à la version 3.
II. Plus besoin d'interfaces locales !▲
Il n'est plus nécessaire d'implémenter une interface locale pour écrire des sessions beans, ce qui était déjà le cas avec les JPA entités et les Message Driven Beans.
2.
3.
4.
5.
6.
7.
@Stateless
public
class
MonStatelessBean {
public
String pause
(
Temps temps) {
return
"Un thé"
;
}
}
On voit qu'il n'est plus nécessaire d'utiliser l'annotation @Local et d'implémenter une interface. Un simple POJO suffit, annoté avec @Stateless ou @Stateful .
III. Le Singleton Bean et la concurrence d'accès▲
Le Singleton Bean correspond bien évidemment au classique design pattern Singleton.
C'est un POJO avec des annotations.
Le but est d'obtenir un objet transactionnel, thread-safe et qui fournit tous les services d'un container EJB : concurrence, sécurité ...
On a ainsi une instance unique d'un stateful session bean qui est partagé par tous les clients et qui supporte les accès concurrents.
Exemple d'un singleton avec des données en écriture :
2.
3.
4.
5.
6.
7.
8.
9.
@Singleton
@ReadOnly
public
class
ContextBean implements
ContextPartage {
@PostConstruct
public
void
init
(
) {
//on initialise le contexte de l'application
}
...
}
On peut gérer la concurrence d'accès à ce singleton avec les annotations @ReadOnly et @ReadWrite qui permettent de poser un verrou en lecture-écriture sur l'instance unique.
La méthode init() sera lancée une seule fois, quand le container démarre l'application, à l'initialisation.
Les singletons peuvent donc être injectés (design pattern Inversion of Control IoC).
Exemple d'un singleton avec des données changeables :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
@Singleton
public
class
ContextBean implements
ContextPartage {
private
ContextPartage contextePartage;
@ReadWrite
public
void
condition
(
...) {
// mise à jour du contexte partage
...
}
@ReadOnly
public
int
getValeur
(
) {
return
contextePartage.valeur;
}
...
}
La concurrence d'accès peut être gérée soit par le container, soit par le développeur du bean (@BeanManagedConcurrency).
Note (mars 2010) : les annotations @ReadOnly et @ReadWrite sont remplacées par @Lock(LockType.READ) et @Lock(LockType.WRITE)
IV. EJB Timer▲
Une nouvelle annotation fait son apparition : @Schedule
2.
3.
4.
@Schedule
(
hour=
"10"
, dayOfMonth=
"1"
)
public
void
uneTache
(
) {
...
}
Cette tâche est lancée le 1er jour de chaque mois, à 10h00.
Il est maintenant possible d'activer un scheduler similaire à la Crontab sous Unix.
Avant on devait passer par l'interface javax.ejb.TimerService:
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
@Stateless
public
class
ControleTrafficBean implements
ControleTraffic {
@Resource
TimerService timerService;
public
void
controleTrain
(
Train train) {
...
// en millisecondes
// createTimer(long initialDuration, long intervalDuration, Serializable info)
timerService.createTimer
(
10
*
60
*
1000
, 60
*
60
*
1000
, train);
...
}
@Timeout
public
void
annulerTrain
(
Timer timer) {
...
Train train =
(
Train) timer.getInfo
(
);
...
}
}
Ici on crée un intervalle de 10 minutes, qui se répète toutes les heures.
La méthode annotée avec @Timeout est activée quand l'intervalle de 10mn est passé.
Avec la version 3.1, les choses deviennent encore plus simples, on écrit de manière déclarative :
2.
3.
4.
5.
6.
7.
8.
@Stateless
public
class
ControleTrafficBean implements
ControleTraffic {
@Schedule
(
second=
"0"
, minute=
"10"
, hour=
"*"
, dayOfMonth=
"*"
, month=
"*"
, year=
"*"
)
public
void
controleTrain
(
Train train) {
...
}
}
On peut donc automatiquement créer des timers.
V. Appels asynchrones▲
Avec les EJB 3.0, les appels asynchrones se font exclusivement via les Message Driven Beans et JMS.
Depuis les EJB 3.1, les méthodes des sessions beans peuvent aussi être appelées de façon asynchrone:
quand le client appelle une méthode asynchrone, le container redonne la main au client et continue l'appel de cette méthode asynchrone dans un autre thread.
Pour cela, on utilise l'annotation @Asynchronous :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
@Stateless
@Remote
(
DemandeFacade.class
)
public
class
DemandeFacadeBean implements
DemandeFacade{
@Asynchronous
public
void
enregistre
(
Demande demande) {
// ...
}
@Asynchronous
public
Future autorise
(
Demande demande) {
// ...
return
new
AsyncResult
(
DemandeEtat.OUI);
}
}
Les 2 méthodes ci-dessus sont asynchrones.
Les types de retour possibles sont void ou java.util.concurrent.Futurecomme c'est le cas pour la méthode autorise(...) .
Cette interface fournit des méthodes qui permettent de vérifier le résultat d'un appel asynchrone, l'annuler ...
La méthode autorise(...) utilise la classe helper javax.ejb.AsyncResult qui possède un constructeur qui prend comme paramètre le résultat. Cette classe implémente Future.
VI. EJB dans un WAR▲
Pour faciliter le déploiement, il est maintenant possible de packager / déployer des composants EJB 3 dans une archive WAR.
Il n'est plus nécessaire de créer une archive JAR et une archive EAR, tout peut être contenu dans une unique archive WAR.
Les classes peuvent aller dans le répertoire WEB-INF/classes, ainsi que le descripteur de déploiement ejb-jar.xml s'il est utilisé,
ou bien le JAR des EJB peut aller directement sous WEB-INF/lib/ .
On peut désormais appeler des EJB directement dans un container de servlet comme Tomcat, tout tient dans un .WAR.
VII. Support des stateful web services▲
Les EJB 3.0 supportent les stateless web services. Avec la version 3.1, les stateful web services seront aussi supportés.
2.
3.
4.
5.
6.
7.
8.
@WebService
@Stateful
public
class
BonjourBean {
public
String direBonjour
(
) {
return
"Bonjour"
;
}
}
Note (mars 2010) : cette nouveauté n'est finalement pas supportée.
VIII. Profils et EJB Lite▲
VIII-A. Profils▲
Java EE 6 introduira la notion de profil : les profils offriront différents types de services JEE.
- Profil A : c'est une version légère (Servlet, JSP etc).
- Profil B : il inclut le profile A + EJB 3.1 Lite, JTA, JPA, JSF et les WebBeans.
- Profil C : c'est une version complète de la plate-forme constituée du profil B + JMS, JAX-WS etc.
VIII-B. EJB Lite▲
L'idée est de permettre une implémentation d'un sous-ensemble des EJB 3.1 en enlevant les choses les moins utilisées, comme les Message Driven Beans et les EJB Timer services.
Caractéristiques | EJB Lite | EJB |
Stateless beans | oui | oui |
Stateful beans | oui | oui |
Singleton beans | oui | oui |
Message driven beans | non | |
Pas d'interfaces | oui | oui |
Interfaces locales | oui | oui |
Remote interfaces beans | oui | |
Interfaces Web Services | oui | |
Invocation asynchrone | oui | |
Interceptors | oui | oui |
Sécurité déclarative | oui | oui |
Transactions déclaratives | oui | oui |
Transactions programmatiques | oui | oui |
Timer service | oui | |
Support EJB 2.X | oui | |
Interopérabilité CORBA | oui |
IX. Liens▲
X. Remerciements▲
Je tiens à remercier Hikage, Ricky81 pour les conseils, remarques et relectures, ainsi qu'Aspic pour la correction orthographique.
Je remercie aussi www.developpez.comme permettant de publier cet article et Nono40 pour ses outils.