Java EE 7 Grundkurs

Interzeptoren

LinkedIn Learning kostenlos und unverbindlich testen!

Jetzt testen Alle Abonnements anzeigen
Interzeptoren dienen dazu, die Ausführung von Methodenaufrufen zu unterbrechen und diese zu kontrollieren. Der Trainer erläutert in diesem Video die Definition sowie den Einsatz von Interzeptoren.

Transkript

In diesem Video werden wir uns mit Interzeptoren befassen. Interzeptoren sind eine Möglichkeit, um in einer Anwendung sog. Cross Cutting Concerns oder übergreifende Anforderungen umzusetzen. Das können bspw. Dinge wie Logging, Transaktionsbehandlung oder Sicherheit sein. Wir unterscheiden inhaltlich drei Arten von Interzeptoren: Geschäftsmethoden, Lebenszyklus und Interzeptoren, die auf Timeout-Ebene wirken. Diese gibt es allerdings nur in der EJB. Wenn wir einen Interzeptor definieren wollen, dann definieren wir meistens zunächst einen Stellvertreter für den Interzeptor. Das ist ein sog. Interceptor-Binding. Dieses Interceptor-Binding fungiert wie ein Platzhalter. Und dieser Platzhalter wird an zwei Stellen verwendet, nämlich auf Ebene des Interzeptors und dort, wo der Interzeptor selbst angewendet werden soll. Der Interzeptor, also die eigentliche Implementierung, wird in einer eigenen Klasse definiert. Am Kopf dieser Klasse steht die Interceptor-Annotation und die Annotation, die als Platzhalter für den Interceptor dient. Damit sind diese beiden Dinge dann zusammengeführt worden. Die eigentliche Ausführungsart wird mithilfe einer eigenen Annotation angegeben. Dieser werden wir uns gleich widmen. Grundsätzlich ist es so, dass mehrere Interzeptoren das gleiche Interceptor-Binding benutzen können. Das bedeutet, ich kann für ein Binding, also ein Platzhalter, mehrere mögliche Implementierungen durchaus auch gleichzeitig verwenden, wobei gleichzeitig relativ ist, denn die Ausführungsreihenfolge ist normalerweise undefiniert. Ich kann sie mithilfe der Priority-Annotation auf Ebene der Interzeptor-Implementierung steuern. Damit Interzeptoren überhaupt genutzt werden können, müssen sie aktiviert werden. Und diese Aktivierung geschieht entweder in der Datei "Beans.xml" oder aber der Interzeptor muss die Priority-Annotation besitzen. Trifft beides nicht zu, wird der Interzeptor komplett ignoriert. Wichtig ist noch ein kleiner, feiner Unterschied: Interzeptoren, die in der Datei "Beans.xml" deklariert sind, gelten nur für Klassen, die im selben Archiv liegen. Das gilt nicht für Interzeptoren, die mit der Priority-Annotation versehen sind. Diese sind tatsächlich global aktiv. Die Priority-Annotation selbst definiert einige vordefinierte Werte. Die sollte man kennen, damit man selber dafür sorgen kann, dass ein Interzeptor korrekt eingesetzt wird. "Interceptor.Priority.PLATFORM_BEFORE" hat den Wert 0; das würde bedeuten, bevor die komplette Java-EE-Applikation zuschlägt oder ganz am Anfang. "LIBRARY_BEFORE" hat den Wert 1000, "APPLICATION" hat den Wert 2000, "LIBRARY_AFTER" hat den Wert 3000, und "PLATFORM_AFTER" hat den Wert 4000. Generell gilt, dass niedrigere Werte für eine zeitigere Ausführung sorgen. Für uns ist ganz wichtig, dass so eine Interceptor-Priority in aller Regel zwischen "Interceptor.Priority.APPLICATION" und "Interceptor.Priority.LIBRARY_AFTER" liegen sollte. So ein Interzeptor kann auf verschiedene Arten und Weisen ausgeführt werden. Wir geben dies mithilfe von Annotationen an. Die "AroundInvoke"-Annotation sagt, dass der Interzeptor ausgeführt wird, bevor und nachdem eine Methode der Zielinstanz angesprungen wird. "AroundConstruct" lässt den Interzeptor vor und nach dem Konstruktor der Zielinstanz wirken. "PostConstruct" lässt ihn nur nach dem Durchlaufen des Konstruktors wirken. "PreDestroy" lässt den Interzeptor wirken, bevor die Zielinstanz zerstört wird. "PrePassivate" funktioniert letztlich nur im EJB-Umfeld und sorgt dafür, dass der Interzeptor aufgerufen wird, bevor eine Session-Bean passiviert wird. Und "PostActivate" sorgt dafür, dass der Interzeptor aufgerufen wird, nachdem eine Session-Bean aktiviert worden ist. Die Verwendung eines Interzeptors werden wir uns gleich in der Praxis anschauen. Wir werden nämlich ein Interceptor-Binding und einen Interzeptor definieren. Wir sehen hier eine Webapplikation. In dieser Webapplikation gibt es einige Geschäftsmethoden, die wir gerne mit einem eigenen Interzeptor begleiten wollen. Wir werden zu diesem Zweck einen Logging-Interceptor implementieren. Dieser Logging-Interceptor benötigt, damit er ausgeführt werden kann, zunächst einmal das sog. Interceptor-Binding. Dieses erzeugen wir, indem wir eine neue Annotation anlegen. Wir nennen sie "Logging". Das ist der Platzhalter für den eigentlichen Interzeptor. Diese Logging-Annotation wird nun versehen mit der Inherited-Annotation, mit der Interceptor-Binding-Annotation und mit Annotationen, die das Laufzeit-Verhalten steuern, nämlich die Retention-Annotation, mit der wir angeben, wie ist dieser Interzeptor dann später bzw. dieses Binding sichtbar, nämlich zur Laufzeit. Und worauf soll dieses Binding denn angewendet werden? Das geben wir mithilfe der Target-Annotation an. Hier geben wir ein Array aus Element-Type-Elementen herein. Und zwar kann so ein Interceptor-Binding auf Ebene von Klassen und auf Ebene von Methoden verwendet werden. Damit ist jetzt letztlich das Binding fertiggestellt und wir können uns dem Interzeptor selbst widmen. Zu diesem Zweck legen wir eine neue Klasse an. Wir nennen sie "LoggingInterceptor". Diese Klasse wird annotiert mit der Interzeptor-Annotation. Ebenfalls wird sie annotiert mit der Logging-Annotation, die wir gerade eben definiert haben. Damit ist dieser Interzeptor an dieses Interceptor-Binding gebunden. Darüber hinaus erhält dieser Interzeptor eine Priority-Annotation, wodurch wir festlegen, mit welcher Priorität er ausgeführt werden soll und wodurch wir ihn überhaupt erst aktivieren. Wir geben diesem eine Priorität auf Ebene der Applikation, bisschen nach dem Starten der Applikation. Und zuletzt gibt es noch die Dependant-Annotation. Diese ist nicht zwingend notwendig, wenn allerdings Ihre "Beans.xml" so eingestellt ist, dass der Bean-Discovery-Mode auf "Annotated" steht, würde der Interzeptor nicht gefunden werden, wenn wir keine CDI-Annotation hier hinterlegen würden. Nun können wir die eigentliche Implementierung der Methoden oder der Logik des Interzeptors angehen. Wir definieren eine Methode, die den Rückgabe-Typ "Object" hat. Wir nennen sie "log". Diese Methode benötigt einen Parameter vom Typ "InvocationContext". Und es kann dabei beim Aufruf dieser Methode zu einem Fehler kommen. Deswegen notieren wir das. Nachdem wir die Methode so grundsätzlich deklariert haben, geben wir an, dass sie vor und nach dem Aufruf einer anderen Methode aufgerufen werden soll, und zwar mithilfe der "AroundInvoke"-Annotation. Nun können wir uns der eigentlichen Implementierung der Methode widmen. Wir machen jetzt hier eine ganz einfache Implementierung eines Loggers. Und zwar geben wir letztendlich nur den Namen der Methode aus, die wir aufrufen bzw. die aufgerufen worden ist. Diesen Namen können wir über diesen Kontext-Parameter erreichen. Hier gibt es eine Methode "getMethod" und dort gibt es eine Methode "getName". Das geben wir jetzt aus. Und nun rufen wir die eigentliche Methode, um die sich dieser Interzeptor letztlich herumgelegt hat, auf. Das machen wir, indem wir auf Ebene dieser Kontext-Variablen die Methode "Proceed" aufrufen. Damit würde jetzt die eigentlich aufgerufene Funktionalität tatsächlich erst eingebunden werden. Wir können nun loggen, dass die Methode erfolgreich durchgeführt worden ist, indem wir den Namen einfach wieder ausgeben. Und zu guter Letzt geben wir die Rückgabe, die eventuelle Rückgabe der ursprünglich aufgerufenen Methode zurück. Damit ist dieser Interzeptor fertig gebaut und er kann jetzt verwendet werden. Wir werden dies auf einigen Klassen machen, z. B. machen wir das hier auf diesem Kontakte-Manager. Ich möchte gerne, dass beim Aufruf der Methode Kontakte-Namen unser Logging-Interceptor eingebunden wird. Zu diesem Zweck annotiere ich diese Methode mit dem entsprechenden Interceptor-Binding. Das gleiche mache ich bei der Klasse "Test-Kontakte-Provider". Hier möchte ich, dass dies für alle Methoden dieser Klasse gilt. Deswegen annotiere ich die komplette Klasse damit. Nun kann ich meine so geschriebene Applikation auf dem Server deployen. Und wenn ich den Server dann gestartet habe und eine Funktionalität darauf aufrufe, dann werde ich in der Lage sein, in der Ausgabe zu erkennen, dass meine entsprechende Funktionalität eingebunden worden ist. Man sieht hier, die Methode "getKontakteNamen" wurde aufgerufen und sie wurde erfolgreich aufgerufen. Sie sehen, es ist gar nicht so schwierig, einen eigenen Interzeptor zu bauen.

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!