Java EE 6 @ javax.annotation.ManagedBean vs. @ javax.inject.Named vs. @ javax.faces.ManagedBean

106

Ich habe das Gefühl, dass die Java EE 6-Spezifikation ein wenig durcheinander ist. Es gibt mehrere Sätze von Anmerkungen.

Wir haben javax.ejbAnmerkungen wie @Statefulund @Statelesszum Erstellen von EJBs.

Es gibt auch eine @javax.annotation.ManagedBeanMöglichkeit, eine verwaltete Bean zu erstellen.

Es gibt Anmerkungen in javax.enterprise.contextlike @SessionScopedund @RequestScoped.

Darüber hinaus gibt es auch @ManagedBeanund @SessionScoped/ @RequestScopedAnmerkungen im javax.faces.beanPaket.

Und um das Ereignis noch komplizierter zu gestalten, gibt es ein Paket javax.injectmit @NamedAnmerkungen.

Kann jemand bitte beschreiben, wie sie miteinander verwandt sind?

Wo kann ich @EJB, @Injectoder @ManagedProperyandere Bohnen zu injizieren?

Piotr Gwiazda
quelle
Siehe auch: stackoverflow.com/questions/4684112/…
Arjan Tijms

Antworten:

193

Lassen Sie mich zunächst einige Klarstellungen vornehmen:

Definition einer verwalteten Bean: Im Allgemeinen ist eine verwaltete Bean ein Objekt, dessen Lebenszyklus (Konstruktion, Zerstörung usw.) von einem Container verwaltet wird.

In Java ee gibt es viele Container, die den Lebenszyklus ihrer Objekte verwalten, z. B. JSF-Container, EJB-Container, CDI-Container, Servlet-Container usw.

Alle diese Container arbeiten unabhängig voneinander. Sie booten in der Anwendungsserverinitialisierung und scannen Klassen aller Artefakte, einschließlich JAR-, EJB-JAR-, War- und Ear-Dateien, in der Bereitstellungszeit und sammeln und speichern einige Metadaten darüber, wenn Sie ein Objekt benötigen einer Klasse zur Laufzeit geben sie Ihnen Instanzen dieser Klassen und nach Beendigung des Jobs zerstören sie sie.

Wir können also sagen, dass wir:

  • JSF verwaltete Beans
  • CDI verwaltete Beans
  • EJB verwaltete Bohnen
  • Und selbst Servlets sind verwaltete Beans, weil sie von einem Container, einem Servlet-Container, instanziiert und zerstört werden.

Wenn Sie also das Managed Bean-Wort sehen, sollten Sie nach dem Kontext oder Typ des Wortes fragen (JSF, CDI, EJB usw.).

Dann könnten Sie sich fragen, warum wir viele dieser Container haben: AFAIK, Java EE-Leute wollten ein Abhängigkeitsinjektions-Framework, aber sie konnten nicht alle Anforderungen in einer Spezifikation erfassen, weil sie die zukünftigen Anforderungen nicht vorhersagen konnten und EJB 1.0 und dann erstellten 2.0 und dann 3.0 und jetzt 3.1, aber das Ziel von EJB waren nur einige Anforderungen (Transaktion, verteiltes Komponentenmodell usw.).

Gleichzeitig (parallel) erkannten sie, dass sie auch JSF unterstützen müssen, dann stellten sie JSF-verwaltete Beans und einen weiteren Container für JSF-Beans her und betrachteten es als ausgereiften DI-Container, aber es war immer noch kein vollständiger und ausgereifter Container.

Danach haben Gavin King und einige andere nette Leute CDI gemacht, das ist der ausgereifteste DI-Container, den ich je gesehen habe. CDI (inspiriert von Seam2, Guice und Spring) wurde entwickelt, um die Lücke zwischen JSF und EJB und vielen anderen nützlichen Dingen wie Pojo-Injektion, Herstellungsmethoden, Abfangjägern, Dekorateuren, Integrations-SPI, sehr flexibel usw. zu schließen Was EJB- und JSF-verwaltete Beans tun, können wir nur einen ausgereiften und leistungsstarken DI-Container haben. Aber aus Gründen der Abwärtskompatibilität und aus politischen Gründen wollen Java EE-Leute sie behalten !!!

Hier finden Sie den Unterschied und die Anwendungsfälle für jeden dieser Typen:

JSF Managed Beans, CDI Beans und EJBs

