iX 3/2019
S. 148
Praxis
Java-Programmierung
Aufmacherbild

Event-Verarbeitung mit CDI 2.0

Auswahl erweitert

Context and Dependency Injection ist das Programmiermodell vieler Jakarta-EE- und MicroProfile-Anwendungen. Die Spezifikation bietet nicht nur die Möglichkeit, Objekte abhängig vom Kontext zu injizieren, sondern auch eine flexible Event-Behandlung.

Synchrones Verarbeiten von Events erfreute sich schon in den ersten Versionen der CDI-Spezifikation (Context and Dependency Injection) großer Beliebtheit. Mit nur wenig Code ließen sich Events auslösen und von einer beliebigen Anzahl an Observern innerhalb derselben Anwendung behandeln. Das Erzeugen und Verarbeiten von Events ist dabei vollkommen entkoppelt, sodass es in voneinander unabhängigen Modulen erfolgen kann.

CDI 2.0 erlaubt nun zusätzlich das asynchrone Verarbeiten und das Sortieren synchroner Observer. Das schafft flexiblere Möglichkeiten, diese Programmierkonzepte in großen Anwendungen umzusetzen. Die nachfolgenden Abschnitte stellen die neuen Features vor. Es geht dabei sowohl um grundlegende Themen wie das Definieren und das Auslösen beider Varianten von Events sowie um das Beschreiben derselben durch Qualifier als auch um ihren Einsatz bei der Auswahl der zuständigen Observer.

Ein CDI-Event besteht aus zwei Teilen: einem beliebigen Java-Objekt (Event-Objekt) und einer optionalen Liste von Qualifiern, die es beschreiben. Qualifier stellen zusätzliche Informationen zu einem Event bereit, die die Auswahl der zu benachrichtigenden Observer beeinflussen können. Dazu später mehr.

Listing 1: Event-spezifische Klasse zum Erzeugen von Event-Objekten

public class OrderEvent {

      private String customer;

      private Double amount;

  public OrderEvent() {

  }

  public OrderEvent(String customer, ⤦
 Double amount) {
    this.customer = customer;
    this.amount = amount;
  }

  public String getCustomer() {
    return customer;
  }

  public void setCustomer(String customer) {
    this.customer = customer;
  }

  public Double getAmount() {
    return amount;
  }

  public void setAmount(Double amount) {
    this.amount = amount;
  }

}

Zunächst gilt die Aufmerksamkeit dem Event-Objekt, das an alle Observer übergeben wird, die für die Klasse des Objekts registriert sind. Es muss keine durch die Spezifikation vorgegebene Superklasse erweitern und kein Interface implementieren. In der Praxis verwendet der Entwickler daher häufig eine Mischung aus Objekten existierender Klassen der Anwendungsdomäne und aus speziell für das Event entworfenen Klassen. Listing 1 zeigt eine solche Event-spezifische Klasse. Objekte der Klasse OrderEvent enthalten lediglich die für das Verarbeiten notwendigen aggregierten Informationen eines Auftrags.

Mit dem ausgewählten Objekt kann man synchrone oder asynchrone Events erzeugen. Die Varianten sind in der CDI-Spezifikation strikt voneinander getrennt, was Kompatibilitätsprobleme zwischen CDI 1 und 2 verhindern soll.

Alles läuft unabhängig voneinander

Das Implementieren beider Event-Ausprägungen basiert auf demselben Grundkonzept. Ein Producer löst ein Event für ein Objekt aus und eine beliebige Anzahl Observer reagiert darauf. Producer und Observer arbeiten unabhängig voneinander, sie müssen lediglich das Objekt kennen, aber nicht einander. So entsteht eine vollständige Entkopplung zwischen Producern und Observern, was vor allem in stark modularisierten Anwendungen Vorteile hat.