Oui, vous pouvez mélanger librement CDI et EJB et obtenir d'excellents résultats. On dirait que vous utilisez @WebService
et @Schedule
, qui sont de bonnes raisons d'ajouter des EJB au mix.
Il y a beaucoup de confusion là-bas, alors voici quelques informations générales sur EJB et CDI car ils se rapportent à chacun ensemble.
EJB> = CDI
Notez que les EJB sont des beans CDI et ont donc tous les avantages du CDI. L'inverse n'est pas (encore) vrai. Alors ne prenez certainement pas l'habitude de penser "EJB vs CDI" car cette logique se traduit vraiment par "EJB + CDI vs CDI", ce qui est une équation étrange.
Dans les futures versions de Java EE, nous continuerons à les aligner. Qu'est - ce que des moyens d' alignement permet à des gens de faire ce qu'ils peuvent déjà faire, juste sans @Stateful
, @Stateless
ou l' @Singleton
annotation en haut.
EJB et CDI en termes de mise en œuvre
En fin de compte, EJB et CDI partagent la même conception fondamentale d'être des composants mandatés. Lorsque vous obtenez une référence à un bean EJB ou CDI, ce n'est pas le 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 va au conteneur qui enverra l'appel via des intercepteurs, des décorateurs, etc. et s'occupera de toute transaction ou contrôle de sécurité. Une fois que tout cela est fait, l'appel va finalement à l'objet réel et le résultat est renvoyé par le proxy à l'appelant.
La différence vient uniquement de la manière dont l'objet à invoquer est résolu. Par «résolu», nous entendons simplement, où et comment le conteneur recherche l'instance réelle à invoquer.
Dans CDI, le conteneur regarde dans une "portée", qui sera essentiellement une carte de hachage qui vit pendant une période de temps spécifique (par requête @RequestScoped
, par session HTTP @SessionScoped
, par application @ApplicationScoped
, conversation JSF @ConversationScoped
ou selon votre implémentation de portée personnalisée).
Dans EJB, le conteneur regarde également dans une table de hachage si le bean est de type @Stateful
. Un @Stateful
bean peut également utiliser l'une des annotations de portée ci-dessus le faisant vivre et mourir avec tous les autres beans de la portée. Dans EJB, il @Stateful
y a essentiellement le bean «any scoped». Il @Stateless
s'agit essentiellement d'un pool d'instances - vous obtenez une instance du pool pour la durée d'un appel. Le @Singleton
est essentiellement@ApplicationScoped
Donc, au niveau fondamental, tout ce que vous pouvez faire avec un bean "EJB" devrait pouvoir être fait avec un bean "CDI". Sous les couvertures, il est extrêmement difficile de les distinguer. Toute la plomberie est la même à l'exception de la façon dont les instances sont résolues.
Ils ne sont actuellement pas les mêmes en termes de services que le conteneur offrira lors de ce proxy, 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 pourriez avoir. C'est tout 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 assez 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 à peu près aucune différence de performance entre l'appel d'un EJB et l'appel d'un bean CDI.
Par défaut sur POJO, puis CDI, puis EJB
Bien sûr, n'utilisez pas CDI ou EJB quand il n'y a aucun avantage. Ajoutez CDI lorsque vous commencez à vouloir une injection, des événements, des intercepteurs, des décorateurs, un suivi du cycle de vie et des choses comme ça. C'est la plupart du temps.
Au - delà de ces bases, il y a un certain nombre de services de conteneurs utiles que vous avez seulement la possibilité d'utiliser si vous faites votre grain de CDI également un EJB en ajoutant @Stateful
, @Stateless
ou @Singleton
sur elle.
Voici une courte liste des moments où j'éclate les EJB.
Utilisation de JAX-WS
Exposer un JAX-WS @WebService
. Je suis fainéant. Lorsque le @WebService
est également un EJB, vous n'avez pas besoin de le lister et de le mapper en tant que servlet dans le 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 à @Stateless
et @Singleton
seulement.
Utilisation de JAX-RS
Exposer une ressource JAX-RS via @Path
. Je suis toujours paresseux. Lorsque le service RESTful est également un EJB, vous obtenez à nouveau une découverte automatique et vous n'avez pas à l'ajouter à une Application
sous - classe JAX-RS ou à quelque chose de ce genre. De plus, je peux exposer exactement le même bean que @WebService
si je veux ou utiliser l'une des fonctionnalités mentionnées ci-dessous.
Disponible à @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
événement dans le cycle de vie du conteneur. Si nous avions fait cela, vous auriez simplement pu avoir un @ApplicationScoped
haricot qui l'écoutait et qui serait effectivement la même chose qu'un @Singleton
avec @Startup
. C'est sur la liste pour CDI 1.1.
Disponible @Singleton
uniquement pour .
Travailler en parallèle
@Asynchronous
invocation de méthode. Le démarrage des threads est un non-non dans tout environnement côté serveur. Avoir trop de threads est un sérieux tueur de performances. Cette annotation vous permet de paralléliser les choses que vous faites à l'aide du pool de threads du conteneur. C'est génial.
Disponible pour @Stateful
, @Stateless
et @Singleton
.
Planification des travaux
@Schedule
ou ScheduleExpression
est essentiellement un cron ou une Quartz
fonctionnalité. Aussi très génial. La plupart des conteneurs utilisent simplement du quartz sous les couvercles pour cela. Cependant, la plupart des gens ne savent pas que la planification du travail dans Java EE est transactionnelle! Si vous mettez à jour une base de données puis planifiez un travail et que l'un d'entre eux échoue, les deux seront automatiquement nettoyés. Si l' EntityManager
appel persistant échoue ou en cas de problème de vidage, il n'est pas nécessaire d'annuler la planification du travail. Ouais, les transactions.
Disponible à @Stateless
et @Singleton
seulement.
Utilisation d'EntityManagers dans une transaction JTA
La note ci-dessus sur les transactions vous oblige bien sûr à utiliser un JTA
fichier géré EntityManager
. Vous pouvez les utiliser avec un simple "CDI", mais sans les transactions gérées par le conteneur, cela peut devenir vraiment monotone en dupliquant la UserTransaction
logique de validation / annulation.
Disponible à tous les composants Java EE , y compris CDI, JSF @ManagedBean
, @WebServlet
, @WebListener
, @WebFilter
, etc. L' @TransactionAttribute
annotation, cependant, est disponible pour @Stateful
, @Stateless
et @Singleton
seulement.
Gérer JTA EntityManager
Le EXTENDED
géré EntityManager
vous permet de garder une EntityManager
ouverture entre les JTA
transactions et de ne pas perdre les données mises en cache. Bonne fonctionnalité pour le bon moment et au bon endroit. Utilisez de manière responsable :)
Disponible @Stateful
uniquement pour .
Synchronisation facile
Lorsque vous avez besoin de synchronisation, les annotations @Lock(READ)
et @Lock(WRITE)
sont plutôt excellentes. Il vous permet d'obtenir gratuitement une gestion des accès simultanés. Ignorez toute la plomberie ReentrantReadWriteLock. Dans le même compartiment se trouve @AccessTimeout
, ce qui vous permet de dire combien de temps un thread doit attendre pour accéder à l'instance du bean avant d'abandonner.
Disponible uniquement pour les @Singleton
haricots.