JSF wurde ursprünglich mit einem eigenen verwalteten Bean- und Abhängigkeitsinjektionsmechanismus entwickelt, der für JSF 2.0 um annotationsbasierte Beans erweitert wurde. Als CDI mit Java EE 6 veröffentlicht wurde, wurde es als verwaltetes Bean-Framework für diese Plattform angesehen, und natürlich haben EJBs sie alle veraltet, da es sie schon seit mehr als einem Jahrzehnt gibt.

Das Problem ist natürlich zu wissen, welche und wann sie verwendet werden sollen.

Beginnen wir mit den einfachsten, JSF Managed Beans.

JSF Managed Beans

Kurz gesagt, verwenden Sie sie nicht, wenn Sie für Java EE 6 entwickeln und CDI verwenden. Sie bieten einen einfachen Mechanismus für die Abhängigkeitsinjektion und die Definition von Backing Beans für Webseiten, sind jedoch weitaus weniger leistungsfähig als CDI Beans.

Sie können mithilfe der @javax.faces.bean.ManagedBeanAnmerkung definiert werden, die einen optionalen Namensparameter verwendet. Dieser Name kann verwendet werden, um auf die Bean von JSF-Seiten zu verweisen.

Der Bereich kann auf die Bean angewendet werden, indem einer der verschiedenen im javax.faces.beanPaket definierten Bereiche verwendet wird , einschließlich der Bereiche Anforderung, Sitzung, Anwendung, Ansicht und Benutzerdefiniert.

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

JSF-Beans können ohne manuelle Codierung nicht mit anderen Beansorten gemischt werden.

CDI Bohnen

CDI ist das Bean-Management- und Abhängigkeitsinjektions-Framework, das als Teil von Java EE 6 veröffentlicht wurde und eine vollständige, umfassende Managed-Bean-Funktion enthält. CDI-Beans sind weitaus fortschrittlicher und flexibler als einfache JSF-verwaltete Beans. Sie können Interceptors, Konversationsumfang, Ereignisse, typsichere Injektionen, Dekorateure, Stereotypen und Herstellungsmethoden verwenden.

Um CDI-Beans bereitzustellen, müssen Sie eine Datei mit dem Namen beans.xml in einem META-INF-Ordner im Klassenpfad ablegen. Sobald Sie dies tun, wird jede Bean im Paket zu einer CDI-Bean. Es gibt viele Funktionen in CDI, zu viele, um sie hier zu behandeln. Als Kurzreferenz für JSF-ähnliche Funktionen können Sie den Umfang der CDI-Bean mithilfe eines der im javax.enterprise.contextPaket definierten Bereiche definieren (nämlich Anforderung, Konversation) , Sitzungs- und Anwendungsbereiche). Wenn Sie die CDI-Bean von einer JSF-Seite verwenden möchten, können Sie ihr mithilfe der javax.inject.NamedAnmerkung einen Namen geben . Um eine Bean in eine andere Bean einzufügen, kommentieren Sie das Feld mit javax.inject.InjectAnnotation.

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

    @Inject
    private SomeService someService;
}

Eine automatische Injektion wie die oben definierte kann durch die Verwendung von Qualifikatoren gesteuert werden, die dazu beitragen können, die spezifische Klasse zu erreichen, die Sie injizieren möchten. Wenn Sie mehrere Zahlungsarten haben, können Sie ein Qualifikationsmerkmal hinzufügen, ob es asynchron ist oder nicht. Sie können die @NamedAnnotation zwar als Qualifikationsmerkmal verwenden, sollten dies jedoch nicht tun, da sie zum Anzeigen der Beans in EL bereitgestellt wird.

CDI behandelt die Injektion von Bohnen mit nicht übereinstimmenden Bereichen mithilfe von Proxys. Aus diesem Grund können Sie eine Bean mit Anforderungsbereich in eine Bean mit Sitzungsbereich einfügen, und die Referenz ist bei jeder Anforderung weiterhin gültig, da der Proxy für jede Anforderung erneut eine Verbindung zu einer Live-Instanz der Bean mit Anforderungsbereich herstellt.

CDI unterstützt auch Interceptors, Ereignisse, den neuen Konversationsbereich und viele andere Funktionen, was es zu einer viel besseren Wahl gegenüber von JSF verwalteten Beans macht.

EJB

EJBs sind älter als CDI-Beans und ähneln in gewisser Weise CDI-Beans und sind auf andere Weise sehr unterschiedlich. In erster Linie besteht der Unterschied zwischen CDI-Beans und EJBs darin, dass EJBs:

  • Transaktion
  • Remote oder lokal
  • Kann Stateful Beans passivieren und Ressourcen freisetzen
  • Kann Timer verwenden
  • Kann asynchron sein

