Backing beans (@ManagedBean) ou CDI Beans (@Named)?

109

Je viens de commencer à lire Core JavaServer Faces, 3e éd. et ils disent ceci (c'est moi qui souligne):

C'est un accident historique qu'il existe deux mécanismes distincts, les beans CDI et les beans gérés JSF, pour les beans qui peuvent être utilisés dans les pages JSF. Nous vous suggérons d'utiliser des beans CDI, sauf si votre application doit fonctionner sur un exécuteur de servlet simple tel que Tomcat.

Pourquoi? Ils ne fournissent aucune justification. J'ai utilisé @ManagedBeanpour tous les beans dans une application prototype fonctionnant sur GlassFish 3, et je n'ai pas vraiment remarqué de problèmes avec cela. Cela ne me dérange pas particulièrement de migrer de @ManagedBeanvers @Named, mais je veux savoir pourquoi je devrais me déranger .

Matt Ball
la source
4
@Bozho: cette question est assez similaire, mais après avoir lu la réponse de Pascal à quelques reprises, je ne comprends toujours pas pourquoi CDI est de loin supérieur. Je ne connais pas CDI et je suis heureux de l'apprendre car c'est "mieux". Pourquoi est-ce mieux?
Matt Ball
"sauf si votre application doit fonctionner sur un simple exécuteur de servlet tel que Tomcat" Je n'utilise que tomcat et je recommande fortement CDI. Tomcat peut le supporter très bien
Karl Kildén
1
@ KarlKildén "plain servlet runner" fait référence à un conteneur de servlet non compatible CDI. Au moment d'écrire ces lignes, Tomcat ne supportait pas le CDI, sauf avec un peu de magie.
Thorbjørn Ravn Andersen

Réponses:

64

CDI est préféré au JSF simple car CDI permet l'injection de dépendances à l'échelle de JavaEE. Vous pouvez également injecter des POJO et les laisser gérer. Avec JSF, vous ne pouvez injecter qu'un sous-ensemble de ce que vous pouvez avec CDI.

Bozho
la source
Donc, fondamentalement, je peux injecter une instance de presque n'importe quelle classe (à condition qu'elle ait "le bon matériel" - qu'est - ce que c'est, juste un constructeur sans argument? ) Avec CDI, alors que je dois l'utiliser @ManagedBeansi je veux l'injecter avec plain JSF?
Matt Ball
3
@MattBall Matt après vos années, pouvez-vous commenter cette migration?
Koray Tugay
5
@KorayTugay Je n'ai pas touché à ce code depuis juin 2011 mais j'étais passé au CDI et les choses fonctionnaient très bien. Je suis heureux de répondre à toutes les questions spécifiques au meilleur de ma mémoire si vous les avez.
Matt Ball
170

Utilisez CDI.

Selon JSF 2.3, @ManagedBean est obsolète . Voir également le numéro de spécification 1417 . Cela signifie que il n'y a pas plus d' une raison de choisir @ManagedBeanplus @Named. Cela a été implémenté pour la première fois dans la version bêta de Mojarra 2.3.0 m06.

entrez la description de l'image ici


L'histoire

La principale différence est qu'elle @ManagedBeanest gérée par le framework JSF et n'est @ManagedPropertydisponible que via un autre beans gérés JSF. @Namedest géré par le serveur d'application (le conteneur) via le framework CDI et est @Injectdisponible pour tout type d'artefact géré par conteneur comme @WebListener,@WebFilter , @WebServlet, @Path, @Stateless, etc. et même un JSF @ManagedBean. De l'autre côté, @ManagedPropertyne fonctionne pas dans un @Namedou tout autre artefact géré par conteneur. Cela ne fonctionne vraiment qu'à l'intérieur @ManagedBean.

Une autre différence est que CDI injecte en fait des proxys déléguant à l'instance actuelle dans la portée cible sur une base par requête / thread (comme la façon dont les EJB sont injectés). Ce mécanisme permet d'injecter un bean de portée plus étroite dans un bean de portée plus large, ce qui n'est pas possible avec JSF @ManagedProperty. JSF "injecte" ici l'instance physique directement en invoquant un setter (c'est aussi exactement pourquoi un setter est nécessaire, alors que ce n'est pas obligatoire avec @Inject).

Bien que ce ne soit pas directement un inconvénient - il existe d'autres moyens - la portée de @ManagedBeanest simplement limitée. D'un autre point de vue, si vous ne voulez pas exposer "trop" pour @Inject, vous pouvez aussi simplement conserver vos beans gérés @ManagedBean. C'est comme protectedcontre public. Mais cela ne compte pas vraiment.

Au moins, dans JSF 2.0 / 2.1, le principal inconvénient de la gestion des backing beans JSF par CDI est qu'il n'y a pas d'équivalent CDI de @ViewScoped. Le @ConversationScopedse rapproche, mais nécessite toujours un démarrage et un arrêt manuels et ajoute un cidparamètre de demande laid aux URL de résultat. MyFaces CODI facilite les choses en reliant de manière totalement transparente les JSF javax.faces.bean.ViewScopedà CDI afin que vous puissiez simplement le faire @Named @ViewScoped, mais cela ajoute un vilainwindowId paramètre de requête aux URL de résultat, également sur la navigation simple de page à page. OmniFaces résout tout cela avec un vrai CDI @ViewScopedqui lie vraiment la portée du bean à l'état de vue JSF plutôt qu'à un paramètre de requête arbitraire.

