Wo kann man EJB 3.1 und CDI verwenden?

120

Ich mache ein Java EE-basiertes Produkt, in dem ich GlassFish 3 und EJB 3.1 verwende.

Meine Anwendung verfügt über Session Beans , einen Scheduler und verwendet Webdienste. Ich habe kürzlich Apache TomEE kennengelernt , das Contexts and Dependency Injection (CDI) unterstützt . Der GlassFish-Container unterstützt auch CDI.

Kann ich Session Beans ersetzen, für die ich keine Funktion benötige, die CDI auch noch nicht bietet? Und wenn ja, welche Vorteile kann ich erhalten?

Dhrumil Shah
quelle

Antworten:

408

Ja, Sie können sowohl CDI als auch EJB frei mischen und einige großartige Ergebnisse erzielen. Es hört sich so an, als würden Sie @WebServiceund verwenden @Schedule, was gute Gründe sind, EJB zum Mix hinzuzufügen.

Es gibt da draußen viel Verwirrung, daher hier einige allgemeine Informationen zu EJB und CDI, die sich auf beide zusammen beziehen.

EJB> = CDI

Beachten Sie, dass EJBs sind CDI Bohnen und haben deshalb alle die Vorteile von CDI. Das Gegenteil ist (noch) nicht der Fall. Gewöhnen Sie sich also definitiv nicht an, "EJB vs CDI" zu denken, da diese Logik wirklich zu "EJB + CDI vs CDI" führt, was eine seltsame Gleichung ist.

In zukünftigen Versionen von Java EE werden wir sie weiterhin ausrichten. Was Mittel Ausrichten Personen erlauben, zu tun , was sie bereits tun können, nur ohne die @Stateful, @Statelessoder @SingletonAnmerkung an der Spitze.

EJB und CDI in Implementierungsbedingungen

Letztendlich haben EJB und CDI das gleiche grundlegende Design wie Proxy-Komponenten. Wenn Sie einen Verweis auf eine EJB- oder CDI-Bean erhalten, handelt es sich nicht um die echte Bean. Vielmehr ist das Objekt, das Sie erhalten, eine Fälschung (ein Proxy). Wenn Sie eine Methode für dieses gefälschte Objekt aufrufen, geht der Anruf an den Container, der den Anruf über Abfangjäger, Dekorateure usw. sendet und sich um alle Transaktionen oder Sicherheitsüberprüfungen kümmert. Sobald alles erledigt ist, geht der Anruf schließlich an das reale Objekt und das Ergebnis wird über den Proxy an den Anrufer zurückgegeben.

Der Unterschied besteht nur darin, wie das aufzurufende Objekt aufgelöst wird. Mit "gelöst" meinen wir einfach, wo und wie der Container nach der realen Instanz sucht, die aufgerufen werden soll.

In CDI sieht der Container in einem "Bereich" aus, bei dem es sich im Grunde um eine Hashmap handelt, die für einen bestimmten Zeitraum gültig ist (pro Anforderung @RequestScoped, pro HTTP-Sitzung @SessionScoped, pro Anwendung @ApplicationScoped, JSF-Konversation @ConversationScopedoder gemäß Ihrer benutzerdefinierten Bereichsimplementierung).

In EJB untersucht der Container auch eine Hashmap, wenn die Bean vom Typ ist @Stateful. Eine @StatefulBean kann auch eine der oben genannten Bereichsanmerkungen verwenden, wodurch sie mit allen anderen Bohnen im Bereich lebt und stirbt. In EJB @Statefulist im Wesentlichen die "jede Scoped" Bohne. Dies @Statelessist im Grunde ein Instanzpool - Sie erhalten eine Instanz aus dem Pool für die Dauer eines Aufrufs. Das @Singletonist im Wesentlichen@ApplicationScoped

Grundsätzlich sollte alles, was Sie mit einer "EJB" -Bohne tun können, mit einer "CDI" -Bohne möglich sein. Unter der Decke ist es furchtbar schwer, sie auseinander zu halten. Alle Installationen sind gleich, mit Ausnahme der Art und Weise, wie Instanzen aufgelöst werden.

