"
 
 1 Einführung in CDI
"
 
 2 CDI Grundkonzepte
"
 
 3 CDI und Java EE
"
 
 4 Portable CDI-Erweiterungen
"
 
 5 Apache DeltaSpike
"
 
 6 CDI Lite
"
 
 7 CDI oder nicht CDI
"
 
 8 CDI in der Cloud

1 Einführung in CDI

IoC: Unter dem Namen "Contexts and Dependency Injection for the Java EE platform", kurz CDI, wurde am 10. Dezember 2009 eine neue Spezifikation in der finalen Version veröffentlicht, welche schon bald darauf das Java EE Ökosystem nachhaltig verändern sollte. Inspiriert von erfolgreichen Open-Source Frameworks (wie bspw. Spring, Seam, Guice) und der damit verbundenen langjährigen Erfahrung wurde ein neues typsicheres Komponentenmodell spezifiziert, welches die tägliche Arbeit erheblich erleichtert. Doch auch komplexere Anforderungen kommen dank der Flexibilität von CDI nicht zu kurz. Diese Flexibilität ermöglichte portable CDI Erweiterungen, welche entscheidend zum Erfolg von CDI beigetragen haben.

1.0.0.1 Ziel dieses Buchs

In diesem Buch lernen Sie Schritt für Schritt die Grundkonzepte von CDI und wie Sie sowohl Java SE als auch Java EE Projekte erfolgreich mit diesem neuen Komponentenmodell umsetzen können. Wie bei jeder Technologie gibt es auch bei CDI den einen oder anderen Fallstrick. Durch Tipps und Tricks lernen Sie diese zu erkennen und erfahren Details zu den Lösungsmöglichkeiten. Neben der Integration mit anderen Technologien widmen wir uns auch erfolgreichen CDI-Erweiterungen und zeigen Ihnen auf wie Sie von diesen profitieren können.

1.1 Context- und Dependency-Management

Context-Management: Um zu verstehen warum mit der Arbeit an CDI begonnen wurde, machen wir einen kurzen Ausflug in die Anfänge der Softwareentwicklung mit Java.

 

Ohne ein zusätzliches Framework steht Ihnen der rudimentäre Sprachumfang von Java zur Verfügung. Geht es um die Erzeugung neuer Instanzen einer Klasse, so können Sie das Schlüsselwort new verwenden. Allerdings müssen Sie eine solche Instanz auch verwalten, um sie zu einem späteren Zeitpunkt wieder verwenden zu können (= Context-Management). Ähnlich wie in anderen Programmiersprachen haben sich auch in Java hierfür verschiedene Entwurfsmuster etabliert. Doch selbst diese Entwurfsmuster führten in großen Applikationen oft zu unnötig komplexen oder ausschweifenden Umsetzungen. Um Instanzen effizienter zu verwalten und mit zusätzlicher Funktionalität anzureichern wurden bald Komponentenmodelle eingeführt, mit welchen die Komplexität in Konfigurationsdateien ausgelagert wurde. Mangels einer sinnvolleren Alternative wurde hierfür oftmals XML als Konfigurationsformat herangezogen. Dies führte jedoch zu neuen Herausforderungen. Ein zentraler Teil einer Applikation ist nicht mehr typsicher und die Konfiguration mancher Komponentenmodelle wurde so umfangreich, dass diese oft mit Generatoren erzeugt werden musste. Im Laufe der Zeit wurden die Komponentenmodelle besser und der Konfigurationsaufwand erheblich gesenkt. Jedoch basiert das Format der Konfigurationsdateien weiterhin auf Strings, wodurch viele Vorteile einer typsicheren Sprache wie Java verloren gehen.

 