Die beiden Arten von EJBs werden als zustandslos und zustandsbehaftet bezeichnet. Statuslose EJBs können als thread-sichere Single-Use-Beans betrachtet werden, die keinen Status zwischen zwei Webanforderungen beibehalten. Stateful EJBs halten den Status und können erstellt und so lange herumgesessen werden, wie sie benötigt werden, bis sie entsorgt werden.

Das Definieren eines EJB ist einfach. Fügen Sie der Klasse entweder eine javax.ejb.Statelessoder eine javax.ejb.StatefulAnmerkung hinzu.

@Stateless
public class BookingService {

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

Statuslose Beans müssen einen abhängigen Bereich haben, während ein Stateful Session Bean einen beliebigen Bereich haben kann. Standardmäßig sind sie transaktional, Sie können jedoch die Annotation für Transaktionsattribute verwenden.

Während sich EJBs und CDI-Beans hinsichtlich der Funktionen stark unterscheiden, ist das Schreiben des Codes zum Integrieren sehr ähnlich, da CDI-Beans in EJBs und EJBs in CDI-Beans injiziert werden können. Es ist nicht erforderlich, beim Einspritzen in das andere zu unterscheiden. Auch hier werden die verschiedenen Bereiche von CDI mithilfe von Proxy behandelt. Eine Ausnahme hiervon ist, dass CDI die Injektion von Remote-EJBs nicht unterstützt, dies jedoch durch Schreiben einer einfachen Herstellermethode implementiert werden kann.

Die javax.inject.NamedAnnotation sowie alle Qualifikationsmerkmale können auf einem EJB verwendet werden, um sie einem Injektionspunkt zuzuordnen.

Wann welche Bohne zu verwenden ist

Woher wissen Sie, wann Sie welche Bohne verwenden müssen? Einfach.

Verwenden Sie niemals JSF-verwaltete Beans, es sei denn, Sie arbeiten in einem Servlet-Container und möchten nicht versuchen, CDI in Tomcat zum Laufen zu bringen (obwohl es dafür einige Maven-Archetypen gibt, gibt es keine Entschuldigung).

Im Allgemeinen sollten Sie CDI-Beans verwenden, es sei denn, Sie benötigen die in den EJBs verfügbaren erweiterten Funktionen, z. B. Transaktionsfunktionen. Sie können Ihren eigenen Interceptor schreiben, um CDI-Beans transaktional zu machen. Derzeit ist es jedoch einfacher, einen EJB zu verwenden, bis CDI transaktionale CDI-Beans erhält, die sich gleich um die Ecke befinden. Wenn Sie in einem Servlet-Container stecken bleiben und CDI verwenden, sind entweder handgeschriebene Transaktionen oder Ihr eigener Transaktions-Interceptor die einzige Option ohne EJBs.

Wenn Sie @ViewScopedin CDI verwenden müssen, sollten Sie

