Blog

EJB 3.1 mit dem Boss – Teil 1: Singleton Session Beans

Der am häufigsten eingesetzte Java EE Application Server – der JBoss Application Server – hat es zum Jahreswechsel zur finalen Version 6.0 geschafft. Diese Version verspricht, die neuen Features der JSR-318-Spezifikation vollständig umzusetzen und somit einen EJB-3.1-fähigen Application Server bereit zu stellen. Allerdings ist JBoss AS 6 bis dato nur für das Java EE 6 Web Profile zertizifiert. Es ist deshalb an der Zeit, sich einmal anzusehen, was die neue Version der Spezifikation mit sich bringt und wie JBoss AS 6 mit den neuen Features von EJB 3.1 umgeht.

Im ersten Teil dieser Serie wollen wir einen genaueren Blick auf die neuen Singleton Session Beans werfen.

Einzelstück

Eines der geläufigsten Entwurfmuster ist das Singleton-Pattern. Die grundlegende Definition eines Singletons – eines Einzelstücks – ist, dass eine als Singleton implementierte Klasse nur genau einmal in einem bestimmten Kontext instanziiert wird. So läßt beispielsweise die typische Singleton-Implementierung in der Java-SE-Welt exakt eine Instanz der Singleton-Klasse pro Classloader zu. Auf diese Weise können Situationen abgebildet werden, bei denen innerhalb eines Systems eine Begebenheit nur durch eine Objektinstanz repräsentiert werden soll oder darf, wie etwa bei einer Robotersteuerung, bei denen es nur ein reales Gegenstück für Klassen gibt, oder für einen applikationsweiten Cache.

Rückblick

Dieses Paradigma in der Java-EE-Welt einzusetzen war vor EJB 3.1 nur über properietäre Lösungen von Container-Herstellern, Drittanbietern oder – unter bestimmten Umständen – über Java-SE-Singletons möglich. Es gab keine einheitliche, standardisierte Konfiguration für verschiedene Container existierte vor EJB 3.1 nicht, auch wenn in der Regel die Anzahl gleichzeitig erlaubter Instanzen einer Session Bean im Deployment Descriptor auf eins gesetzt werden konnte, um eine Singleton-Semantik für eine Session Bean zu schaffen.

Die anderen Varianten haben gemein, dass man sich bei ihnen nicht auf die durch Java EE geschaffenen Vorteile von Wiederverwendbarkeit, Skalierbarkeit und Sicherheit verlassen kann. Es müssen transparente, Container-inhärente Umsetzungen von Mechanismen wie Zugriffssteuerung und Transaktionalität selbst implementiert werden oder für Lösungen von Drittanbietern konfiguriert und in die eigene Applikation integriert werden. Man muss sich fragen: erhält eine properitäre Lösung Security- oder andere Anwendungs-Konfigurationen, und was passiert bei einem Wechsel zu einem anderen Container-Provider? Wie konfiguriere ich die Classloader-Isolation und wie verhält sich die Container-spezifische Classloader-Hierarchie im Kontext meiner Java-SE-Singletons?

Einen gangbaren Weg für Java-SE-Singletons, wenn der Aufruf innerhalb desselben Classloaders garantiert ist, hatte jüngst mein Kollege Jo Ehm in seinem Blogbeitrag „Synchronisation und Nebenläufigkeitskontrolle mit EJBs leicht gemacht“ vorgestellt.

EJB 3.1 Singleton Session Beans

Aber genug der Schwarzmalerei: die EJB 3.1 Singleton Session Beans sind da, funktionieren nun spezifikationsgemäß mit JBoss und bringen eine Lösung für (fast) alle beschriebenen Probleme.

Den schönsten Vorteil für die praktische Anwendung merkt man als Entwickler sofort: sie sind verdammt einfach zu konfigurieren. Es bedarf lediglich der Annotation @Singleton an der Session Bean-Klasse, und schon stellt der Container eine Singleton Session Bean bereit.

...
@Singleton
public class Einzelstück {
    ...
}

Nebenläufigkeit

Standardmäßig unterbindet der Container den nebenläufigen Zugriff auf die Geschäftsmethoden der Bean.