Dependency-Management: Eine zweite Herausforderung bei der Entwicklung von Applikationen sind die Referenzen zu anderen Instanzen (= Dependency-Management). Hierbei erhöht sich die Komplexität, sobald Beans mit unterschiedlicher Lebensdauer (Scopes) beteiligt sind. Sorgt der Container dafür, dass die erforderlichen Referenzen zu anderen Instanzen automatisch gesetzt (= injiziert) werden, so spricht man von Dependency-Injection. Für dieses Dependency-Management nutzen viele Komponentenmodelle Konfigurationseinträge, welche ebenfalls zum Verlust der Typsicherheit führen.

 

Ein Container stellt ein Komponentenmodell zur Verfügung, welches vom Applikationscode verwendet werden kann, um Teile der Applikation einfacher umzusetzen. Dadurch stellen sie das Bindeglied zwischen der darunter liegenden Laufzeitumgebung und dem Applikationscode dar.

 

Sowohl beim Context- als auch beim Dependency-Management gab es bis zu JDK 5 keine Alternative, um diese Grundproblematik effizienter und vor allem typsicher zu lösen. 2004 wurden die anfänglich stark unterschätzten Annotationen mit Java 5 eingeführt. Doch erst 2006 wurden mit Java EE 5 Annotationen erstmals (offiziell) für Dependency-Injection verwendet. Im darauffolgenden Jahr wurde dieser Ansatz von einem Projekt namens Guice bezüglich der Typsicherheit verfeinert. Durch die zunehmende Beliebtheit von typsicheren Komponentenmodellen war eine Spezifikation solcher Konzepte naheliegend. Ursprünglich wurde CDI (JSR-299) unter dem Namen "Web Beans" geführt. Es war nämlich das primäre Ziel ein Bindeglied zwischen der JSF- und EJB-Spezifikation zu schaffen. Drei Jahre später feierte CDI sein Debüt. Bis zur finalen Version der Spezifikation hatte sich nicht nur der Name der Spezifikation geändert, sondern es wurden mehrere größere Überarbeitungen vorgenommen. So wurde bspw. ein Teil der Spezifikation ausgelagert (zu JSR-330) und stellt nicht nur die Basis für CDI dar, sondern auch für andere Komponentenmodelle. Außerdem ist CDI in der heutigen Form nicht mehr an Java EE gebunden, sondern kann ebenfalls problemlos in Java SE Applikationen verwendet werden.
Tipp: JSR-330 besteht aus 5 Annotationen und einem Interface und spezifiziert einen minimalen Funktionsumfang, welcher für Dependency-Injection und die Definition eigener Scopes erforderlich ist. Neben Implementierungen der CDI-Spezifikation wir die Spezifikation auch von anderen Projekten als Basis verwendet.

1.2 Annotationen als zentraler Bestandteil

Annotationen sind zusätzliche Metadaten und wurden in Java 5 als Erweiterung des Typsystems eingeführt. Da CDI hauptsächlich auf Annotationen basiert und die Erstellung eigener Annotationen zum täglichen Handwerkszeug für die Arbeit mit CDI gehören, sehen wir uns ein paar Details etwas näher an. Bei Annotationen muss grundsätzlich unterschieden werden, ob sie zur Laufzeit der Applikation abgefragt werden können oder nicht. Ein bekannter Vertreter für Annotationen, welche nicht zur Laufzeit abgefragt werden können ist @Override , da hier @Retention(RetentionPolicy.SOURCE) definiert ist. Für ein Komponentenmodell wie CDI sind natürlich nur Informationen sinnvoll, welche zur Laufzeit zur Verfügung stehen. Daher müssen alle Annotationen, welche Sie in Zusammenhang mit CDI erstellen, immer @Retention(RetentionPolicy.RUNTIME) definieren. Anderenfalls sieht der CDI-Container die Annotation zur Laufzeit nicht.

 

