Sie können eine Bean-Implementierungsklasse für eine
Stateful-Session-Bean erstellen. Dies wurde in der Spezifikation
Enterprise JavaBeans™ (EJB) 1.0
eingeführt und in der Spezifikation EJB 3.0 erheblich vereinfacht.
Eine Stateful-Bean ist ein Typ von Session-Bean, die von einem einzigen
Client in seiner Laufzeit verwendet wird und den Dialogstatus mit dem Client, der die Bean aufruft, verwaltet.
Vorbereitende Schritte
Stellen Sie sicher, dass Sie die Vererbungsregeln für jede implementierte Annotation verstehen.
Die Annotation "@TransactionManagement" wird nur in der Stateful-Session-Bean-Klasse
codiert. Sie können die Annotation "@TransactionManagement" weder in der Klasse, die erweitert wird, noch in Klassen, die in der Klassenvererbungsbaumstruktur über dieser Klasse stehen.
Informationen zu diesem Vorgang
Stateful-Session-Beans können die folgenden Ansichten haben:
lokale Ansicht ohne Schnittstelle (neu in EJB 3.1), lokale Geschäftsansicht, ferne Geschäftsansicht,
lokale Ansicht der EJB Version 2.1 und ferne Clientansicht der EJB Version 2.1.
Ein Beispiel hierfür ist ein elektronischer Warenkorb, dem der Client im Verlauf seiner
Einkaufssitzung online Artikel hinzufügt.
Das folgende Beispiel zeigt eine grundlegende Stateful-Session-Bean:
package com.ibm.example;
public interface ShoppingCart {
void addToCart (Object o);
Collection getContents();
}
package com.ibm.example;
@Stateful
public class ShoppingCartBean implements ShoppingCart {
private ArrayList contents = new ArrayList();
public void addToCart (Object o) {
contents.add(o);
}
public Collection getContents() {
return contents;
}
}
Wie bei anderen Enterprise-Bean-Typen können Sie
Metadaten für Stateful-Session-Beans im Implementierungsdeskriptor deklarieren, anstatt Annotationen zu verwenden; z. B.:
<?xml version="1.0"?>
<ejb-jar
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd"
version="3.1">
<enterprise-beans>
<ejb-name>ShoppingCartBean</ejb-name>
<business-local>com.ibm.example.ShoppingCart</business-local>
<ejb-class>com.ibm.example.ShoppingCartBean</ejb-class>
<session-type>Stateful</session-type>
</enterprise-beans>
</ejb-jar>
- Codieren Sie die Initialisierungs- und Vernichtungsmethoden. Beachten Sie dabei, dass diese Methoden
in einem nicht spezifizierten Sicherheitskontext und in einem nicht spezifizierten Transaktionskontext ausgeführt
werden.
Während der Initialisierung geschieht Folgendes: Die Instanz wird erstellt, die Abhängigkeitsinjektion wird durchgeführt, und die Interceptor-Callbacks für den
PostConstruct-Lebenszyklus werden aufgerufen. Die Interceptor-Callbacks für den PreDestroy-Lebenszyklus
werden für eine Stateful-Session-Bean beim Aufruf einer Methode "remove" aufgerufen.
Beachten Sie auch, dass die Interceptor-Callbacks für den PreDestroy-Lebenszyklus
nicht aufgerufen werden, wenn die Stateful-Session-Bean das zulässige Zeitlimit überschreitet, während sie
inaktiviert ist oder wenn eine unerwartete Ausnahme während eines Methodenaufrufs in der Bean eintritt
und die Bean verworfen wird.
- Verwenden Sie die Methoden "PrePassivate" und "PostActivate", wenn die Stateful-Session-Bean
Statusdaten enthalten kann, die nicht serialisierbar sind. Der Container
kann eine Instanz einer Stateful-Session-Bean, die nicht in einer Transaktion registriert ist
oder die momentan eine Methodenanforderung ausführt, jederzeit inaktivieren.
Die Instanz der Stateful-Session-Bean wird in den Status "Inaktiv" versetzt, indem alle Statusdaten
serialisiert werden.
Werden Statusdaten nicht serialisiert, wird die Instanz der
Stateful-Session-Bean vom Container verworfen.
- Sie können die optionale Schnittstelle "javax.ejb.SessionSynchronization"
implementieren, wenn die Statusdaten der Stateful-Session-Bean
nach einem Transaktionsrollback zurückgesetzt werden müssen.
Die Statusdaten einer Stateful-Session-Bean sind nicht transaktionsorientiert und werden aufgrund
eines Transaktionsrollbacks nicht automatisch zurückgesetzt.
Durch die Implementierung der Methode "afterCompletion" der Schnittstelle "javax.ejb.SessionSynchronization"
kann sich die Instanz der Stateful-Session-Bean selbst in den Anfangszustand bzw. in einen konsistenten Zustand
zurückversetzen.
- Verwenden Sie die Notation "@AccessTimeout", um gleichzeitige
Clientanforderungen zu verhindern oder um die Zeit zu beschränken, die eine Methode
auf die Erteilung einer Sperre für die Instanz wartet.
Standardmäßig lässt der Container gleichzeitige Clientanforderungen zu, serialisiert
aber alle Methodenaufrufe und vom Container aufgerufenen Callbacks, um Multithreadzugriffe
auf die Instanz der Stateful-Session-Bean zu verhindern.
Dieses Verhalten gleicht der Verwendung containergesteuerter gemeinsamer Zugriffe mit Schreibsperren
für Singleton-Session-Beans.
Anders als Singleton-Session-Beans können Stateful-Session-Beans jedoch nicht
für die Verwendung beangesteuerter gemeinsamer Zugriffe konfiguriert werden, und der Sperrtyp kann nicht geändert werden.
Für Stateful-Session-Beans kann nur der Wert von access-timeout geändert werden. Das folgende Codebeispiel veranschaulicht eine Stateful-Session-Bean mit
einem Zeitlimitwert für gleichzeitige Zugriffe (access-timeout), der gleichzeitige
Clientanforderungen verhindert:
package com.ibm.example;
@Stateful
public class ShoppingCartBean implements ShoppingCart {
private ArrayList contents = new ArrayList();
@AccessTimeout( value=0 )
public void addToCart (Object o) {
contents.add(o);
}
public Collection getContents() {
return contents;
}
}
package com.ibm.example;
@Stateful
public class ShoppingCartBean implements ShoppingCart {
private ArrayList contents = new ArrayList();
@AccessTimeout( value=0 )
public void addToCart (Object o) {
contents.add(o);
}
public Collection getContents() {
return contents;
}
}
Wenn keine Annotation angegeben ist, wartet die Methode standardmäßig so lange, bis eine Sperre erteilt wird.
Es gibt kein Zeitlimit für das Warten auf eine Sperrre.
Da keine Festlegung auf Klassenebene codiert ist,
gibt es für alle Methoden der Klasse kein Wartezeitlimit für die Erteilung einer Sperre.
Wenn die Annotation "@AccessTimeout" verwendet wird und der Container die Sperre nicht innerhalb des angegebenen
Zeitlimits erteilen kann, wird ein Ausnahme des Typs "javax.ejb.ConcurrentAccessTimeoutException" an den Client ausgegeben.
Die Annotation "@AccessTimeout" gilt nur für Methoden, die in derselben Klasse deklariert sind wie die Annotation
"@AccessTimeout".
Die Metadaten für die Annotation "@AccessTimeout" in einer bestimmten Klasse werden nie von einer Klasse
übernommen, die in der Klassenvererbungsbaumstruktur über dieser Klasse stehen.
Der Wert "-1" für "access-timeout" gibt an, dass
gleichzeitige Methodenaufrufe den Zugriff auf die Beaninstanz
unbegrenzt blockieren (Standardeinstellung).
Der Wert "0" für "access-timeout" gibt an, dass gleichzeitige
Methodenaufrufe nicht zulässig sind.
Die Ausnahme "javax.ejb.ConcurrentAccessException" tritt ein, wenn gleichzeitige Zugriffe
erkannt werden.
Jeder positive Wert gibt die Wartezeit an, bevor die Methode fortgesetzt werden kann.
Vor Java™ EE
6 wurde nur der access-timeout-Wert "-1" für gleichzeitige Zugriffe für Stateful-Session-Beans
unterstützt (keine gleichzeitigen Zugriffe zulässig).
Da die Spezifikation Java EE 6 das Standardverhalten
geändert hat, wird eine Systemeigenschaft bereitgestellt, die das ältere Standardverhalten
unterstützt.
Weitere Informationen zur Systemeigenschaft "com.ibm.websphere.ejbcontainer.EE5Compatibility"
finden Sie in den Beschreibungen der Systemeigenschaften des EJB-Containers.
Sie können auch die Annotation
"@AccessTimeout" mithilfe des XML-Implementierungsdeskriptors
angeben. Wenn Sie den XML-Implementierungsdeskriptor verwenden, werden die Metadaten aus der Annotation
"@AccessTimeout" ignoriert. Im folgenden Beispiel wird der XML-Implementierungsdeskriptor verwendet, um dieselben Metadaten wie im vorherigen Beispiel anzugeben.
<session>
<ejb-name>ShoppingCartBean</ejb-name>
<concurrent-method>
<method>
<method-name>addToCart</method-name>
</method>
<access-timeout>
<timeout>0</timeout>
<unit>Milliseconds</unit>
</access-timeout>
</concurrent-method>
</session>
- Sie müssen wissen, dass die XML-Codierung von concurrent-methodType
den drei Stilen entspricht, die in der EJB-Spezifikation für die Erstellung der XML-Elemente für
Containertransaktionsmethoden beschrieben sind.
Die drei Stile sind im Folgenden beschrieben. Stil 1 verwendet den Sondermethodennamen *, um den access-timeout-Wert
auf alle Geschäftsmethoden der angegebenen Bean anzuwenden.
<!-- Beispiel: Stil 1 -->
<concurrent-method>
<method>
<method-name>*</method-name>
</method>
<access-timeout>
<timeout>2000</timeout>
<unit>Milliseconds</unit>
</access-timeout>
</concurrent-method>
Stil 2 wird verwendet, um auf eine Geschäftsmethode mit einem bestimmten Namen zu
verweisen und dieser
den angegebenen access-timeout-Wert zuzuordnen.
Wenn der Methodenname überladen ist, was bedeutet, das mehrere Methoden denselben Namen, aber unterschiedliche
Methodensignaturen haben, haben alle Methoden mit diesem Namen den angegebenen access-timeout-Wert.
<!-- Beispiel: Stil 2 -->
<concurrent-method>
<method>
<method-name>businessMethod</method-name>
</method>
<access-timeout>
<timeout>2000</timeout>
<unit>Milliseconds</unit>
</access-timeout>
</concurrent-method>
Stil 3 wird verwendet, um auf eine bestimmte Methode zu verweisen, die dem angegebenen Methodennamen entspricht
und eine Methodensignatur besitzt, die den aufgelisteten Methodenparametern entspricht.
Stil 3 hat Vorrang vor den Stilen 1 und 2.
<!-- Beispiel: Stil 3 -->
<concurrent-method>
<method>
<method-name>businessMethod</method-name>
<method-params>
<method-param>long</method-param>
<method-param>int</method-param>
</method-params>
</method>
<access-timeout>
<timeout>2000</timeout>
<unit>Milliseconds</unit>
</access-timeout>
</concurrent-method>
Wenn XML-Stil 1 verwendet wird, um einen access-timeout-Wert zu definieren,
werden alle @AccessTimeout-Annotationen in der Bean ignoriert, weil stattdessen der Wert auf Methodenebene
verwendet wird.
- Stellen Sie sicher, dass Sie die Vererbungsregeln für die verwendeten Annotationen verstehen.
- Stateful-Session-Beans sind nicht wiedereintrittsfähig, was bedeutet, dass die Methode der Stateful-Session-Bean
sich selbst zurückruft.
Wenn ein wiedereintrittsfähiger aufruf an eine Stateful-Session-Bean abgesetzt
wird, tritt unabhängig vom access-timeout-Wert eine Ausnahme "javax.ejb.ConcurrentAccessTimeoutException"
im Client ein.
Diese Ausnahme führt weder dazu, dass die Stateful-Session-Bean
verworfen wird, noch dass die Transaktion für Rollback markiert wird, sofern
die Ausnahme nicht vom Caller behandelt wird.