Où utiliser EJB 3.1 et CDI?

120

Je crée un produit basé sur Java EE dans lequel j'utilise GlassFish 3 et EJB 3.1.

Mon application a des beans session , un planificateur et utilise des services Web. J'ai récemment découvert Apache TomEE , qui prend en charge les contextes et l'injection de dépendances (CDI) . Le conteneur GlassFish prend également en charge CDI.

Puis-je remplacer des session beans lorsque je n'ai besoin d'aucune fonctionnalité que CDI ne fournit pas déjà? Et si oui, quels avantages puis-je obtenir?

Dhrumil Shah
la source

Réponses:

408

Oui, vous pouvez mélanger librement CDI et EJB et obtenir d'excellents résultats. On dirait que vous utilisez @WebServiceet @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, @Statelessou l' @Singletonannotation 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 @ConversationScopedou 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 @Statefulbean 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 @Statefuly a essentiellement le bean «any scoped». Il @Statelesss'agit essentiellement d'un pool d'instances - vous obtenez une instance du pool pour la durée d'un appel. Le @Singletonest 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, @Statelessou @Singletonsur 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 @WebServiceest également un EJB, vous n'avez pas besoin de le lister et de le mapper en tant que servlet dans le web.xmlfichier. 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 à @Statelesset @Singletonseulement.

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 Applicationsous - classe JAX-RS ou à quelque chose de ce genre. De plus, je peux exposer exactement le même bean que @WebServicesi je veux ou utiliser l'une des fonctionnalités mentionnées ci-dessous.

Disponible à @Statelesset @Singletonseulement.

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 @ApplicationScopedharicot qui l'écoutait et qui serait effectivement la même chose qu'un @Singletonavec @Startup. C'est sur la liste pour CDI 1.1.

Disponible @Singletonuniquement pour .

Travailler en parallèle

@Asynchronousinvocation 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, @Statelesset @Singleton.

Planification des travaux

@Scheduleou ScheduleExpressionest essentiellement un cron ou une Quartzfonctionnalité. 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' EntityManagerappel 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 à @Statelesset @Singletonseulement.

Utilisation d'EntityManagers dans une transaction JTA

La note ci-dessus sur les transactions vous oblige bien sûr à utiliser un JTAfichier 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 UserTransactionlogique de validation / annulation.

Disponible à tous les composants Java EE , y compris CDI, JSF @ManagedBean, @WebServlet, @WebListener, @WebFilter, etc. L' @TransactionAttributeannotation, cependant, est disponible pour @Stateful, @Statelesset @Singletonseulement.

Gérer JTA EntityManager

Le EXTENDEDgéré EntityManagervous permet de garder une EntityManagerouverture entre les JTAtransactions 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 @Statefuluniquement 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 @Singletonharicots.

David Blevins
la source
32
Mon Dieu, David :) Je pense que vous l'avez couvert.
LightGuard
7
Merci pour cette réponse. Vous avez effacé le sabot dans ma tête et connecté beaucoup de points.
Jeudi
7
C'est de loin la meilleure explication sur ce sujet que j'ai jamais lue. Il couvre également presque tous les aspects importants de l'EJB dans la vie réelle. Bon travail!!
nanoquack
3
Très compréhensible et Adam n'a pas tort en termes juridiques stricts, mais la distinction est sans objet. La spécification indique que l'instance EJB n'est pas contextuelle, mais indique ensuite que la référence (proxy) à l'EJB est contextuelle. Le cycle de vie d'un bean avec état est entièrement contrôlé par la référence (proxy), donc lorsque le conteneur CDI contrôle cette référence (proxy), le calcul est le même - les EJB avec état peuvent effectivement être contextuels.
David Blevins
3
Avez-vous écrit ceci lors de votre pause déjeuner à TESLA?
Edison
2

si vous n'utilisez vraiment aucune des fonctionnalités d'ejb 3.1, la réponse est simple. mais supposez que votre question indique que vous pensez qu'il y a des concepts ejb 3.1 dont vous bénéficiez sans en être conscient. un exemple pourrait être que le conteneur peut garder un pool de slsb prêt à être utilisé, de sorte que les connexions jms et de base de données n'aient pas à être injectées dans le cadre de la requête

Aksel Willgert
la source