Darüber hinaus muss noch angegeben werden an welchen Stellen die Annotation verwendet werden kann. Dies wird mit Hilfe von @Target ausgedrückt. Somit können wir bereits die gebräuchlichste Annotation namens @Inject für die tägliche Arbeit mit CDI, welche in Listing Spezifizierter Aufbau von @Inject dargestellt ist, analysieren.
@Target({ElementType.CONSTRUCTOR,
    ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Inject {}
Im Falle von @Inject sind die möglichen Verwendungsziele Konstruktoren, Methoden und Felder. Abgesehen von den eben erwähnten Elementtypen sind im Kontext von CDI noch ElementType.TYPE für Annotationen auf Klassenebene, ElementType.PARAMETER für Annotationen auf Methodenparametern und ElementType.ANNOTATION_TYPE für Annotationen auf Annotationen wichtig. Eine Annotation zu annotieren mag sich anfänglich etwas ungewohnt anhören. Im Laufe des Buches werden wir jedoch sehr sinnvolle Verwendungsmöglichkeiten für diesen Elementtyp kennenlernen.

1.3 Hello CDI

CDI folgt in der minimalen Ausprägung einigen wenigen Regeln. In den nachfolgenden Kapiteln werden wir zusätzlich spezielle Konstellationen betrachten. Behalten Sie bitte im Hinterkopf, dass viele der vorgestellten Konzepte optional sind und somit zwar zur Verfügung stehen, aber selbstverständlich nicht laufend verwendet werden müssen. Eine durchschnittliche CDI basierte Applikation kommt sogar mit erstaunlich wenigen CDI-Funktionalitäten aus. Dennoch ist es sinnvoll einen Überblick über den gesamten Funktionsumfang zu haben, falls Sie auf komplexere Anwendungsfälle stoßen und auch diese mit den eleganten CDI-Konzepten lösen möchten.

 

Listing Minimales CDI-Bean zeigt ein POJO (Plain Old Java Object), welches bereits ein vollwertiges CDI-Bean darstellt. Wie unschwer zu erkennen ist, wird hier weder eine CDI-Klasse noch eine spezielle Annotation verwendet.
public class HelloWorldBean {
  public String hello() {
    return "Hello CDI";
  }
}
Nur anhand der Klasse kann in diesem Fall nicht festgestellt werden, ob es sich um ein CDI-Bean handelt oder nicht. Damit der CDI-Container von dieser Klasse überhaupt erfährt muss eine Marker-Datei namens beans.xml je Modul (in META-INF bei JAR-Dateien bzw. WEB-INF bei WAR-Dateien) angelegt werden. Wie bereits der Begriff Marker-Datei vermuten lässt kann diese Datei leer (= 0 Byte) sein, da diese im einfachsten Fall lediglich zur Kennzeichnung sog. Bean-Archive (bzw. Bean Deployment Archive) verwendet wird. Somit muss nicht der gesamte Klassenpfad gescannt werden, sondern nur die entsprechend markierten Archive.

 

Selbst wenn der CDI-Container die Klasse aus Listing Minimales CDI-Bean gefunden hat, muss dieses Bean vom Container implizit via Dependency-Injection oder explizit via manuellem Bean-Lookup vom Container bezogen werden. Würden Sie manuell eine Instanz dieser Klasse erzeugen, dann wird diese nicht vom Container verwaltet und die Instanz ist auch kein CDI-Bean.
Tipp: Ab CDI 1.1 ist die Datei beans.xml optional. Um mit CDI 1.0 Bean-Module ohne beans.xml zu integrieren kann bspw. auf die SPI von CDI zurückgegriffen werden. Die entsprechenden Mechanismen werden im Kapitel Portable CDI-Erweiterungen vorgestellt.
Die erste Instanz, welche den Einstiegspunkt einer Verarbeitung darstellt, muss immer vom CDI-Container initialisiert werden. In einem Java EE Applikationsserver wird dies im Regelfall autom. durchgeführt. Java-SE Applikationen müssen hingegen mindestens ein Bean manuell vom CDI-Container abfragen oder manuelle Injizierung durchführen, damit der Objektgraph vom CDI-Container korrekt aufgebaut wird. Vor CDI 1.1 ist dies in einer Java SE Applikation nicht mit Hilfe einer standardisierten API möglich. Um dennoch unser Bean bspw. mit einem einfachen Unit-Test zu überprüfen, müssen wir an dieser Stelle etwas vorgreifen und verwenden einen JUnit Test-Runner einer portablen CDI-Erweiterung namens Apache DeltaSpike. Sowohl der Test-Runner als auch viele weitere Bestandteile von DeltaSpike werden später im Kapitel Portable CDI-Erweiterungen im Detail beschrieben. Dieser Test-Runner sorgt im Hintergrund vor allem dafür, dass der CDI-Container gestartet wird und CDI-Beans in die JUnit-Testklasse injiziert werden können.
@RunWith(CdiTestRunner.class)
public class HelloWorldBeanTest {
  @Inject
  private HelloWorldBean bean;

  @Test
  public void testInjectedBean() {
    Assert.assertEquals("Hello CDI", bean.hello());
  }
}
Erst durch @Inject wird veranlasst, dass der CDI-Container eine Instanz der Klasse HelloWorldBean erzeugt und eine Referenz auf diese zur Verfügung stellt. Somit kann über das mit @Inject annotierte Feld auf diese Instanz zugegriffen werden.

 

Listing Minimales CDI-Bean und Injection eines CDI-Beans zeigen wie einfach CDI sein kann. Natürlich gibt es viele weitere Mechanismen, welche in den nachfolgenden Kapiteln im Detail beschrieben werden. Dennoch sei an dieser Stelle nochmals erwähnt, dass eine durchschnittliche CDI-Applikation nicht den vollen Funktionsumfang von CDI ausschöpfen muss. In vielen Fällen lautet die Devise: "Je geringer die Komplexität gehalten wird, desto einfacher kann eine Applikation gewartet werden." Dies trifft nicht nur auf Geschäftslogik einer Applikation zu, sondern auch bei der Auswahl der zur Verfügung stehenden Funktionsumfänge von Komponentenmodellen wie CDI.

1.4 Die Applikation zu diesem Buch

Der Name der Beispielapplikation ist IdeaFork . Im Laufe des Buches wird eine kleine Plattform entwickelt, mit welcher bspw. Rezept-, Reise-, ..., Geschenk-Ideen einfach verwaltet werden können. Darüber hinaus können Ideen gesucht und kopiert (geforked) werden. Dies ermöglicht die Abwandlung und Weiterentwicklung bestehender Ideen.

 

Bitte beachten Sie, dass die Beispielapplikation kein Referenzdesign einer typischen CDI-Applikation darstellen soll. Stattdessen werden alle Grundkonzepte von CDI, sowie Funktionalitäten von CDI-Erweiterungen anhand konkreter Anwendungsfälle einer Applikation illustriert. Selbstverständlich können einige der Anwendungsfälle auch ohne die Hilfe von CDI umgesetzt werden. Auch mit CDI bedeutet die Verfügbarkeit einer Funktionalität nicht, dass diese um jeden Preis verwendet werden muss.

 

Im ersten Teil des Buches konzentrieren wir uns auf das Backend der Applikation. Anfänglich wird der Backend-Code keine Abhängigkeiten zu anderen Java EE Spezifikationen, wie bspw. JPA, haben. Dadurch können wir uns voll und ganz auf die CDI-Konzepte konzentrieren. Erst danach werden wir uns mit der Integration von anderen Java EE Spezifikationen sowie anderen Technologien beschäftigen. Die Struktur des Backend-Moduls ist einfach gehalten, da die illustrierten CDI-Funktionalitäten im Mittelpunkt stehen und nicht die Erstellung eines bestimmten Applikationsdesigns. Für eine einfachere Verwendung des Moduls gibt es nur eine Trennung zwischen API- und Impl-Package.

 

Da CDI selbst nur eine schriftliche Spezifikation ist, benötigen wir eine Implementierung dieser. Hier haben wir eine beachtliche Auswahl. Neben der Referenzimplementierung namens Weld (von JBoss) gibt es noch OpenWebBeans (von Apache) und CanDI (von Resin). Weit verbreitet sind Weld und OpenWebBeans (aka OWB). Daher werden wir uns auf diese beiden Implementierungen beschränken. In Java SE Anwendungen sowie bei Webapplikationen, welche in einen Servlet-Container deployed werden, können Sie selbst entscheiden für welche der Implementierungen Sie sich entscheiden. Bei Java EE6+ Applikationsservern wird Ihnen diese Entscheidung vorerst einmal vom Hersteller des Servers abgenommen und somit müssen Sie sich hier nicht manuell um das Setup kümmern.

1.4.0.1 Das Setup

In Kombination mit einem Java EE6+ Applikationsserver ist das Setup minimal, da nur das Java EE API-JAR während der Entwicklung erforderlich ist. Für das Deployment ist es dann nicht mehr erforderlich und somit müssen nur die Klassen des Projekts selbst zur Verfügung gestellt werden. Da wir jedoch mit Java SE (bzw. JUnit Tests) und CDI anfangen, werden wir uns das erforderliche Setup für OpenWebBeans und Weld etwas genauer ansehen.

 

Sowohl Weld als auch OpenWebBeans sind mit jeder standardkonformen API verwendbar. Hier gibt es mehrere Möglichkeiten.
[groupId:artifactId]VersionBeschreibung
javax:javaee-web-api 6.0 Offizielle Java EE 6 API
javax:javaee-web-api 7.0 Offizielle Java EE 7 API
org.apache.openejb:javaee-api 6.0-5 Alternatives Java EE 6 API

Tabelle tab:ee-api zeigt unterschiedliche EE API-Bundles, welche aktuell zur Verfügung stehen. Da jedes Bundle die komplette API enthält ist nur eines dieser Bundles erforderlich. Sind Sie jedoch nur an der CDI-API selbst interessiert, so können Sie alternativ javax.inject:javax.inject:1 und javax.enterprise:cdi-api:1.0-SP4 einbinden. Als weitere Alternative können die einzelnen API-Module von Apache verwendet werden, welche in Tabelle tab:spec-apis aufgelistet sind. Bei Apache werden diese API Module gesammelt im Projekt Apache Geronimo gehostet, jedoch gibt es keine Abhängigkeit zu der gleichnamigen Serverimplementierung.
[groupId:artifactId]VersionBeschreibung
org.apache.geronimo.specs: geronimo-atinject_1.0_spec 1.0 JSR-330
org.apache.geronimo.specs: geronimo-jcdi_1.0_spec 1.0 JSR-299
org.apache.geronimo.specs: geronimo-interceptor_1.1_spec 1.0 Bestandteil von JSR-318

Zusätzlich zu den API Modulen sind die entsprechenden Implementierungsmodule erforderlich:
[groupId:artifactId]VersionBeschreibung
org.apache.openwebbeans: openwebbeans-impl 1.2.2 Implementierung von JSR-299
org.apache.openwebbeans: openwebbeans-spi 1.2.2 Separates SPI Modul für eine einfachere Erweiterbarkeit von OWB

[groupId:artifactId]VersionBeschreibung
org.jboss.weld: weld-core-bom 1.1.18 BOM für Weld
org.jboss.weld: weld-api Durch BOM definiert Proprietäre API von Weld
org.jboss.weld: weld-core Durch BOM definiert Implementierung von JSR-299
org.jboss.weld.se: weld-se Durch BOM definiert Spezielles Module für Java SE
org.slf4j: slf4j-simple 1.7.2 Logging Framework, welches von Weld verwendet wird

Im pom.xml von IdeaFork werden sowohl die Dependencies von OpenWebBeans (Tabelle tab:owb_java-se ) als auch Weld (Tabelle tab:weld_java-se ) verwendet. Zur Laufzeit darf immer nur eine Implementierung aktiv sein. Diese erforderliche Trennung wird in IdeaFork mit Maven-Profilen umgesetzt. Somit kann die Portabilität der Applikation sichergestellt werden.

 

Damit CDI einfach in JUnit Tests gestartet und verwendet werden kann, finden Sie in der Demo-Applikation zusätzlich Test-Dependencies für das Test-Control Modul von Apache DeltaSpike, welches im Kapitel Portable CDI-Erweiterungen detailliert beschrieben wird.

1.5 Wichtige Begriffe der Spezifikation

Bevor wir mit den einzelnen Grundkonzepten loslegen, betrachten wir noch die wichtigsten Begriffe der CDI-Spezifikation. Auf diese Begriffe werden Sie nicht nur in den nachfolgenden Kapiteln vermehrt stoßen, sondern auch im JavaDoc von CDI und möglicherweise bei der einen oder anderen eigenen Recherche über ein CDI spezifisches Thema.

1.5.0.1 Injection-Point

Injection-Points sind Referenzvariablen, welche vom CDI-Container autom. gesetzt werden. Im Laufe des Buchs werden wir verschiedene Möglichkeiten für explizite und implizite Injection-Points kennenlernen. Eine mit @Inject annotierte Instanzvariable ist bspw. ein expliziter Injection-Point.

 

Das SPI von CDI enthält ebenfalls ein Interface mit diesem Namen. Über dieses Interface können die Metadaten von einem Injection-Point während dem Containerstart angepasst werden.

1.5.0.2 Scope und Kontext

Der Scope definiert die Lebensdauer einer Instanz. Mit @NormalScope definiert CDI selbst nur eine Scope-Art. Da CDI auf JSR-330 basiert und hier durch @Scope ein einfacherer Scope-Typ spezifiziert wird, muss man effektiv zwischen den Normal-Scopes von CDI (JSR-299) und den sog. Pseudo-Scopes von JSR-330 unterscheiden.

 

Für CDI basierte Applikationen sind primär Normal-Scoped Beans relevant. Hier definiert CDI @ApplicationScoped (Instanzen werden beim Shutdown der Applikation zerstört), @SessionScoped (die Lebensdauer ist von der HTTP-Session abhängig), @RequestScoped (die Lebensdauer ist auf einen HTTP-Request beschränkt) und @ConversationScoped (halb automatisch gesteuert). Der einzige durch CDI spezifizierte Pseudo-Scope ist @Dependent , welcher aus CDI-Sicht in vielen Fällen eine Ausnahme darstellt.

 

Ein Scope ist mit einer Instanz einer Implementierung von javax.enterprise.context.spi.Context verbunden, welche den Lebenszyklus von Instanzen (Contextual-Instances) verwaltet. Ob ein Kontext aktiv ist oder nicht, hängt von der Art des Scopes ab und kann dynamisch ausgewertet werden.

 

Von CDI spezifizierte Standard-Kontexte werden komplett beenden. Wird bspw. der Request-Scope für den aktuellen Thread zerstört, so werden alle request-scoped Beans gesammelt vernichtet. Die manuelle Verwaltung einzelner Beans ist bei den Standard-Kontexten nicht vorgesehen. Hierbei handelt es sich jedoch nicht um eine technische Einschränkung von CDI. Daher ist eine feingranulare Verwaltung einzelner Beans bei eigenen Kontext-Implementierungen durchaus möglich.
Tipp: In der Praxis können @SessionScoped und @RequestScoped sogar in Java SE Applikationen verwendet werden. Jedoch müssen sie manuell gesteuert werden. Weitere Details hierzu und zu den einzelnen Scopes, sowie die Definition eigener Scopes folgen in den Kapiteln CDI und Java EE und Portable CDI-Erweiterungen .

1.5.0.3 Managed-Bean

Managed-Beans sind nach der Definition von CDI nicht mit Java-Beans zu verwechseln. Jedoch sind selbst in der CDI-Spezifikation mehrere Verwendungen des Begriffs für unterschiedliche Konzepte zu finden. Zumindest in diesem Buch verwenden wir aus Sicht von CDI folgende Hauptdefinition:

 

Ein Managed-Bean wird durch javax.enterprise.inject.spi.Bean<T> repräsentiert und setzt sich aus der Java-Klasse und den zusätzlichen Metadaten zusammen. Wie wir später noch sehen werden, können diese Metadaten während dem Containerstart beinahe beliebig angepasst werden. In jedem Fall werden sie im Zuge des Startprozesses der Applikation überprüft. Werden CDI-Regeln nicht eingehalten, so wird der Containerstart abgebrochen und eine entsprechende Fehlerbeschreibung angezeigt.

 

Auf Basis der Java-Klasse und der Metadaten kann der Container zur Laufzeit die sog. Contextual-Instance erzeugen.

1.5.0.4 Contextual-Instance

Umgangssprachlich wird statt Contextual-Instance oft der Begriff (CDI )Bean verwendet. Da der Begriff "Bean" jedoch mehrdeutig ist, werden wir in den nachfolgenden Kapiteln (größtenteils) den Begriff Contextual-Instance verwenden. Wie zuvor erwähnt, handelt es sich bei der Contextual-Instance um die effektive Instanz, welche vom CDI-Container auf Basis des Managed-Beans (= Java-Klasse und zusätzliche Metadaten) erzeugt wird. Jedoch gibt der Container in vielen Fällen nicht die physische Referenz auf die Instanz nach außen, sondern eine sog. Contextual-Reference.

1.5.0.5 Contextual-Reference

Statt der physischen Referenz auf eine (Contextual-)Instance gibt der CDI-Container in vielen Fällen eine Proxy-Instanz nach außen. Ob ein Proxy verwendet wird oder nicht, hängt vom definierten Scope des Managed-Beans ab. Für Normal-Scoped Beans werden immer Proxys erzeugt und für Pseudo-Scoped Beans ist es nur vorgeschrieben wenn Interceptoren oder Decoratoren um eine Contextual-Instance gelegt werden müssen, da solche Funktionalitäten ohne angepassten Bytecode nicht umsetzbar sind.

 

Durch die Verwendung von Proxys wird außerdem die sog. Cross-Scope-Injection Thematik gelöst. Ohne Proxys würde bspw. ein Session-Scoped Bean mit einer (injizierten) Referenz auf ein Request-Scoped Bean nach dem 1. Request eine Referenz auf die alte Instanz (aus dem 1. Request) haben. Stattdessen soll das Session-Scoped Bean immer das aktuelle Request-Scoped Bean ansprechen können. Hierfür sorgt die Contextual-Reference (der Proxy), da für jeden Methodenaufruf die richtige Instanz gesucht wird und erst auf diese der Methodenaufruf ausgeführt wird.

 

Da Proxys lt. CDI-Spezifikation unabhängig von der Contextual-Instance immer serialisierbar sind, ist die Passivierung (= Serialisierung und Speicherung einer Contextual-Instance außerhalb der Laufzeitumgebung) einer Contextual-Instance unabhängig von den injizierten Referenzen.
Tipp: Der Proxy-Overhead ist bei aktuellen Implementierungen bereits minimal. Bspw. erzeugt OpenWebBeans 1.2+ hoch optimierte Proxys via Subclassing auf Bytecode-Ebene. Unabhängig von der konkreten Umsetzung gibt es jedoch Einschränkungen welche zu beachten sind. Durch Proxys dürfen Klassen und deren Methoden nicht final sein. Außerdem ist bei der täglichen Verwendung von CDI zu beachten, dass im Debugger ("leere") Proxy-Instanzen angezeigt werden. Um den State der Contextual-Instance im Debugger zu sehen muss man sich innerhalb dieser Instanz befinden.