web-dev-qa-db-fra.com

Où utiliser EJB 3.1 et CDI?

Je fabrique un Java EE dans lequel j'utilise GlassFish 3 et EJB 3.1.

Mon application a session beans , un planificateur et utilise les services Web. J'ai récemment appris à connaître Apache TomEE , qui prend en charge Injections de contextes et de dépendances (CDI) . Le conteneur GlassFish prend également en charge CDI.

Puis-je remplacer les beans de session lorsque je n'ai besoin d'aucune fonctionnalité que CDI ne fournit pas non plus? Et si ensuite, quels sont les avantages que je peux obtenir?

114
Dhrumil Shah

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 EJB au mélange.

Il y a beaucoup de confusion, alors voici quelques informations générales sur les EJB et les CDI dans la mesure où ils se rapportent.

EJB> = CDI

Notez que les EJB are beans CDI et ont donc tous les avantages de CDI. L'inverse n'est pas vrai (encore). Donc, ne prenez pas l'habitude de penser "EJB vs CDI", cette logique se traduisant par "EJB + CDI vs CDI", ce qui est une équation étrange.

Dans les futures versions de Java EE, nous allons continuer à les aligner. Ce que l'on entend par alignement, c'est permettre aux gens de faire ce qu'ils peuvent déjà faire, sans le @Stateful, @Stateless Ou @Singleton En haut.

EJB et CDI en termes de mise en œuvre

En fin de compte, EJB et CDI partagent le même concept fondamental de composants proxy. Lorsque vous obtenez une référence à un bean EJB ou CDI, ce n'est pas le véritable bean. L'objet qui vous est donné est plutôt un faux (un proxy). Lorsque vous appelez une méthode sur cet objet fictif, l'appel est dirigé vers le conteneur qui l'enverra via des intercepteurs, des décorateurs, etc., et s'occupera également de toute transaction ou vérification de sécurité. Une fois que tout est fait, l'appel est finalement dirigé vers l'objet réel et le résultat est renvoyé via le proxy à l'appelant.

La différence réside uniquement dans la manière dont l'objet à appeler est résolu. Par "résolu", nous voulons simplement dire où et comment le conteneur recherche l'instance réelle à appeler.