  • verwenden Nahtflächen oder MyFaces CODI Modul. Fügen Sie einfach einen davon zu Ihrem Klassenpfad hinzu und er @ViewScopedfunktioniert in CDI. MyFaces CODI unterstützt @ViewScoped noch solider
  • Verwenden Sie MyFaces CODIs. Dies @ViewAccessScopedist eine Erweiterung, die von Apache auf CDI geschrieben wurde. Laden Sie sie einfach herunter und verwenden Sie @ViewAccessScopedstattdessen Annotation @ViewScoped.
  • Verwenden Sie CDI @ConversationScopedund machen Sie es langlebig. Sehen Sie hier für weitere Informationen .
  • Verwenden Sie die Annotation Omnifaces @ViewScoped

Einige Teile wurden von hier gestohlen .

Mehdi
quelle
3
Das ist toll! Vielen Dank! Um vollständig zu sein, erklären Sie einfach, wie Sie CDI- oder EJB-Beans in JSF-Beans injizieren. Ist @ManagedProperty("#{someBean})"der richtige Weg?
Piotr Gwiazda
2
Nee! es wird nicht funktionieren. Verwandeln Sie einfach Ihre jsf-verwaltete Bean in eine CDI-verwaltete Bean, indem Sie sie mit @Namedund @javax.enterprise.context.RequestScopedkommentieren und die CDI-Injection mit @Inject annotation verwenden. Verwenden Sie keine von jsf verwalteten Beans, wenn Sie dies nicht müssen;).
Mehdi
3
> JEE Jungs wollen sie behalten !!! - Es ist etwas subtiler. CDI wurde ziemlich spät im Java EE 6-Zyklus beendet und sowohl JSF 2 als auch JAX-RS waren bereits fertig. Sie hatten resp verbessert. haben bereits eine eigene Managed Bean-Anlage eingeführt. Wäre CDI etwas früher verfügbar gewesen, hätten die Dinge möglicherweise anders ausgesehen. In Java EE 7 wird JSF CDI übernehmen und die Datei javax.faces.bean wird schließlich veraltet sein (Verfall ist in Java EE jedoch ein langsamer Prozess, der sowohl gut als auch schlecht ist).
Arjan Tijms
3
Wenn Sie sagen: Um CDI-Beans bereitzustellen, müssen Sie eine Datei mit dem Namen beans.xml in einem META-INF-Ordner im Klassenpfad ablegen. Sobald Sie dies tun, wird jede Bean im Paket zu einer CDI-Bean. Meinen Sie damit, dass jede Bohne zusätzlich zu dem, was sie war, auch eine CDI-Bohne wird? Was ist, wenn ich JSF ManagedBeans mit ManagedBean und ViewScoped habe? Sie sind immer noch JSF Managed Beans, oder?
Koray Tugay
3
Kann jemand ein Update für Java EE 7 für diesen großartigen Artikel durchführen?
Martijn Burger
7

Ja, das kann verwirrend sein.

Für einige ehm historischen Gründen JSF und CDI werden mit den gleichen Annotationen für Bereiche, aber aus verschiedenen Paketen.

Wie Sie wahrscheinlich erraten haben, stammen diese von javax.faces.beanaus der JSF-Spezifikation und sind nicht mit CDI verwandt. Verwenden Sie sie nur, wenn Sie einen sehr guten Grund dafür haben. Und mischen Sie sie niemals mit CDI-Anmerkungen von javax.ejb. Dies führt zu einer endlosen Liste von Fehlern und subtilen Anomalien.

Ich empfehle generell, dass Sie die ersten paar (oder sogar mehr) Seiten der hervorragenden Schweißdokumentation überfliegen . Dies sollte Sie auf den richtigen Weg für Java EE 6 bringen.

Und zögern Sie nicht, hier weitere Fragen zu stellen.

Jan Groth
quelle
Eigentlich habe ich zwei Fragen: 1. Ich finde den Sichtbereich oft sehr nützlich. Muss ich dann JSF-Annotationen verwenden? 2. Das bedeutet, dass dies @javax.annotation.ManagedBeannutzlos ist, da CDI alle Klassen als verwaltete Beans behandelt. Stimmt das?
Piotr Gwiazda
Nicht ganz. Sie müssen JSF-Bereiche mit z. B. Seam Faces zu CDI verbinden. Und ja, @ManagedBeans werden nicht benötigt, wenn Sie eine beans.xml in der entsprechenden JAR-Datei haben. Oh, und wenn Sie weitere Fragen haben, ist es besser, einen neuen Thread zu starten, bevor wir uns im Kommentarbereich verlieren.
Jan Groth
3

Da es keine spezifischen Antworten gibt, finden Sie @javax.annotation.ManagedBeanhier einen Link zur Antwort auf eine ähnliche Frage: Backing Beans (@ManagedBean) oder CDI Beans (@Named)? . Die Spezifikation finden Sie unter http://download.oracle.com/otndocs/jcp/managed_beans-1.0-fr-eval-oth-JSpec/ . Es scheint mir also @javax.annotation.ManagedBeaneine Verallgemeinerung von zu sein @javax.faces.bean.ManagedBean.

Nach allem, was ich zusammengetragen habe, werden JSF Managed Beans zugunsten von CDI Beans auslaufen (möglicherweise von JSF 2.3 veraltet?). Ich denke, dies @javax.annotation.ManagedBeanwird jetzt umso veralteter.

Hein Blöd
quelle
@Namedwird @ManagedBeanin Zukunft ersetzen ?
Thufir
1
Ich habe mehrere Aussagen von verschiedenen Java EE-Experten gelesen, die vorhersagen, dass die CDI- @NamedBeans JSF ersetzen werden @ManagedBeans, z. B. in stackoverflow.com/questions/4347374/… . BalusC sagt: "Die Erwartung ist, dass @ManagedBean und Freunde gemäß Java veraltet sind EE 8. ".
Hein Blöd