Java EE 6 @ javax.annotation.ManagedBean contre @ javax.inject.Named et @ javax.faces.ManagedBean

107

Je pense qu'il y a un petit désordre dans la spécification Java EE 6. Il existe plusieurs ensembles d'annotations.

Nous avons des javax.ejbannotations comme @Statefulet @Statelesspour créer des EJB.

Il existe également un @javax.annotation.ManagedBeanpour créer un bean géré.

Il y a des annotations dans javax.enterprise.contextlike @SessionScopedet @RequestScoped.

De plus, il y a aussi des annotations @ManagedBeanet @SessionScoped/ @RequestScopeddans le javax.faces.beanpackage.

Et pour compliquer les choses, il existe un package javax.injectavec @Namedannotation.

Quelqu'un peut-il s'il vous plaît décrire comment ils sont liés les uns aux autres?

Où puis - je utiliser @EJB, @Injectou @ManagedProperyd'injecter d' autres haricots?

Piotr Gwiazda
la source
Voir aussi: stackoverflow.com/questions/4684112/…
Arjan Tijms

Réponses:

194

Tout d'abord, permettez-moi de faire quelques éclaircissements:

Définition du bean géré : généralement un bean géré est un objet dont son cycle de vie (construction, destruction, etc.) est géré par un conteneur.

Dans Java ee, nous avons de nombreux conteneurs qui gèrent le cycle de vie de leurs objets, comme le conteneur JSF, le conteneur EJB, le conteneur CDI, le conteneur Servlet, etc.

Tous ces conteneurs fonctionnent de manière indépendante, ils démarrent lors de l'initialisation du serveur d'applications et analysent les classes de tous les artefacts, y compris les fichiers jar, ejb-jar, war et ear au moment du déploiement, et collectent et stockent des métadonnées à leur sujet, puis lorsque vous avez besoin d'un objet d'une classe au moment de l'exécution, ils vous donneront des instances de ces classes et après avoir terminé le travail, ils les détruiront.

Nous pouvons donc dire que nous avons:

  • Beans gérés JSF
  • Beans gérés par CDI
  • Beans gérés par EJB
  • Et même les servlets sont des beans gérés car ils sont instanciés et détruits par un conteneur, qui est un conteneur de servlet.

Ainsi, lorsque vous voyez le mot Managed Bean, vous devez vous renseigner sur le contexte ou le type de celui-ci (JSF, CDI, EJB, etc.)

Ensuite, vous pourriez vous demander pourquoi nous avons beaucoup de ces conteneurs: AFAIK, les gars de Java EE voulaient avoir un cadre d'injection de dépendances, mais ils ne pouvaient pas rassembler toutes les exigences dans une spécification car ils ne pouvaient pas prédire les exigences futures et ils ont créé EJB 1.0 et ensuite 2.0 puis 3.0 et maintenant 3.1 mais la cible d'EJB était juste pour certaines exigences (transaction, modèle de composant distribué, etc.).

En même temps (en parallèle), ils ont réalisé qu'ils devaient également prendre en charge JSF, puis ils ont créé des beans gérés par JSF et un autre conteneur pour les beans JSF et ils l'ont considéré comme un conteneur DI mature, mais ce n'était toujours pas un conteneur complet et mature.

Après cela, Gavin King et d'autres gentils gars;) ont créé CDI qui est le conteneur DI le plus mature que j'ai vu. CDI (inspiré de Seam2, Guice et Spring) a été conçu pour combler le vide entre JSF et EJB et beaucoup d'autres choses utiles comme l'injection de pojo, les méthodes de production, les intercepteurs, les décorateurs, l'intégration SPI, très flexible, etc. et cela peut même le faire. ce que font les beans gérés EJB et JSF, nous ne pouvons alors avoir qu'un seul conteneur DI mature et puissant. Mais pour des raisons de rétrocompatibilité et des raisons politiques, les gars de Java EE veulent les conserver !!!

Vous trouverez ici la différence et les cas d'utilisation pour chacun de ces types:

