Alles Ansichtssache: Spaß mit @Scopes

Im obigen Beispiel produzieren wir das User-Objekt aus einer Methode heraus, ohne dabei explizit einen Scope anzugeben. Das User-Objekt nimmt so automatisch den Default Scope Dependent an. Dependent ist – genau wie Singleton – ein so genannter CDI Pseudo Scope. Im Gegensatz zu den Normal Scopes – RequestScoped, ConversationScoped, SessionScoped und ApplicationScoped – arbeiten Pseudo Scopes nicht mit einem Proxy. Stattdessen wird die gewünschte Instanz – in unserem Fall das User-Objekt – direkt in den Injection Point injiziert. Dies passiert beim Erzeugen des Objekts, in dem der User injiziert werden soll (aka Injection Target). Ist das Injection Target ApplicationScoped, wird also derjenige User injiziert, der „zufällig“ der erste war, der das ApplicationScoped-Objekt nutzt. Das wiederum hängt damit zusammen, dass eine CDI Managed Bean – in unserem Fall also das ApplicationScoped-Objekt mit dem Injection Point für das User-Objekt – gemäß Spezifikation erst bei der ersten Nutzung erzeugt wird.

Alle anderen User, die später auf dieses Objekt und den darin referenzierten User zugreifen, sehen entsprechend als angemeldeten User nicht sich selbst sondern stattdessen den ersten Aufrufer. Ist das Injection Target dagegen SessionScoped, wird beim ersten Zugriff innerhalb des Scopes – also der Session – jeweils der aktuelle Session-User injiziert und somit das gewünschte Verhalten erreicht. Bei ConversationScoped und RequestScoped ist das Verhalten ähnlich. Da die Producer-Methode allerdings einmal pro Scope aufgerufen wird – in diesem Fall also einmal pro Conversation bzw. einmal pro Request – ist zusätzlich noch entscheidend, welchen Scope die Bean hat, in der sich die Producer-Methode befindet. Ist sie SessionScoped – durchaus sinnvoll -, dann gibt es keinerlei Probleme. Wäre die Bean mit der Producer-Methode dagegen – warum auch immer – ApplicationScoped, hätten wir wieder das Problem, dass der produzierte User für alle Injection Points ein und derselbe wäre.

Wichtig zu verstehen ist in unserem bisherigen Beispiel, dass wir es mit einem Pseudo Scope zu tun haben. Dies bedeutet, dass die zugehörige Producer-Methode jedes Mal aufgerufen wird, wenn der Container auf einen entsprechenden Injection Point stößt. Ebenfalls wichtig ist, dass im Falle des Pseudo Scopes das injizierte Objekt serialisierbar sein muss, wenn es das Injection Target auch ist.

Wie aber sähe die Alternative aus? Listing 2 zeigt die gleiche Producer-Methode wie in Listing 1. Allerdings wird dieses Mal das User-Objekt via @SessionScoped produziert. Nebenbei wurde auch der Scope der umliegenden Bean auf SessionScoped gesetzt.

Listing 2: CDI-Producer-Methode mit Scope
@SessionScoped
public class AuthenticationController {

  ... 

  @Named("authenticatedUser")
  @Produces @SessionScoped
  @Authenticated  
  public User getAuthenticatedUser() {     return this.user;    }
}

Auch wenn sich der Code beider Listings kaum unterscheidet, greift in Listing 2 ein völlig anderer Mechanismus. Das Objekt der Klasse, in der sich der Injection Point @Inject @Authenticated User befindet, bekommt bei seiner Erzeugung – entsprechend der Spezifikation der CDI Normal Scopes – zunächst nur einen Proxy injiziert. Die Verlinkung mit dem tatsächlichen User-Objekt dagegen erfolgt erst beim Zugriff auf das User-Objekt selbst (Abb. 1).

Abb. 1: CDI Nomal Scope

Dank Proxy kann in unserem Beispiel die Abfrage nach dem aktuell angemeldeten User problemlos auch in einem ApplicationScoped-Objekt genutzt werden. Ein weiterer Vorteil liegt darin, dass die zugehörige Producer-Methode nur ein einziges Mal pro Session aufgerufen wird. Anschließend befindet sich das User-Objekt unter der Verwaltung des CDI BeanManagers im Session Scope.

Kommentare

Schreibe einen Kommentar

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