Sie sind derzeit nicht dieselben in Bezug auf die Dienste, die der Container bei diesem Proxy anbietet, aber wie gesagt, wir arbeiten auf der Java EE-Spezifikationsebene daran.

Leistungshinweis

Ignorieren Sie alle "leichten" oder "schweren" mentalen Bilder, die Sie möglicherweise haben. Das ist alles Marketing. Sie haben größtenteils das gleiche interne Design. Die Auflösung von CDI-Instanzen ist möglicherweise etwas komplexer, da sie etwas dynamischer und kontextbezogener ist. Die Auflösung der EJB-Instanz ist im Vergleich ziemlich statisch, dumm und einfach.

Ich kann Ihnen aus Sicht der Implementierung in TomEE sagen, dass zwischen dem Aufrufen eines EJB und dem Aufrufen einer CDI-Bean etwa kein Leistungsunterschied besteht.

Standardmäßig POJOs, dann CDI, dann EJB

Verwenden Sie CDI oder EJB natürlich nicht, wenn es keinen Nutzen gibt. Werfen Sie CDI ein, wenn Sie Injektionen, Ereignisse, Abfangjäger, Dekorateure, Lebenszyklus-Tracking und ähnliches wünschen. Das ist die meiste Zeit.

Abgesehen von diesen Grundlagen, gibt es eine Reihe von nützlichen Containerdienste nur Sie haben die Möglichkeit, zu verwenden , wenn Sie Ihre CDI Bean auch ein EJB durch Zugabe machen @Stateful, @Statelessoder @Singletonauf sie.

Hier ist eine kurze Liste, wann ich die EJBs ausbreche.

Verwenden von JAX-WS

JAX-WS verfügbar machen @WebService. Ich bin faul. Wenn das @WebServiceauch ein EJB ist, müssen Sie es nicht auflisten und als Servlet in der web.xmlDatei zuordnen . Das ist Arbeit für mich. Außerdem habe ich die Möglichkeit, eine der anderen unten genannten Funktionen zu verwenden. Für mich ist das also ein Kinderspiel.

Verfügbar für @Statelessund @Singletonnur.

Verwenden von JAX-RS

Offenlegen einer JAX-RS-Ressource über @Path. Ich bin immer noch faul. Wenn der RESTful-Dienst auch ein EJB ist, erhalten Sie erneut eine automatische Erkennung und müssen ihn nicht zu einer JAX-RS- ApplicationUnterklasse oder Ähnlichem hinzufügen . Außerdem kann ich genau die gleiche Bohne wie eine aussetzen, @WebServicewenn ich eine der unten genannten großartigen Funktionen nutzen möchte oder möchte.

Verfügbar für @Statelessund @Singletonnur.

Startlogik

Laden beim Start über @Startup. Derzeit gibt es in CDI kein Äquivalent dazu. Irgendwie haben wir es versäumt, so etwas wie ein AfterStartupEreignis in den Container-Lebenszyklus einzufügen. Wenn wir das getan hätten, hätten Sie einfach eine @ApplicationScopedBohne haben können, die darauf gehört hat, und das wäre praktisch dasselbe wie eine @Singletonmit @Startup. Es ist auf der Liste für CDI 1.1.

Nur für verfügbar @Singleton.

Parallel arbeiten

@AsynchronousMethodenaufruf. Das Starten von Threads ist in jeder serverseitigen Umgebung ein No-No. Zu viele Threads zu haben, ist ein ernstzunehmender Leistungskiller. Mit dieser Anmerkung können Sie Dinge parallelisieren, die Sie mithilfe des Thread-Pools des Containers ausführen. Das ist fantastisch.

Zur Verfügung @Stateful, @Statelessund @Singleton.

Arbeit planen