Beans gérés JSF, Beans CDI et EJB

JSF a été initialement développé avec son propre mécanisme d'injection de bean géré et de dépendances qui a été amélioré pour JSF 2.0 pour inclure des beans basés sur des annotations. Lorsque CDI a été publié avec Java EE 6, il était considéré comme le framework de bean géré pour cette plate-forme et, bien sûr, les EJB les dépassaient tous depuis plus d'une décennie.

Le problème est bien sûr de savoir lequel utiliser et quand les utiliser.

Commençons par les beans gérés JSF les plus simples.

Beans gérés JSF

En bref, ne les utilisez pas si vous développez pour Java EE 6 et utilisez CDI. Ils fournissent un mécanisme simple pour l'injection de dépendances et la définition de beans de sauvegarde pour les pages Web, mais ils sont beaucoup moins puissants que les beans CDI.

Ils peuvent être définis à l'aide de l' @javax.faces.bean.ManagedBeanannotation qui prend un paramètre de nom facultatif. Ce nom peut être utilisé pour référencer le bean à partir des pages JSF.

L'étendue peut être appliquée au bean en utilisant l'une des différentes étendues définies dans le javax.faces.beanpackage qui incluent la demande, la session, l'application, la vue et les étendues personnalisées.

@ManagedBean(name="someBean")
@RequestScoped
public class SomeBean {
    ....
    ....
}

Les beans JSF ne peuvent pas être mélangés avec d'autres types de beans sans une sorte de codage manuel.

Haricots CDI

CDI est le cadre de gestion de bean et d'injection de dépendances qui a été publié dans le cadre de Java EE 6 et il comprend une fonction de bean géré complète et complète. Les beans CDI sont bien plus avancés et flexibles que de simples beans gérés JSF. Ils peuvent utiliser les intercepteurs, la portée de la conversation, les événements, l'injection sécurisée de type, les décorateurs, les stéréotypes et les méthodes de production.

Pour déployer des beans CDI, vous devez placer un fichier appelé beans.xml dans un dossier META-INF sur le chemin de classe. Une fois que vous faites cela, chaque bean du package devient un bean CDI. Il y a beaucoup de fonctionnalités dans CDI, trop nombreuses pour être couvertes ici, mais comme référence rapide pour les fonctionnalités de type JSF, vous pouvez définir la portée du bean CDI en utilisant l'une des portées définies dans le javax.enterprise.contextpackage (à savoir, demande, conversation , les portées de session et d'application). Si vous souhaitez utiliser le bean CDI à partir d'une page JSF, vous pouvez lui donner un nom à l'aide de l' javax.inject.Namedannotation. Pour injecter un bean dans un autre bean, vous annotez le champ avec une javax.inject.Injectannotation.

@Named("someBean")
@RequestScoped
public class SomeBean {

    @Inject
    private SomeService someService;
}

L'injection automatique comme celle définie ci-dessus peut être contrôlée grâce à l'utilisation de qualificatifs qui peuvent aider à faire correspondre la classe spécifique que vous souhaitez injecter. Si vous disposez de plusieurs types de paiement, vous pouvez ajouter un qualificatif indiquant s'il est asynchrone ou non. Bien que vous puissiez utiliser l' @Namedannotation comme qualificatif, vous ne devriez pas le faire car il est fourni pour exposer les beans en EL.

CDI gère l'injection de beans avec des portées incompatibles grâce à l'utilisation de proxies. Pour cette raison, vous pouvez injecter un bean de portée de requête dans un bean de portée de session et la référence sera toujours valide sur chaque requête car pour chaque requête, le proxy se reconnecte à une instance active du bean de portée de requête.

CDI prend également en charge les intercepteurs, les événements, la nouvelle portée de conversation et de nombreuses autres fonctionnalités, ce qui en fait un bien meilleur choix par rapport aux beans gérés JSF.

EJB

