EnterpriseTales

Alles Ansichtssache: Spaß mit @Scopes

Lars Röwekamp und Matthias Weßendorf

Eines der wesentlichen Features von CDI liegt in der Möglichkeit, eigene Custom Scopes zu implementieren, die dann automatisch die Lifecycle-Verwaltung der ihr zugeordneten CDI Managed Beans übernehmen. Was sich zunächst toll anhört, birgt aber auch einige Stolperfallen. Um diese zu umgehen, sollte man sich die Konzepte des Scope-Modells von CDI einmal genauer ansehen.

Werfen wir dazu einen Blick zurück: Wie schön einfach war doch die Welt noch zu Zeiten von Java EE 5! Eine klassische Mehrschichtanwendung wird aus JSF, EJB und JPA zusammengebaut. Jede Schicht für sich definiert dabei klare Lebensräume für ihre jeweiligen Komponenten. Die verschiedenen JSF Scopes zum Beispiel bilden eine klare Hierarchie, wobei sich innerhalb eines Scopes nur Instanzen des gleichen oder eines übergeordneten Scopes injizieren lassen. Und auch die Welt der EJBs definiert mit Stateful und Stateless eine überschaubare Komplexität.

Mit Java EE 6 haben wir CDI als alternatives, schichtenübergreifendes Komponentenmodell dazugewonnen. Und damit auch so schöne Dinge wie Normal Scopes, Pseudo Scopes und, nicht zu vergessen, die bereits erwähnten Custom Scopes. Die gute Nachricht: CDI Scopes erlauben eine deutlich größere Flexibilität als wir sie bisher von den JSF-, EJB- und JPA-Welten her kennen. Die schlechte Nachricht: Diese Flexibilität hat ihren Preis.

Um die Komplexität der CDI Scopes besser zu verstehen, ziehen wir ein kleines Beispiel heran und beleuchten dieses aus verschiedenen Blickwinkeln. Stellen Sie sich vor, Ihre Anwendung besitzt einen AuthenticationController, mit dessen Hilfe sich ein Benutzer am System anmelden kann. Soll später in der Anwendung der aktuell angemeldete Nutzer abgefragt werden, kann dies mithilfe der Methode getAuthenticatedUser erfolgen. Der zugehörige, CDI-basierte Quellcode könnte stark vereinfacht aussehen wie in Listing 1.

Listing 1: CDI-Producer-Methode
// some cdi scope
public class AuthenticationController {

  private User user;

  public User authenticate(AuthenticationData data) {
    this.user = ... // do some authentication
    return this.user;    }
  
  @Named("authenticatedUser")
  @Produces
@Authenticated  // self made annotation
  public User getAuthenticatedUser() {     return this.user;    }
}

Findet sich nun irgendwo innerhalb der Anwendung folgendes Code-Fragment:

@Inject @Authenticated User authenticatedUser;

wird „automatisch“ im Hintergrund die Producer-Methode getAuthenticatedUser des AuthenticationController aufgerufen und das Ergebnis in den Injection Point injiziert. Soweit so gut. Wann aber genau passiert das? Was spielt sich in diesem Moment im Hintergrund ab? Und wie wirkt sich das letztendlich auf die Anwendung aus?

Geschrieben von
Lars Röwekamp und Matthias Weßendorf
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.