@Scheduleoder ScheduleExpressionist im Grunde ein Cron oder eine QuartzFunktionalität. Auch sehr genial. Die meisten Behälter verwenden dafür nur Quarz unter der Decke. Die meisten Leute wissen jedoch nicht, dass Planungsarbeiten in Java EE transaktional sind! Wenn Sie eine Datenbank aktualisieren und dann einige Arbeiten planen und eine davon fehlschlägt, werden beide automatisch bereinigt. Wenn der EntityManagerAufruf zum Fortbestehen fehlschlägt oder ein Problem beim Löschen auftritt, müssen Sie die Planung der Arbeit nicht aufheben. Ja, Transaktionen.

Verfügbar für @Statelessund @Singletonnur.

Verwenden von EntityManagern in einer JTA-Transaktion

Der obige Hinweis zu Transaktionen erfordert natürlich die Verwendung eines JTAverwalteten EntityManager. Sie können sie mit einfachem "CDI" verwenden, aber ohne die von Containern verwalteten Transaktionen kann es wirklich eintönig werden, die UserTransactionCommit / Rollback-Logik zu duplizieren .

Verfügbar für alle Java EE - Komponenten einschließlich CDI, JSF @ManagedBean, @WebServlet, @WebListener, @WebFilterusw. Die @TransactionAttributeAnmerkung ist jedoch zur Verfügung @Stateful, @Statelessund @Singletonnur.

JTA verwaltet halten EntityManager

Mit der EXTENDEDverwalteten Funktion EntityManagerkönnen Sie EntityManagerzwischen JTATransaktionen offen bleiben und die zwischengespeicherten Daten nicht verlieren. Gutes Feature für die richtige Zeit und den richtigen Ort. Verantwortungsbewusst verwenden :)

Nur für verfügbar @Stateful.

Einfache Synchronisation

Wenn Sie eine Synchronisierung benötigen, sind die @Lock(READ)und @Lock(WRITE)Anmerkungen ziemlich gut. Sie können damit gleichzeitig kostenlos gleichzeitig verwalten. Überspringen Sie alle ReentrantReadWriteLock-Leitungen. Im selben Bucket @AccessTimeoutkönnen Sie angeben, wie lange ein Thread warten soll, um Zugriff auf die Bean-Instanz zu erhalten, bevor er aufgibt.

Nur für @SingletonBohnen verfügbar .

David Blevins
quelle
32
Mein Gott, David :) Ich denke, du hast es abgedeckt.
LightGuard
7
Vielen Dank für diese Antwort. Sie haben die Verstopfung in meinem Kopf beseitigt und viele Punkte verbunden.
Thupten
7
Dies ist bei weitem die beste Erklärung zu diesem Thema, die ich je gelesen habe. Es deckt auch fast alle wichtigen Aspekte von EJB im realen Gebrauch ab. Gute Arbeit!!
Nanoquack
3
Sehr verständlich und Adam ist rechtlich nicht falsch, aber die Unterscheidung ist umstritten. Die Spezifikation besagt, dass die EJB-Instanz nicht kontextabhängig ist, später jedoch, dass der Verweis (Proxy) auf die EJB kontextbezogen ist. Der Lebenszyklus einer Stateful Bean wird vollständig über die Referenz (Proxy) gesteuert. Wenn also der CDI-Container diese Referenz (Proxy) steuert, wird die Mathematik gleich ausgegeben - Stateful EJBs können effektiv kontextbezogen sein.
David Blevins
3
Haben Sie dies in Ihrer Mittagspause bei TESLA geschrieben?
Edison
2

Wenn Sie wirklich keine der Funktionen von ejb 3.1 verwenden, ist die Antwort einfach. Vermutlich deutet Ihre Frage jedoch darauf hin, dass Sie den Verdacht haben, dass es ejb 3.1-Konzepte gibt, von denen Sie profitieren, ohne sich dessen bewusst zu sein. Ein Beispiel könnte sein, dass der Container einen Pool von slsb für die Verwendung bereithalten kann, sodass JMS- und Datenbankverbindungen nicht als Teil der Anforderung eingefügt werden müssen

Aksel Willgert
quelle