Les EJB sont antérieurs aux beans CDI et sont en quelque sorte similaires aux beans CDI et très différents à d'autres égards. Principalement, la différence entre les beans CDI et les EJB est que les EJB sont:

  • Transactionnel
  • À distance ou local
  • Capable de passiver les beans avec état en libérant des ressources
  • Capable d'utiliser des minuteries
  • Peut être asynchrone

Les deux types d'EJB sont appelés sans état et avec état. Les EJB sans état peuvent être considérés comme des beans à usage unique thread-safe qui ne maintiennent aucun état entre deux requêtes Web. Les EJB avec état conservent l'état et peuvent être créés et rester en place aussi longtemps que nécessaire jusqu'à ce qu'ils soient éliminés.

La définition d'un EJB est simple, il vous suffit d'ajouter une javax.ejb.Statelessou une javax.ejb.Statefulannotation à la classe.

@Stateless
public class BookingService {

  public String makeReservation(Item Item, Customer customer) {
    ...
    ...
  }
}

Les beans sans état doivent avoir une portée dépendante tandis qu'un bean session avec état peut avoir n'importe quelle portée. Par défaut, ils sont transactionnels, mais vous pouvez utiliser l'annotation d'attribut de transaction.

Alors que les EJB et les beans CDI sont très différents en termes de fonctionnalités, l'écriture du code pour les intégrer est très similaire puisque les beans CDI peuvent être injectés dans les EJB et les EJB peuvent être injectés dans les beans CDI. Il n'est pas nécessaire de faire de distinction lors de l'injection de l'un dans l'autre. Encore une fois, les différentes portées sont gérées par CDI via l'utilisation de proxy. Une exception à cela est que CDI ne prend pas en charge l'injection d'EJB distants, mais cela peut être implémenté en écrivant une méthode de producteur simple pour cela.

L' javax.inject.Namedannotation ainsi que tous les qualificatifs peuvent être utilisés sur un EJB pour le faire correspondre à un point d'injection.

Quand utiliser quel haricot

Comment savoir quand utiliser quel grain? Facile.

N'utilisez jamais de beans gérés JSF à moins que vous ne travailliez dans un conteneur de servlet et que vous ne vouliez pas essayer de faire fonctionner CDI dans Tomcat (bien qu'il existe des archétypes Maven pour cela, il n'y a donc aucune excuse).

En général, vous devez utiliser des beans CDI, sauf si vous avez besoin des fonctionnalités avancées disponibles dans les EJB, telles que les fonctions transactionnelles. Vous pouvez écrire votre propre intercepteur pour rendre les beans CDI transactionnels, mais pour l'instant, il est plus simple d'utiliser un EJB jusqu'à ce que CDI obtienne des beans CDI transactionnels, ce qui est juste au coin de la rue. Si vous êtes coincé dans un conteneur de servlet et que vous utilisez CDI, les transactions écrites à la main ou votre propre intercepteur de transactions sont la seule option sans EJB.

Si vous devez utiliser @ViewScopedCDI, vous devez

  • utilisez le module Seam -faces ou MyFaces CODI . ajoutez simplement l'un d'entre eux à votre chemin de classe et @ViewScopedfonctionnera dans CDI. MyFaces CODI a un support encore plus solide de @ViewScoped
  • utilisez MyFaces CODI @ViewAccessScoped, c'est une extension écrite sur CDI par Apache, téléchargez-la simplement et utilisez l' @ViewAccessScopedannotation au lieu de @ViewScoped.
  • Utilisez CDI @ConversationScopedet rendez-le long. Voir ici pour plus d'informations .
  • Utiliser l' annotation Omnifaces @ViewScoped

Certaines pièces ont été volées d' ici .

