Oui, vous pouvez librement mélanger CDI et EJB et obtenir d'excellents résultats. Il semble que vous utilisiez @WebService
et @Schedule
qui sont de bonnes raisons pour ajouter EJB au mélange.
Il y a beaucoup de confusion dans l'air. Voici donc quelques informations générales sur EJB et CDI dans leur relation mutuelle.
EJB >= CDI
Notez que les EJBs sont haricots CDI et bénéficient donc de tous les avantages du CDI. L'inverse n'est pas vrai (encore). Ne prenez donc surtout pas l'habitude de penser "EJB vs CDI", car cette logique se traduit en réalité par "EJB+CDI vs CDI", ce qui constitue une étrange équation.
Dans les prochaines versions de Java EE, nous continuerons à les aligner. L'alignement consiste à permettre aux gens de faire ce qu'ils peuvent déjà faire, mais sans l'inconvénient de l'utilisation d'un système d'exploitation. @Stateful
, @Stateless
ou @Singleton
en haut de l'écran.
EJB et CDI en termes de mise en œuvre
En fin de compte, EJB et CDI partagent la même conception fondamentale qui consiste à être des composants mandataires. Lorsque vous obtenez une référence à un bean EJB ou CDI, il ne s'agit pas du vrai bean. L'objet qui vous est donné est plutôt un faux (un proxy). Lorsque vous invoquez une méthode sur ce faux objet, l'appel est transmis au conteneur qui l'envoie par le biais d'intercepteurs, de décorateurs, etc. et s'occupe des contrôles de transaction ou de sécurité. Une fois que tout cela est fait, l'appel est finalement envoyé à l'objet réel et le résultat est renvoyé à l'appelant via le proxy.
La différence réside uniquement dans la manière dont l'objet à invoquer est résolu. Par "résolu", nous voulons simplement dire, où et comment le conteneur recherche l'instance réelle à invoquer.
En CDI, le conteneur cherche dans un "scope", qui sera essentiellement un hashmap qui vit pendant une période de temps spécifique (par demande). @RequestScoped
par session HTTP @SessionScoped
par demande @ApplicationScoped
Conversation JSF @ConversationScoped
ou selon votre mise en œuvre personnalisée de l'étendue).
Dans EJB le conteneur regarde aussi dans un hashmap si le bean est de type @Stateful
. Un site @Stateful
peut également utiliser l'une des annotations de portée ci-dessus, ce qui fait qu'il vit et meurt avec tous les autres beans de la portée. Dans EJB @Stateful
est essentiellement le haricot "any scoped". Le site @Stateless
est fondamentalement un pool d'instances -- vous obtenez une instance du pool pour la durée d'une invocation. Le site @Singleton
est essentiellement @ApplicationScoped
Ainsi, à un niveau fondamental, tout ce que vous pouvez faire avec un bean "EJB", vous devriez pouvoir le faire avec un bean "CDI". En apparence, il est très difficile de les distinguer. Toute la plomberie est la même, à l'exception de la façon dont les instances sont résolues.
Actuellement, ils ne sont pas les mêmes en termes de services offerts par le conteneur lors de l'exécution de cette procuration, mais comme je l'ai dit, nous y travaillons au niveau de la spécification Java EE.
Note de performance
Ne tenez pas compte des images mentales "légères" ou "lourdes" que vous pouvez avoir. Ce n'est que du marketing. Ils ont la même conception interne pour la plupart. La résolution d'instance CDI est peut-être un peu plus complexe car elle est légèrement plus dynamique et contextuelle. La résolution d'instance EJB est plutôt statique, stupide et simple en comparaison.
Je peux vous dire que du point de vue de l'implémentation dans TomEE, il n'y a aucune différence de performance entre l'invocation d'un EJB et l'invocation d'un bean CDI.
Par défaut, POJO, puis CDI, puis EJB
Bien sûr, n'utilisez pas CDI ou EJB s'il n'y a aucun avantage. Intégrez CDI lorsque vous commencez à avoir besoin d'injection, d'événements, d'intercepteurs, de décorateurs, de suivi du cycle de vie, etc. C'est le cas la plupart du temps.
Au-delà de ces éléments de base, il existe un certain nombre de services de conteneur utiles que vous ne pouvez utiliser que si vous faites de votre bean CDI également un EJB en ajoutant la fonction @Stateful
, @Stateless
ou @Singleton
sur elle.
Voici une courte liste des cas où j'utilise les EJB.
Utilisation de JAX-WS
Exposition d'un JAX-WS @WebService
. Je suis paresseux. Quand le @WebService
est également un EJB, il n'est pas nécessaire de le répertorier et de le mapper comme une servlet dans le fichier web.xml
fichier. C'est du travail pour moi. De plus, j'ai la possibilité d'utiliser l'une des autres fonctionnalités mentionnées ci-dessous. C'est donc une évidence pour moi.
Disponible pour @Stateless
et @Singleton
seulement.
Utilisation de JAX-RS
Exposition d'une ressource JAX-RS via @Path
. Je suis toujours paresseux. Lorsque le service RESTful est également un EJB, vous bénéficiez à nouveau de la découverte automatique et vous n'avez pas besoin de l'ajouter à un JAX-RS. Application
sous-classe ou quelque chose comme ça. De plus, je peux exposer exactement le même haricot en tant qu'objet de type @WebService
si je le veux ou si j'utilise l'une des excellentes fonctionnalités mentionnées ci-dessous.
Disponible pour @Stateless
et @Singleton
seulement.
Logique de démarrage
Chargement au démarrage via @Startup
. Il n'y a actuellement aucun équivalent à cela dans CDI. D'une manière ou d'une autre, nous avons manqué d'ajouter quelque chose comme un AfterStartup
dans le cycle de vie du conteneur. Si nous avions fait cela, vous auriez simplement pu avoir un @ApplicationScoped
qui l'a écouté et qui serait effectivement la même chose qu'une @Singleton
avec @Startup
. C'est sur la liste pour CDI 1.1.
Disponible pour @Singleton
seulement.
Travailler en parallèle
@Asynchronous
invocation de la méthode. Le lancement de threads est à proscrire dans tout environnement côté serveur. Le fait d'avoir trop de threads nuit gravement aux performances. Cette annotation vous permet de paralléliser les opérations que vous effectuez en utilisant le pool de threads du conteneur. C'est génial.
Disponible pour @Stateful
, @Stateless
et @Singleton
.
Planification du travail
@Schedule
ou ScheduleExpression
est essentiellement un cron ou Quartz
fonctionnalité. C'est aussi très impressionnant. La plupart des conteneurs se contentent d'utiliser Quartz sous le manteau pour cela. La plupart des gens ne savent pas, cependant, que le travail de planification dans Java EE est transactionnel ! Si vous mettez à jour une base de données puis planifiez un travail et que l'un d'eux échoue, les deux seront automatiquement nettoyés. Si le EntityManager
Si l'appel échoue ou si la chasse d'eau pose problème, il n'est pas nécessaire de dérégler le travail. Yay, les transactions.
Disponible pour @Stateless
et @Singleton
seulement.
Utilisation d'EntityManagers dans une transaction JTA
La note ci-dessus sur les transactions nécessite bien sûr que vous utilisiez une JTA
géré EntityManager
. Vous pouvez les utiliser avec un simple "CDI", mais sans les transactions gérées par conteneur, il peut devenir vraiment monotone de dupliquer le processus de gestion de l'information. UserTransaction
logique d'engagement/de retour en arrière.
Disponible pour tous les composants Java EE, y compris CDI, JSF @ManagedBean
, @WebServlet
, @WebListener
, @WebFilter
etc. Le site @TransactionAttribute
Cependant, l'annotation est disponible pour @Stateful
, @Stateless
et @Singleton
seulement.
Maintenir la gestion de la JTA EntityManager
Le site EXTENDED
géré EntityManager
vous permet de garder une EntityManager
ouvert entre JTA
transactions et ne pas perdre les données mises en cache. Une bonne fonctionnalité au bon moment et au bon endroit. A utiliser de manière responsable :)
Disponible pour @Stateful
seulement.
Synchronisation facile
Lorsque vous avez besoin d'une synchronisation, le @Lock(READ)
et @Lock(WRITE)
Les annotations sont plutôt excellentes. Elles vous permettent d'obtenir gratuitement une gestion des accès concurrents. Sautez toute la plomberie du ReentrantReadWriteLock. Dans le même seau se trouve @AccessTimeout
qui vous permet d'indiquer combien de temps un thread doit attendre pour accéder à l'instance du haricot avant d'abandonner.
Disponible pour @Singleton
haricots seulement.