133 votes

Où utiliser EJB 3.1 et CDI ?

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

Ma demande a haricots de session Il s'agit d'un planificateur et il utilise des services Web. J'ai récemment appris l'existence de Apache TomEE qui soutient Contextes et injection de dépendances (CDI) . Le conteneur GlassFish supporte également le CDI.

Puis-je remplacer les beans de session lorsque je n'ai pas besoin d'une fonctionnalité que CDI ne fournit pas déjà ? Et si oui, quels sont les avantages que je peux en tirer ?

452voto

David Blevins Points 10502

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.

36 votes

Ciel, David :) Je pense que tu as tout couvert.

8 votes

Merci pour cette réponse. Vous avez débloqué la situation dans ma tête et relié beaucoup de points.

9 votes

C'est de loin la meilleure explication sur ce sujet que j'aie jamais lue. Il couvre également presque tous les aspects importants d'EJB dans la vie réelle. Excellent travail !

2voto

Aksel Willgert Points 3791

Si vous n'utilisez vraiment aucune des fonctionnalités d'ejb 3.1, la réponse est simple. mais je suppose que votre question indique que vous soupçonnez 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 ne doivent pas être injectées dans le cadre de la demande.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X