Konfigurieren läßt sich das Locking-Verhalten über die Annotation @Lock und einen LockType, wobei standardmäßig LockType.WRITE für alle Geschäftsmethoden einer Singleton Session Bean aktiv ist. Damit werden alle gleichzeitig eintreffenden Aufrufe einer Methode zurückgestellt und der Reihe nach abgearbeitet. Dieses Verhalten empfiehlt sich für alle den Applikationszustand verändernden Methoden, um Anomalien (verursacht durch Dirty Reads etc.) vorzubeugen.

Damit kein Client zu lange warten muss, kann optional über die Annotation @AccessTimeout ein Zeitspanne angegeben werden, wie lange ein Aufruf vom Container zurückgestellt werden darf, bevor eine ConcurrentAccessTimeoutException geworfen wird. JBoss erwartet einen Wert in Millisekunden, aber es können auch andere Zeiteinheiten konfiguriert werden.
Über LockType.READ kann der Container auf Methoden- oder Klassenebene angewiesen werden, nebenläufige Aufrufe zuzulassen.

Im folgenden Beispiel sind alle Geschäftsmethoden für nebenläufige Zugriffe konfiguriert, mit Ausnahme der datenverändernden Methode nurEinerAufEinmal(Daten daten).

...
@Singleton
@Lock(READ)
public class Einzelstück {

    @Lock(WRITE)
    public void nurEinerAufEinmal(Daten daten) {
        schreibeDaten(daten);
    }

    public Daten lesen() {
        return daten;
    }
...
}

Alternativ hat man die Möglichkeit, über die Annotation @ConcurrencyManagement unter Angabe des ConcurrencyManagementType.BEAN die Nebenläufigkeit für seine Singleton Session Bean selbst zu definieren und zu implementieren. Dabei darf man sich auch der Annotationen @Synchronized und @Volatile bedienen.

Hinten anstellen!

Des Weiteren ist es möglich, Abhängigkeiten zwischen Singleton Session Beans zu annotieren, so dass benötigte Singletons vom Container vor den abhängigen Singletons erzeugt werden.
Im Gegensatz zum JBoss 6 CR1-Release unterstützt die finale Version nun auch korrekt die Angabe von Abhängigkeiten und ruft wie in der Spezifikation vorgegeben die @PostConstruct-Callbacks von als benötigt annotierten Singleton Session Beans vor den Callback-Methoden der jeweilig abhängigen Singleton Session Beans auf.

Im Beispiel wird die Singleton Session Bean NotwendigeBean spätestens dann vom Container erzeugt und deren PostConstruct-Callback init() aufgerufen, wenn die Bean AbhängigeBean erzeugt werden muss.

@Singleton
@DependsOn("NotwendigeBean")
public class AbhängigeBean {
   @PostConstruct
   public void init() {
        ...
    }
    ...
}

@Singleton
public class NotwendigeBean {
    @PostConstruct
    private void init() {
        vorbereitendeMaßnahmen();
    }
    ...
}

Sofort loslegen

Der Container kann über die Annotation @Startup angewiesen werden, eine Singleton Session Bean sofort beim Starten der Applikation zu instanziieren. Dies kann man sich zunutze machen, um etwa gleich zu Beginn einen Cache zu füllen und damit bereits die Geschäftsmethoden vom ersten Aufruf an performant nutzen zu können.

Ebenso kann man eine Singleton Session Bean verwenden, um in der Applikation beim Herunterfahren aufzuräumen. Dazu kann das @PreDestroy-Callback verwendet werden. Um sicherzustellen, dass die entsprechende Singleton Session Bean überhaupt instanziiert wurde, verwendet man hierfür ebenso eine Bean, die mit @Startup annotiert wird.

Keine Cluster aus der Box

Leider gilt auch für die neuen EJB 3.1 Singleton Session Beans, dass die Singleton-Eigenschaft nur pro JVM erhalten wird. Für Applikationen, die im Cluster laufen, werden also nach wie vor selbstgestrickte Lösungen benötigt, die alle Nodes synchronisieren, oder Container-spezifische Lösungen, wie die HA-Services von JBoss.

Holisticon AG — Teile diesen Artikel

Über den Autor

Antwort hinterlassen