Am 14. September 2017 haben wir eine überarbeitete Fassung unserer Datenschutzrichtlinie veröffentlicht. Wenn Sie video2brain.com weiterhin nutzen, erklären Sie sich mit diesem überarbeiteten Dokument einverstanden. Bitte lesen Sie es deshalb sorgfältig durch.

Java EE 7 Grundkurs

Gültigkeitsbereiche von CDI-Beans

LinkedIn Learning kostenlos und unverbindlich testen!

Jetzt testen Alle Abonnements anzeigen
Die CDI verfügt über mehrere unterschiedliche Gültigkeitsbereiche, welche Beans zugewiesen werden können. Das Wissen darüber erleichtert es einem Programmierer, diese sinnvoll einzusetzen.

Transkript

CDI ist die Abkürzung für Context and Dependency Injection. Ein Teil von Dependency Injection ist das Einfügen von Abhängigkeiten, ein anderer Teil ist Context, also Kontexte. Aus diesem Grund werden wir uns in diesem Video, mit den Gültigkeitsbereich und Kontexten, die uns CDI bereitstellt, befassen. Generell ist es so, dass sich eine Bean stets in einem Gültigkeitsbereich befindet und mit einem Kontext assoziiert ist. Der Kontext selbst ist dabei verantwortlich für Lebenszyklus und Sichtbarkeit. Es gibt potenziell verschiedene Implementierungen eines Kontextes, dies obliegt letztlich dem Anbieter der Komponente, welchen Kontext er einsetzt. Eine Bean, und das ist das für uns interessantere, wird immer für einen Gültigkeitsbereich erzeugt und auch meistens nur einmal für einen Gültigkeitsbereich erzeugt und dann wiederverwendet. Der charmante Aspekte der CDI ist, dass sich nutzende Komponenten um den Gültigkeitsbereich nicht kümmern müssen. Das bedeutet, CDI sorgt dafür, dass ein entsprechendes Stellvertreter-Objekt bereit steht und dass intern im Zweifelsfall eine Komponente erzeugt wird, wenn sie benötigt wird. Die Gültigkeitsbereiche von Komponenten sind stets auf Bean- oder Produzentenebene definierbar. Das heißt, sie werden über Annotationen ausgedrückt. Es gibt verschiedene definierte Gültigkeitsbereiche, die in der CDI verwendet werden können. Der erste Gültigkeitsbereich ist "RequestScoped". Das bedeutet, eine Bean ist an einen Web-Requests gebunden. Das heißt, bei der Anfrage an den Server wird diese Bean erzeugt, wenn sie genutzt werden soll und sie ist so lange aktiv, bis der Server die aktuelle Anfrage abgeschlossen hat. Danach wird diese Bean verworfen. "SessionScoped" bedeutet, dass eine Bean an eine Benutzersitzung gebunden ist. Auch das ist im Webumfeld ein Konstrukt und das bedeutet, dass eine Bean über mehrere Anforderungen hinweg für einen definierten Zeitraum aktiv sein kann. So eine Session hat einen gleitenden Gültigkeitsbereich. Das bedeutet, wenn innerhalb des noch aktiven Gültigkeitsbereiches eine weitere Anfrage dieses Nutzers kommt, wird die Session entsprechend verlängert und damit bleibt auch die Bean aktiv und gültig. Ein weiterer Kontext ist "ApplicationScoped". "ApplicationScoped" bedeutet, dass die Bean an den Lebenszyklus der kompletten Applikation gebunden ist. Das bedeutet letztlich nichts anderes, als dass es diese Bean genau einmal gibt, so lange, wie es diese Applikation gibt. "ConversationScoped" ist eine Mischung zwischen Request- und SessionScopes. Dieser Kontext wird relativ selten eingesetzt, erlaubt es jedoch, bspw. Assistenten oder ähnliche Funktionalitäten umzusetzen. Der StandardScope ist "Dependent". "Dependent" bedeutet, dass die Bean letztlich in keinem anderen Gültigkeitsbereich existiert. Bei "DependentScopes" wird bei jedem Aufruf der Bean eine neue Instanz erzeugt. Ein weiterer Scope ist "Singleton". "Singleton" bedeutet, dass diese Bean genau einmal existiert. Und zuletzt gibt es den, trotz des Namens, veralteten "NewScope". Den sollte man nicht mehr benutzen. "New" bedeutet, dass bei jedem Aufruf eine neue Instanz erzeugt wird. Dies wird aber auch über den "DependenceScope" abgebildet. Aus diesem Grund ist "New" mittlerweile veraltet und "deprecated". Beans, die sich in einem Gültigkeitsbereich befinden, werden niemals direkt referenziert, auch wenn das in Ihrem Code so aussieht, sondern, es wird von der CDI-Runtime ein Proxy erzeugt und dann letztlich an dem Injection Point zugewiesen. Der Proxy selber kümmert sich um alle Interna, das bedeutet, wenn es notwendig ist, eine neue Instanz zu erzeugen, wird eine neue Instanz erzeugt. Dies obliegt nicht Ihrem Aufgabenbereich, sondern wird von der Umgebung geleistet. Eine Ausnahme ist der "DependentScope", beziehungsweise der "SingletonScope". Hier hält der Client direkt eine Referenz auf die Bean. Das bedeutet, die Bean wird, bei mehrfacher Injektion, niemals mehrfach verwendet werden, sondern sie wird jedes mal neu erzeugt werden. Der "DependentScope" selbst hat noch eine weitere Eigenschaft, wenn wir ihn mit Hilfe von Expression-Language-Ausdrücken verwenden, wird bei jedem Zugriff auf die Bean eine neue Instanz erstellt. Das bedeutet, Sie sollten mit Beans, die den Scope "Dependent" haben, besser nicht mit Expression-Language-Ausdrücken arbeiten. Zum "SingletonScope" sei noch angemerkt, dass dieser nicht mehr verwendet werden sollte. Wir sollten heutzutage besser "ApplicationScoped" verwenden, denn dies hat denselben Effekt. Lassen Sie uns nun anschauen, wie wir Scopes definieren können und welche Auswirkungen Scopes haben können. Wir befinden uns hier in einem Servlet. Dieses Servlet hat einen Injection Point, an dem eine KontakteManager-Instanz injiziert wird. Diese KontakteManager-Instanz ist eine normale CDI-verwaltete Klasse, die mit der Annotation "Dependent" markiert ist. Das heißt, bei jeder Injection wird eine neue Instanz erzeugt. Intern hält diese KontakteManager Instanz eine Implementierung der KontakteProvider-Klasse. Diese KontakteProvider-Klasse bietet uns die Möglichkeit, dass wir eine Liste von Namen verwalten können. Das ist aber eigentlich gar nicht relevant, relevant ist vielmehr, dass die entsprechende Instanz in einem Producer erzeugt wird und als letzter Eintrag in diesem Producer die aktuelle Uhrzeit ausgegeben wird. Dies werden wir nutzen, um zu überprüfen, wie sich die verschiedenen Scopes verhalten. Lassen Sie uns die Applikation einmal starten. Die Applikation läuft nunmehr und wir sehen als letzten Eintrag, die aktuelle Zeit. Wenn wir die Seite aktualisieren, müsste sich die Zeit ändern. Dies scheint sie nicht zu tun. Lassen Sie uns kurz darüber nachdenken, wo hier das Problem liegen könnte, denn schließlich injizieren wir ja an genau dieser Stelle eine als "Dependent" markierte Komponente. Nun, des Rätsels Lösung liegt darin, dass wir ein Servlet verwenden. Ein Servlet hat nämlich einen ganz spezifischen Lebenszyklus. Es wird beim ersten Aufruf einmal erzeugt und danach mit genau dieser Instanz bis zum Verwerfen und Entladen der Webapplikation weiter genutzt. Das bedeutet aber auch, dass Injection nur genau einmal stattfindet, und da wir hier durch die "Dependent"-Annotation eine einzelne direkte Instanz das KontakteManagers halten, wird genau diese einzelne Instanz die ganze Zeit verwendet und deswegen ändert sich die Uhrzeit nicht. Um das Verhalten zu ändern, wechseln wir zurück in den KontakteManager und markieren diesen KontakteManager nunmehr als "RequestScoped". Achten Sie bitte darauf, dass Sie die richtige "RequestScoped"-Annotation aus dem "javax.enterprise.context" Package verwenden. Es gibt noch eine zweite, die ist aber für unsere Zwecke nicht relevant. Nachdem wir den KontakteManager nunmehr als "RequestScoped" markiert haben, können wir die Applikation neu auf dem Server deployen, und werden nunmehr das gewünschte Verhalten erhalten, dass nämlich bei jedem Aufruf die Uhrzeit neu generiert wird. Wunderbar. "RequestScope" funktioniert nunmehr. Der Grund, warum es nunmehr funktioniert, ist, dass wir an dieser Stelle jetzt keine direkte Instanz mehr halten, sondern nur noch ein Proxy und dieser Proxy erledigt die Verwaltung des Lebenszyklusses für uns. Dies erlaubt es uns auch den Scope des KontakteManagers zu ändern, von "RequestScoped" auf "SessionScoped". Achten Sie allerdings darauf, dass auch "SessionScoped" im richtigen Package liegen muss, nämlich "javax.enterprise.context" und alle Komponenten, die als "SessionScoped" markiert sind, müssen das Interface "Serializable" implementieren. Dies ist ein Marker-Interface, das bedeutet für uns letztlich, dass wir keine weitere Implementierung tätigen müssen. Wichtig ist jedoch, dass auch alle Komponenten, die von dieser Komponente verwendet werden, ebenfalls das entsprechende Interface, nämlich "Serializable" implementieren. Dies muss gewährleistet sein. Das ist in dem Fall auf Ebene dieses TestKontaktProviders der Fall. Wäre dies nicht der Fall, gäbe es Exceptions. Nun können wir die Applikation erneut deployen. Und wenn wir sie nunmehr aufrufen, werden wir feststellen, dass sich die Uhrzeit beim mehrfachen Aufrufen nicht mehr ändert. Dies ist ein logisches und richtiges Verhalten, denn es ist immer dieselbe Benutzersitzung. Wenn wir jetzt allerdings einen Browser öffnen und in dem Browser die entsprechende Adresse aufrufen, haben wir eine zweite Benutzersitzung. In diesem Fall ändert sich die Uhrzeit und unterscheidet sich von der ersten Benutzersitzung. Hier steht sie auf 12:05 und 11 Sekunden und in der ersten Benutzersitzung steht sie bei 12:04 und 49 Sekunden und wenn ich die Seite aktualisiere, ändert sie sich nicht, denn die Bean wird nur einmal erzeugt und liegt im "SessionScope". So lange wie diese Sitzung aktiv ist, wird sie dann darin verbleiben. Ein Wort noch zu den Scopes. Wenn wir einen Producer haben, wie hier, die Erzeugung des KontakteProviders, dann können wir auch auf Ebene dieses Producers Scopes angeben. Geben wir keinen Scope an, ist das, was dort erzeugt wird, immer "Dependent". Das bedeutet letztlich, dass es sich den Kontext mit der Komponente teilt, in die es injiziert wird. Wenn wir möchten, dass die hier erzeugte Komponente einen anderen Scope hat, dann können wir das machen, indem wir sie ebenfalls, beispielsweise "SessionScoped" annotieren. Sobald dies erledigt ist, wird jetzt in den KontakteManager auch kein direkter Verweis mehr auf den KontakteProvider injiziert, sondern, es wird ein Proxy injiziert und das bedeutet letztlich, dass auch der KontakteManager einen anderen Lebenszyklus haben kann, beispielsweise "Dependent". Da dieser als "Dependent" markierte Komponente nunmehr eine Komponente hält, die ihrerseits "SessionScoped" ist, wird sich das gleiche Verhalten zeigen, wie das, was wir gerade eben auch hatten, nur eben mit einer anderen Implementierung. Lassen Sie uns das kurz überprüfen, indem wir die Applikation, nachdem wir diese Änderungen vorgenommen haben, neu deployen, und die entsprechenden Aufrufe tätigen. Die Uhrzeit ändert sich einmal und danach ändert sie sich für diesen Benutzer nicht. Analoges gilt für den anderen Benutzer. Hier ändert sich die Uhrzeit auch einmal und danach nicht mehr. Die interne Implementierung ist allerdings eine andere. Für Sie bleibt mitzunehmen, verwenden Sie diese Gültigkeitsbereiche, also "SessionScoped", "RequestScoped" "ApplicationScoped", "Dependent" oder "ConversationScoped" bewusst. Überlegen Sie sich, in welchen Szenarien Sie diese verschiedenen Gültigkeits- und Lebenszyklus-Bereiche benötigen und setzen Sie Ihre Applikation entsprechend um. Sie können damit das Verhalten grundlegend ändern und steuern.

Java EE 7 Grundkurs

Lernen Sie die Grundlagen der Programmierung mit Java EE 7 verstehen und anwenden.

6 Std. 4 min (44 Videos)
Derzeit sind keine Feedbacks vorhanden...
 

Dieser Online-Kurs ist als Download und als Streaming-Video verfügbar. Die gute Nachricht: Sie müssen sich nicht entscheiden - sobald Sie das Training erwerben, erhalten Sie Zugang zu beiden Optionen!

Der Download ermöglicht Ihnen die Offline-Nutzung des Trainings und bietet die Vorteile einer benutzerfreundlichen Abspielumgebung. Wenn Sie an verschiedenen Computern arbeiten, oder nicht den ganzen Kurs auf einmal herunterladen möchten, loggen Sie sich auf dieser Seite ein, um alle Videos des Trainings als Streaming-Video anzusehen.

Wir hoffen, dass Sie viel Freude und Erfolg mit diesem Video-Training haben werden. Falls Sie irgendwelche Fragen haben, zögern Sie nicht uns zu kontaktieren!