CDI 2.0 ist da: Dependency Injection jetzt auch für Java SE

Die Arbeiten an Java EE 8 schreiten voran. Mit der Version 2.0 der Context and Dependency Injection (CDI) Spezifikation ist nun eine der Kernkomponenten für das Release fertiggestellt. Was ist neu?
CDI 2.0: Neue Struktur
Was zunächst auffällt, ist die neue Struktur der Spezifikation. In der Version 2.0 wurde CDI in drei Teile aufgesplittet: In „Core CDI“ werden die übergreifenden Konzepte beschrieben. Auf dieser Grundlage fügt der neue Part „CDI in Java SE“ spezifische Features für die CDI-Nutzung in der Java Standard Edition hinzu. Die Spezifikationen in Teil 3 basieren ebenfalls auf Core CDI, sind aber auf den Einsatz in einem Java EE Container zugeschnitten.
Diese Aufteilung spiegelt eine der wichtigsten Neuerungen in CDI 2.0 wider: Die bislang nur in der Praxis realisierte, jedoch nicht spezifizierte Nutzung von CDI in Java-SE-Projekten wurde durch ein neues API offiziell in den Standard aufgenommen.
CDI 2.0 in Java SE – so geht`s
Im Java SE-Kontext muss der CDI Container explizit gestartet werden. Dies wird in CDI 2.0 durch die abstrakte Klasse SeContainerInitializer
und die statische Methode newInstance()
durchgeführt.
Dabei ist SeContainerInitializer
ein ServiceProvider
der Services javax.enterprise.inject.se.SeContainerInitializer
, der in META-INF/services deklariert wird. Diese Klasse erlaubt die Konfigurierung des CDI Containers vor dem eigentlichen Bootstrapping. Die Methode SeContainerInitializer.initialize()
löst dann das Bootstrapping aus und gibt eine Instanz von SeContainer
zurück.
Lesen Sie auch: CDI – Java SE, die Welt der Threads
Aus synchron wird asynchron
Eine weitere Neuerung in CDI 2.0 ist die Unterstützung für asynchrone Events. Dafür steht die Methode fireAsync()
zur Verfügung. Das Beispiel aus der offiziellen Spezifikation sieht so aus:
@Inject Event<LoggedInEvent> loggedInEvent; public void login() { ... loggedInEvent.fireAsync( new LoggedInEvent(user) ); }
Alle aufgelösten asynchronen Observer werden in einem oder mehreren separaten Threads aufgerufen. Darüber hinaus stellt das Interface Event
eine Methode bereit, um Events mit einer spezifischen Kombination aus Typen und Qualifiern zu feuern:
public interface Event<T> { public void fire(T event); public <U extends T> CompletionStage<U> fireAsync(U event); public <U extends T> CompletionStage<U> fireAsync(U event, NotificationOptions options); public Event<T> select(Annotation... qualifiers); public <U extends T> Event<U> select(Class<U> subtype, Annotation... qualifiers); public <U extends T> Event<U> select(TypeLiteral<U> subtype, Annotation... qualifiers); }
Mehr zum Thema: EnterpriseTales: Asynchrone Events in CDI 2.0
Observer-Prioritäten
Interessant ist die neue Option, eine Reihenfolge für den Aufruf verschiedener Observer-Methoden für spezifische Events festzulegen. Dafür wurde die Annotation @Priority
eingeführt, mit der ein Event-Parameter ausgezeichnet werden kann:
void afterLogin(@Observes @Priority(javax.interceptor.Interceptor.Priority.APPLICATION) LoggedInEvent event) { ... }
Allerdings ist die Bearbeitung mehrerer Observer derselben Priorität undefiniert, sodass die Observer-Methoden in einer nicht vorhersehbaren Reihenfolge notifiziert werden.
Eingebaute Annotation-Literale
Neu sind zudem einige vordefinierte Annotationen, über die sich statische Literal-Klassen definieren lassen. Die folgenden Annotationen stehen zur Verfügung:
javax.enterprise.inject.Any
javax.enterprise.inject.Default
javax.enterprise.inject.New
javax.enterprise.inject.Specializes
javax.enterprise.inject.Vetoed
javax.enterprise.util.Nonbinding
javax.enterprise.context.Initialized
javax.enterprise.context.Destroyed
javax.enterprise.context.RequestScoped
javax.enterprise.context.SessionScoped
javax.enterprise.context.ApplicationScoped
javax.enterprise.context.Dependent
javax.enterprise.context.ConversationScoped
javax.enterprise.inject.Alternative
javax.enterprise.inject.Typed
Somit kann die Literal-Klasse
genutzt werden, um das korrespondierende AnnotationLiteral
zu instantiieren:
Default defaultLiteral = new Default.Literal();
Zusätzlich stellt CDI Annotations-Literale für die folgenden JSR 330 Annotationen (Dependency Injection for Java) bereit:
javax.inject.Inject
mit der Klassejavax.enterprise.inject.literal.InjectLiteral
javax.inject.Named
mit der Klassejavax.enterprise.inject.literal.NamedLiteral
javax.inject.Qualifier
mit der Klassejavax.enterprise.inject.literal.QualifierLiteral
javax.inject.Singleton
mit der Klassejavax.enterprise.inject.literal.SingletonLiteral
Lambdas, Streams & More
Was hat CDI 2.0 sonst noch im Gepäck?
Zu erwähnen sind die Konfiguration für SPI-Elemente sowie die Unterstützung von Java 8 Features wie Streams und Lambda Expressions. Außerdem ist es möglich, im Event ProcessObserverMethod
Observer-Methoden zu konfigurieren. Im Interface InterceptionFactory
kann ein Interceptor auf einen Producer angewandt werden:
@Produces @RequestScoped public Product createInterceptedProduct(InterceptionFactory<Product> interceptionFactory) { interceptionFactory.configure().add(ActionBinding.Literal.INSTANCE); return interceptionFactory.createInterceptedInstance(new Product()); }
CDI 2.0 ausprobieren
Wer CDI 2.0 mit dieser Feature-Vielfalt nutzen möchte, muss nicht auf das Release von Java EE 8 warten. Schon jetzt stehen die Neuerungen in der Referenzimplementieruing Weld 3.0 zur Verfügung.
CDI Spec Lead Antoine Sabot-Durand von Red Hat beschreibt auf www.cdi-spec.org die Vorgehensweise. Durch folgenden Code wird der pom.xml-Datei die cdi-api 2.0-Komponente hinzugefügt:
<dependency> <groupId>javax.enterprise</groupId> <artifactId>cdi-api</artifactId> <version>2.0-PFD</version> </dependency>
Weitere Einrichtungsschritte, beispielsweise für Red Hats WildFly-Server, beschreibt Sabot-Durand in seinem Blogpost.
Die gesamte Spezifikation für CDI 2.0 finden Interessierte unter http://docs.jboss.org/cdi/spec/2.0/cdi-spec.html.
Hinterlasse einen Kommentar