Dans CDI, le conteneur recherche dans une "portée", qui sera essentiellement une table de hachage qui durera une période donnée (par requête @RequestScoped, Par session HTTP @SessionScoped, Par application @ApplicationScoped, Conversation JSF @ConversationScoped, Ou selon votre implémentation d'étendue personnalisée).

Dans EJB, le conteneur examine également une table de hachage si le bean est de type @Stateful. Un haricot @Stateful Peut également utiliser n'importe laquelle des annotations ci-dessus, ce qui le fait vivre et mourir avec tous les autres haricots de l'étendue. Dans EJB @Stateful Est essentiellement le haricot "de n'importe quelle portée". Le @Stateless Est essentiellement un pool d'instances - vous obtenez une instance du pool pour la durée d'une invocation. Le @Singleton Est essentiellement @ApplicationScoped

Donc, à un niveau fondamental, tout ce que vous pouvez faire avec un haricot "EJB" devrait pouvoir être fait avec un haricot "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.

Actuellement, ils ne sont pas les mêmes en ce qui concerne les services que le conteneur offrira lors de ce traitement par proxy, mais comme je le disais, nous y travaillons au niveau des spécifications Java EE.

Note de performance

Ne tenez pas compte des images mentales "légères" ou "lourdes" que vous pourriez avoir. C'est tout le 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 légèrement plus dynamique et contextuelle. La résolution d'instance EJB est relativement 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 pratiquement aucune différence de performance entre invoquer un EJB et invoquer un bean CDI.

La valeur par défaut est POJOs, puis CDI, puis EJB.

Bien sûr, n'utilisez pas CDI ou EJB lorsqu'il n'y a aucun avantage. Ajoutez le CDI lorsque vous commencez à vouloir l'injection, les événements, les intercepteurs, les décorateurs, le suivi du cycle de vie, etc. C'est la plupart du temps.

Outre ces bases, il existe un certain nombre de services de conteneur utiles que vous ne pouvez utiliser que si vous faites de votre bean CDI un EJB en ajoutant @Stateful, @Stateless Ou @Singleton dessus.

Voici une courte liste de quand 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 répertorier et de le mapper en tant que servlet dans le fichier web.xml. C'est un travail pour moi. De plus, je peux utiliser l'une des fonctionnalités mentionnées ci-dessous. C'est donc une évidence pour moi.

Disponible uniquement pour @Stateless Et @Singleton.

Utilisation de JAX-RS

Exposer une ressource JAX-RS via @Path. Je suis encore paresseux. Lorsque le service RESTful est également un EJB, là encore, vous obtenez une découverte automatique et vous n'avez pas besoin de l'ajouter à une sous-classe JAX-RS Application ou quelque chose du genre. De plus, je peux exposer exactement le même haricot qu'un @WebService Si je souhaite utiliser l'une des fonctionnalités mentionnées ci-dessous.

Disponible uniquement pour @Stateless Et @Singleton.

Logique de démarrage

Charger au démarrage via @Startup. Il n'y a actuellement aucun équivalent à ceci dans CDI. D'une manière ou d'une autre, nous avons oublié d'ajouter quelque chose comme un événement AfterStartup dans le cycle de vie du conteneur. Si nous avions fait cela, vous auriez simplement pu avoir un haricot @ApplicationScoped Qui l'écoutait et qui serait en fait le même qu'un @Singleton Avec @Startup. C'est sur la liste pour CDI 1.1.

Disponible pour @Singleton Uniquement.

Travailler en parallèle

@Asynchronous Invocation de la méthode. Le démarrage de threads est interdit dans n'importe quel environnement côté serveur. Avoir trop de threads est un tueur de performance sérieux. Cette annotation vous permet de paralléliser ce que vous faites à l'aide du pool de threads du conteneur. C'est génial.

Disponible pour @Stateful, @Stateless Et @Singleton.

Travaux de planification

@Schedule Ou ScheduleExpression est fondamentalement une fonctionnalité cron ou Quartz. Aussi très génial. La plupart des conteneurs n'utilisent que du quartz sous les couvertures. La plupart des gens ne savent pas, cependant, que la planification fonctionne dans Java EE est transactionnel! Si vous mettez à jour une base de données, planifiez une partie du travail et l'une d'entre elles échoue; EntityManager l'appel persiste échoue ou en cas de problème de vidage, il n'est pas nécessaire d'annuler la planification du travail.

Disponible uniquement pour @Stateless Et @Singleton.

Utilisation d'EntityManagers dans une transaction JTA

La note ci-dessus sur les transactions nécessite bien sûr que vous utilisiez un JTA géré EntityManager. Vous pouvez les utiliser avec un "CDI" simple, mais sans les transactions gérées par le conteneur, la duplication de la logique UserTransaction commit/rollback peut être vraiment monotone.

Disponible pour tous Java EE, y compris CDI, JSF @ManagedBean, @WebServlet, @WebListener, @WebFilter, Etc. L'annotation @TransactionAttribute N'est toutefois disponible que pour @Stateful, @Stateless Et @Singleton.

Garder JTA géré EntityManager

Le EXTENDED géré EntityManager vous permet de garder un EntityManager ouvert entre les transactions JTA et de ne pas perdre les données mises en cache. Bon élément pour le bon moment et le bon endroit. Utilisez de manière responsable :)

Disponible pour @Stateful Uniquement.

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 la 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 avoir accès à l'instance de bean avant d'abandonner.

Disponible uniquement pour les haricots @Singleton.

375
David Blevins

si vous n’utilisez vraiment aucune des fonctionnalités de ejb 3.1, la réponse est simple. mais devinez, votre question indique que vous soupçonnez qu'il existe des concepts ejb 3.1 dont vous tirez parti sans en être conscients. un exemple pourrait être que le conteneur puisse 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 requête

2
Aksel Willgert