Mehdi
la source
3
C'est bien! Merci! Pour être complet, dites simplement comment injecter le bean CDI ou EJB dans le bean JSF. Est-ce @ManagedProperty("#{someBean})"la bonne manière?
Piotr Gwiazda
2
Nan! ça ne marchera pas. il suffit de transformer votre bean géré jsf en bean géré CDI en l'annotant à l'aide de @Namedet @javax.enterprise.context.RequestScopedet d'utiliser l'injection CDI en utilisant l'annotation @Inject. n'utilisez pas de beans gérés par jsf si vous n'êtes pas obligé;).
Mehdi
3
> Les gars de JEE veulent les garder !!! - C'est un peu plus subtil que ça. CDI s'est terminé assez tard dans le cycle Java EE 6 et JSF 2 et JAX-RS étaient déjà terminés. Ils avaient amélioré resp. a déjà lancé sa propre installation de gestion des haricots. Si CDI avait été disponible un peu plus tôt, les choses auraient pu se présenter différemment. Dans Java EE 7, JSF adoptera CDI et javax.faces.bean sera finalement obsolète (la dépréciation est un processus lent dans Java EE, ce qui est à la fois bon et mauvais).
Arjan Tijms
3
Lorsque vous dites: Pour déployer des beans CDI, vous devez placer un fichier appelé beans.xml dans un dossier META-INF sur le chemin de classe. Une fois que vous faites cela, chaque bean du package devient un bean CDI. Voulez-vous dire que chaque bean devient également un bean CDI en plus de ce qu'il était? Que faire si j'ai JSF ManagedBeans avec ManagedBean et ViewScoped. Ce sont toujours des Beans gérés par JSF, n'est-ce pas?
Koray Tugay
3
Quelqu'un capable de faire une mise à jour pour Java EE 7 sur cet excellent article?
Martijn Burger
7

Oui, cela peut être déroutant.

Pour certaines EHM raisons historiques JSF et CDI utilisent les mêmes annotations pour les étendues, mais de différents forfaits.

Comme vous le devinez probablement, ceux de javax.faces.beansont issus de la spécification JSF et ne sont pas liés à CDI. Ne les utilisez que si vous avez une très bonne raison de le faire. Et ne les mélangez jamais avec les annotations CDI de javax.ejb. Cela produira une liste infinie de bogues et d'anomalies subtiles.

Je vous recommande généralement de parcourir les premières pages (voire plus) de l'excellente documentation Weld . Cela devrait vous mettre sur la bonne voie pour Java EE 6.

Et n'hésitez pas à poster d'autres questions ici.

Jan Groth
la source
En fait, j'ai deux questions: 1. Je trouve souvent la portée de la vue très utile. J'ai besoin d'utiliser les annotations JSF alors? 2. Cela signifie que @javax.annotation.ManagedBeanc'est inutile car CDI traite toutes les classes comme des beans gérés, ai-je raison?
Piotr Gwiazda
Pas assez. Vous aurez besoin de relier les portées JSF à CDI avec par exemple Seam Faces. Et oui, @ManagedBeans n'est pas nécessaire si vous avez un beans.xml dans le fichier jar approprié. Oh, et si vous avez d'autres questions, il est préférable de commencer un nouveau fil avant de nous perdre dans la section des commentaires.
jan groth
3

Puisqu'il n'y a pas de réponse spécifique @javax.annotation.ManagedBean, voici un lien vers la réponse à une question similaire: Backing beans (@ManagedBean) ou CDI Beans (@Named)? . La spécification peut être trouvée à http://download.oracle.com/otndocs/jcp/managed_beans-1.0-fr-eval-oth-JSpec/ . Il me semble donc que @javax.annotation.ManagedBeanc'était censé être une généralisation de @javax.faces.bean.ManagedBean.

D'après ce que j'ai compris, JSF Managed Beans est progressivement éliminé au profit de CDI Beans (peut-être devenant obsolète de JSF 2.3?), Donc je suppose que cela @javax.annotation.ManagedBeandevient d'autant plus obsolète maintenant.

Hein Blöd
la source
@Namedremplacera @ManagedBeanà l'avenir?
Thufir
1
J'ai lu plusieurs déclarations de différents experts Java EE qui prédisent que les @Namedbeans CDI remplaceront JSF @ManagedBeans, par exemple dans stackoverflow.com/questions/4347374/… , BalusC dit: «On s'attend à ce que @ManagedBean et ses amis soient obsolètes selon Java EE 8. ".
Hein Blöd