JSF 2.2 (qui sort 3 ans après cette question / réponse) offre une nouvelle @ViewScopedannotation entièrement compatible CDI prête à l'emploi dans la saveur de javax.faces.view.ViewScoped. JSF 2.2 est même livré avec un CDI uniquement @FlowScopedqui n'a pas d' @ManagedBeanéquivalent, poussant ainsi les utilisateurs JSF vers CDI. On s'attend à ce que les @ManagedBeanamis soient obsolètes selon Java EE 8. Si vous l'utilisez toujours @ManagedBean, il est donc fortement recommandé de passer à CDI pour être préparé aux futurs chemins de mise à niveau. CDI est facilement disponible dans des conteneurs compatibles Java EE Web Profile, tels que WildFly, TomEE et GlassFish. Pour Tomcat, vous devez l'installer séparément, exactement comme vous l'avez déjà fait pour JSF. Voir aussi Comment installer CDI dans Tomcat?

BalusC
la source
4
J'ai créé beans.xml, converti des @ManagedBeanbacking beans en @Namedet convertis @ManagedPropertyen @Inject. Tout va bien avec le monde. Cependant, si je change mes @EJBannotations en @Inject, le déploiement échoue ( org.jboss.weld.exceptions.DeploymentException) avec message WELD-001408 Injection point has unsatisfied dependencies. Dois-je réellement utiliser @Injectpour injecter des EJB sans interface dans un @Namedbean, ou devrais-je m'en tenir @EJB? Les EJB sont emballés dans un JAR EJB, dans le même EAR que le WAR qui contient mes beans CDI.
Matt Ball
Cela devrait juste fonctionner. Êtes-vous toujours confronté à ce problème avec la version actuelle de Weld?
BalusC
Hélas, je ne pourrais pas le dire. Cette question est posée par 2 employeurs et il y a plus de 2 ans. Sur la base de mon ancien commentaire sur la réponse de Bozho, j'ai dû basculer vers CDI / @Named.
Matt Ball
"MyFaces CODI facilite la tâche en reliant de manière totalement transparente javax.faces.bean.ViewScoped de JSF à CDI pour que vous puissiez simplement le faire @Named @ViewScoped, mais cela ajoute un paramètre de requête windowId laid aux URL de résultat, également sur la navigation simple de page à page." Notez qu'avec DeltaSpike, cela n'est plus vrai. Vous pouvez désactiver les paramètres d'URL dsId et windowId, si vous n'avez pas besoin de l'étendue de la fenêtre.
janvier 2013
1
@Jan: Et en attendant, OmniFaces a également un JSF 2.2-like @ViewScopedpour JSF 2.0 / 2.1: showcase.omnifaces.org/cdi/ViewScoped
BalusC
16

Avec Java EE 6 et CDI, vous avez différentes options pour Managed Beans

  • @javax.faces.bean.ManagedBeanfait référence à JSR 314 et a été introduit avec JSF 2.0. L'objectif principal était d'éviter la configuration dans le fichier faces-config.xml pour utiliser le bean dans une page JSF.
  • @javax.annotation.ManagedBean(“myBean”) est défini par JSR 316. Il généralise les beans gérés JSF pour une utilisation ailleurs dans Java EE
  • @javax.inject.Named(“myBean”) sont presque les mêmes que celui ci-dessus, sauf que vous avez besoin d'un fichier beans.xml dans le dossier web / WEB-INF pour activer CDI.
h2mch
la source
1
Quelle est la différence entre les deux premiers?
Matt Ball
Le but de la première annotation est / était de remplacer la configuration du bean dans le faces-config.xml pour l'utilisation dans JSF. Le second copie le concept dans le "conteneur java ee 6". Il a plus de fonctions (comme les annotations @PostConstruct et @PreDestroy), mais est également accessible par la page JSF (avec Expression Language).
h2mch
1
pourquoi avez-vous besoin d'un beans.xmlfichier? Est-ce toujours vrai aujourd'hui?
Thufir
2
Non, avec JavaEE7, vous n'avez plus besoin du beans.xml. voir docs.oracle.com/javaee/7/tutorial/doc/cdi-adv001.htm
h2mch
1
Avec JavaEE7, vous n'avez pas besoin des beans.xml: docs.oracle.com/javaee/7/tutorial/cdi-adv001.htm (lien correct) blogs.oracle.com/theaquarium/entry/… (activation CDI par défaut en Java EE 7)
M. Atif Riaz
2

J'utilisais CDI dans GlassFish 3.0.1, mais pour le faire fonctionner, j'ai dû importer le framework Seam 3 (Weld). Cela a plutôt bien fonctionné.

Dans GlassFish 3.1, CDI a cessé de fonctionner et le Seam Weld a cessé de fonctionner avec. J'ai ouvert un bug à ce sujet mais je ne l'ai pas encore vu corrigé. J'ai dû convertir tout mon code en utilisant les annotations javax.faces. * Mais je prévois de revenir au CDI une fois qu'il fonctionnera.

Je suis d'accord que vous devriez utiliser CDI, mais un problème que je n'ai pas encore vu résolu est ce qu'il faut faire avec l'annotation @ViewScoped. J'ai beaucoup de code qui en dépend. Il n'est pas clair si @ViewScoped fonctionne si vous n'utilisez pas @ManagedBean avec lui. Si quelqu'un peut clarifier cela, je l'apprécierais.

AlanObject
la source
-1

Une bonne raison de passer à CDI: vous pourriez avoir une ressource commune à la session (profil utilisateur par exemple) @Inject dans les beans gérés JSF et les services REST (c'est-à-dire Jersey / JAX-RS).

D'autre part, @ViewScopedest une raison impérieuse de s'en tenir à JSF@ManagedBean - en particulier pour tout ce qui a un AJAX important. Il n'y a pas de remplacement standard pour cela dans CDI.

Semble qu'il peut avoir un certain soutien pour un @ViewScoped annotation-like pour les beans CDI, mais je n'ai pas joué avec personnellement.

http://seamframework.org/Seam3/FacesModule

Wrschneider
la source