Im ersten Teil der Serie über die neuen Features von EJB 3.1 und Besonderheiten in der Umsetzung innerhalb des JBoss AS 6 haben wir die neuen Singleton Session Beans der JSR-318-Spezifikation betrachtet.
Im zweiten Teil werfen wir nun einen Blick auf die mit EJB 3.1 eingeführten asynchronen Methodenaufrufe an Session Beans.
Messaging versus asynchrone Methodenaufrufe
Asynchrone Kommunikation ist im Kontext von Enterprise-Applikationen eine fundamentale Anforderung. Einerseits möchte man durch parallele, den Aufrufer nicht blockierende Anfragen eine Verbesserung der Performanz erreichen, andererseits bietet das Konzept der asynchronen, nachrichtenbasierten Kommunikation die Möglichkeit, Systeme zu integrieren, wenn lediglich eine lose Kopplung der Beteiligten benötigt wird. Zudem bietet die nachrichtenbasierte Kommunikation die Möglichkeit, eine Nachricht mehreren Empfängern zukommen zu lassen.
Unter EJB ermöglichen Message Driven Beans die nachrichtenbasierte Kommunikation. Genau genommen weicht das Einsatzszenario von Messaging über Message Driven Beans mit ihrem nachrichtenbasierten Ansatz von dem Konzept klassischer asynchroner Aufrufe ab. Während das typische Einsatzszenario von Messaging ist, die Kommunikation zwischen Softwaresystemen weitgehend technologieunabhängig und über eine lose Kopplung von Sender und Empfänger zu vollziehen, dienen asynchrone Aufrufe in erster Linie der Erhöhung des Durchsatzes, da Aufgaben parallel und im Hintergrund erledigt werden können und damit die Systemressourcen potenziell besser ausgenutzt werden können.
Wollte man vor EJB 3.1 asynchrone Verarbeitung in einer JEE-Umgebung realisieren, war man gezwungen, Messaging über JMS einzusetzen. Es ist zwar nicht unbedingt aufwändig oder kompliziert, Message Driven Beans zu implementieren, dennoch ist es notwendig, für die Nachrichtenverarbeitung im Applikationsserver JMS zu konfigurieren.
Asynchrone Methodenaufrufe mit EJB 3.1
Mit der Version 3.1 der EJB-Spezifikation sind nun asynchrone Methodenaufrufe direkt an Session Beans möglich. Dazu muss lediglich die entsprechende Methode mit der Annotation @javax.ejb.Asynchronous
versehen werden. Alternativ können auch alle Geschäftsmethoden einer Session Bean asynchron deklariert werden, indem die Annotation auf Klassenebene gesetzt wird.
Im folgenden Beispiel wird die Methode fireAndForget()
als asynchron aufrufbar deklariert. Ruft ein Client der Session Bean MeineBean
die Methode auf, erhält dieser unmittelbar nach dem Aufruf wieder den Fokus und kann mit seiner Verarbeitung fortfahren.
…
@Stateless
public class MeineBean {
@Asynchronous
public void fireAndForget() {
…
}
…
}
Zurück in der Zukunft
Doch mit EJB 3.1 kann man nicht nur die typischen fire-and-forget-Methoden realisieren, sondern interessanterweise auch Rückgabeparameter an asynchronen Methoden deklarieren. Hierbei kann der Client das Ergebnis des Methodenaufrufs zu einem späteren Zeitpunkt anfordern. Dazu liefert der EJB-Container ein Stellvertreterobjekt an den Aufrufer zurück, über das sich das Resultat und weitere Informationen zum Methodenaufruf ermitteln lassen. Tatsächlich birgt also der Aufruf einer asynchronen Methode mit Rückgabewert eine synchrone Kommunikation des Clients mit dem EJB-Container in sich.
Das Stellvertreterobjekt ist vom Typ Future<V>
– das Resultat vom Typ V
. Als Convenience-Implementierung des Future-Interface steht die Klasse javax.ejb.AsyncResult
zur Verfügung.
Über die Methode get()
am Stellvertreterobjekt kann der Client das Resultat anfordern.
In folgendem Beispiel wird in der Methode komplizierteSumme()
der Session Bean ClientBean
die asynchrone Methode fireAndRetrieve()
aufgerufen. Unmittelbar nach Erhalt des Futures kompliziertInDerZukunft
wird die Abarbeitung fortgesetzt. Erst am Ende der Methode wird über das Stellvertreterobjekt das Resultat von fireAndRetrieve()
angefordert.
…
@Stateless
public class KomplizierteBerechnungBean
implements KomplizierteBerechnung {
@Asynchronous
public Future<Long> fireAndRetrieve() {
Long result;
…
return new AsyncResult<Long>(result);
}
…
}
@Stateless
public class ClientBean {
@EJB
private KomplizierteBerechnung meineBean;
…
public Long komplizierteSumme() {
Future<Long> kompliziertInDerZukunft =
meineBean.fireAndRetrieve();
Long result;
…
return result + kompliziertInDerZukunft.get();
}
…
}
Synchrones Retrieve
Dabei wird deutlich, dass das Anfordern des Resultats einen synchronen Aufruf darstellt: steht das Ergebnis der asynchronen Methode zu diesem Zeitpunkt noch nicht zur Verfügung, ist der Client blockiert. Alternativ kann über die Methode isDone()
geprüft werden, ob das Resultat bereits zur Verfügung steht.
Des Weiteren kann die Berechnung über einen Aufruf von cancel()
am Stellvertreterobjekt abgebrochen werden, um Ressourcen wieder freizugeben.
Fazit
Mit dem Konzept der asynchronen Methodenaufrufe an Session Beans unter EJB 3.1 steht dem nachrichtenbasierten Ansatz der Message Driven Beans eine wichtige und sinnvolle Erweiterung zur Seite. Vor allem die Möglichkeit, über asynchrone Methoden mit Rückgabewert eine Berechnung anstoßen zu können, um das Ergebnis zu einem späteren Zeitpunkt abzuholen, stellt einen nützlichen Mehrwert in der Entwicklung performanter Enterprise-Applikationen dar. Der JBoss AS 6 setzt dieses Feature vollständig gemäß der Spezifikation um.