|
Letzte
Bearbeitung dieses Dokuments: |
Voraussetzungen für das Verständnis dieses Dokuments:Grundkenntnisse in der Programmierung bei der Verwendung - und als Voraussetzung dafür Kenntnisse in der Programmierung mit Java (Klassen, Methoden, Vererbung, Interface). Theoretische Kenntnisse über die Architektur eines Client/Server-Programms wenn EJB verwendet werden. |
Ungefährer Zeitbedarf zum Durcharbeiten dieses Dokuments:Dieses Dokument ist ein 'Nachschlagwerk' mit Themen zur 'Philosophie', wie ein Java Application Server (JAS) EJB lädt und verwendet und wie die Entwurfs- und Implementierungs-Entscheidungen darauf abzustimmen sind. Aus diesem Grund wird kein Zeitbedarf angegeben. |
Dieses Dokument beschreibt im ersten Teil die Anweisungen 'Stateless' und 'Stateful' mit denen dem Java Application Server (JAS) mitgeteilt wird, 'wie es im Inneren eines EJB aussieht'.
Im zweiten Teil wird beschrieben, wie bei einem als 'Stateless' gekennzeichneten EJB mit 'synchronized' verhindert wird, dass Variablen innerhalb einer Methode von mehr als einem Client-Programm verändert werden können.
Im
dritten Teil sind Anleitungen dargelegt, wie eine optimale
Architektur für
* EJB, deren Methoden relativ kurze
Laufzeiten haben und selten von Client-Programmen aufgerufen
werden:
* EJB, die häufig von Client-Programmen aufgerufen
werden (High Volume Access);
* EJB, deren Methoden lange
Laufzeiten haben aber selten aufgerufen werden
aussieht.
'Stateless'
und 'Stateful' Anweisungen für ein EJB
Auswirkungen
von 'synchronized'
Muster-Architekturen
* EJB
mit selten verwendeten Methoden mit kurzen Laufzeiten
* EJB
mit häufig verwendeten Methoden
* EJB
mit selten verwendten Methoden mit langen Laufzeiten
Verwandte
Dokumentation
Vor
dem
EJB3-Standard:
Der Parameter 'Stateless' bzw. 'Stateful' wird
in der Datei 'ejb-jar.xml' (als Wert des XML-Elements <session-type>)
festgelegt und informiert den JAS (Java Application Server) ob
innerhalb der EJB-Klasse (mindestens) eine Variable definiert ist,
deren Wert innerhalb jeder Methode verändert werden kann
(Stateful) – oder nicht (Stateless).
Ab
dem EJB3-Standard:
Durch die 'Injection'-Anweisungen
@Stateless bzw.
@Stateful wird in
der Klasse für das EJB die Anweisungen an den JAS
festgelegt.
Die Wirkungsweise dieser 'Injection'-Anweisungen ist
gleich wie vor dem EJB3-Standard.
Ist
ein EJB als 'Stateful' gekennzeichnet, dann kann eine Instanz
des EJB nur einem Client zugeordnet werden.
Das ist notwendig um
sicher zu stellen, dass die Variable, die für die gesamte
EJB-Klasse gilt, nicht von einem anderen Client verändert werden
kann.
Wie der JAS bei der Instanziierung von 'Stateful' EJB vorgeht zeigt folgendes Schema:
|
|
Wenn
ein weiterer Client die EJB-Klasse instanziiert erzeugt der JAS
eine eigene Instanz. |
|
Wenn
die Ausführung der von Client A aufgerufenen Methoden beendet
ist - und die Zuordnung im Code des Client-Programms gelöst
wird - wird die Instanz vom JAS als 'verfügbar'
gekennzeichnet. |
|
Wenn ein weiterer Client die EJB-Klasse instanziiert verwendet der JAS die im Speicher vorhandene verfügbare Instanz des EJB. |
|
Die obigen Schemata zeigen nur die Speicherbelegung bei einer EJB-Klasse. Im realen Betrieb mit mehr EJB-Klassen und einer Vielzahl von Clients wird der zur Verfügung stehende Speicher wesentlich mehr Instanzen verschiedener EJB-Klassen enthalten. Aufgabe des JAS ist, seit längerer Zeit nicht mehr verwendete Instanzen zu entfernen und damit Speicherplatz freizugeben. |
|
Ist ein EJB als 'Stateless' gekennzeichnet, dann kann eine Instanz des EJB mehreren Clients zugeordnet werden.
Wie der JAS bei der Instanziierung von 'Stateless' EJB vorgeht zeigt folgendes Schema:
|
|
Wenn ein weiterer Client die EJB-Klasse instanziiert erzeugt der JAS keine eigene Instanz sondern verwendet die bereits vorhandene Instanz für die Methoden-Aufrufe des weiteren Clients. |
|
Wenn die Ausführung der von Client A aufgerufenen Methoden beendet ist wird die Zuordnung des Client A zur Instanz der EJB-Klasse durch den Code im Client-Programm gelöst. Auch wenn die Instanz der EJB-Klasse mit keinem anderen Client mehr verbunden wäre würde der JAS die Instanz im Speicher belassen – solange freier Speicher vorhanden ist. |
|
Wenn ein weiterer Client die EJB-Klasse instanziiert verwendet der JAS die im Speicher vorhandene Instanz des EJB auch für diesen Client. |
|
Vorteil gegenüber 'Stateful' EJB ist, dass für eine EJB-Klasse nur eine Instanz erstellt wird und damit weniger Speicher für die Instanzen der EJB-Klassen notwendig ist. |
|
Bei
der Architektur von 'Stateless' EJB ist darauf zu achten, dass keine
Variablen, die für die gesamte Klasse gelten, definiert
sind.
Weiters muss verhindert werden, dass Variablen innerhalb von
Methoden durch verschiedene Clients verändert werden.
Das
wird durch 'synchronized' erreicht.
Mit
der Anweisung 'synchronized' wird festgelegt, dass der Code einer
Methode, Teile des Codes oder auch nur einzelne Variable gleichzeitig
nur von einem 'Thread' verwendet werden kann.
Ein 'Thread' ist im
einfachsten Fall der Aufruf durch eine andere Methode.
Nebenthema:
Java
Code ist als Standard nicht 'thread-safe'; das bedeutet, dass
ein Code gleichzeitig von mehreren Threads ausgeführt werden
kann und der Wert einer Variable von verschiedenen Threads verändert
und abgefragt werden kann.
Unter Umständen werden
dadurch die Werte der Variable innerhalb der Methode ungewollt
verändert.
Ohne Verwendung von 'synchronized' könnte innerhalb der Methode eines EJB folgende ungewollte Situation auftreten:
|
|
Für Client A wird innerhalb der Methode das zweite 'Select' auf die Datenbank ausgeführt. Zu dieser Zeit ruft Client B die Methode auf. |
|
Für Client A wurde der gesamte Code für die Verarbeitung des Geschäftsfalles abgeschlossen und die Verbindung zur Datenbank wird 'geschlossen'. Zu diesem Zeitpunkt wird für Client B eine Verarbeitung der Daten aus dem ersten 'Select' auf die Datenbank ausgeführt. |
|
Die Verarbeitung für Client B will das zweite 'Select' auf die Datenbank ausführen. Es tritt dabei ein Fehler auf weil die Verbindung zur Datenbank bereits durch die Verarbeitung für Client A 'geschlossen' wurde. |
|
Mit 'synchronized' wird bewirkt, dass die Verarbeitung für Client B erst beginnt wenn die Methode für Client A beendet ist.
Um
eine ganze Methode als 'synchronized' zu deklarieren wird folgende
Methoden-Deklaration verwendet (Beispiel):
public
synchronized
Connection
establishDBConnection {
Es
ist nicht erforderlich, eine ganze Methode als
synchronized
zu deklarieren - es können nur
Teile der Methode oder einzelne Variable deklariert werden.
Eine
weitergehende Abhandlung des Themas würde aber die Aufgabe
dieses Dokuments überschreiten.
Bei Interesse zu diesem
Thema (und besonders wenn Sie an der Optimierung des Codes arbeiten)
finden Sie unzählige Beispiele im Internet.
Die Entscheidung, welches der folgenden Muster am günstigsten für die jeweilige Anforderung ist, lässt sich leider nicht mit einer mathematischen Formel oder einem Algorithmus ermitteln.
Die
Grenze, ab der ein EJB als 'Stateless' oder 'Stateful' deklariert
wird, ist fließend und hängt auch von der persönlichen
Erfahrung bei der Entwicklung von Anwendungen mit EJB ab.
Ich (der
Autor) gehe wie folgt vor:
Bei Methoden, die klar einem der Muster entsprechen schreibe ich eine kurze Begründung als Kommentar zu Beginn der Methoden-Deklaration in der EJB-Klasse.
Bei
Methoden die nicht offensichtlich ein als 'Stateful' deklariertes
EJB erfordern, dokumentiere ich folgende Annahmen:
* Erwartete
Aufrufe der Methode (pro Sekunde) zu Spitzenzeiten.
* Erwartete
maximale Anzahl der Clients, die annähernd gleichzeitig die
Methode aufrufen werden.
* Bei Standard-Software als
Vergleichswert die maximale Anzahl der Arbeitsplätze (Clients),
von denen Methoden aufgerufen werden könnten.
* Eine
Begründung, warum nur vom angenommenen Teil der Clients die
Methode annähernd gleichzeitig aufgerufen wird.
Mit
dieser Dokumentation kann später im Betrieb der Anwendung
verglichen werden, wie weit die Annahmen des Entwurfs von der
Realität abweichen und ob Änderungen notwendig sind.
Methoden,
die in einem als 'Stateful' deklarierten EJB implementiert werden
müssen, werden darauf hin untersucht, ob die Aufrufe dieser
Methode ein eigenes EJB notwendig machen.
Als Alternative kann
sinnvoll sein, Methoden, die annähernd gleichzeitig aufgerufen
werden, gemeinsam in ein EJB zu implementieren.
Dann ist zu
erwarten, dass ein 'verfügbares' EJB bereits im Speicher
geladen ist wenn ein Client eine dieser Methoden aufruft.
Obwohl
Hauptspeicher ausreichend vorhanden und billig ist rate ich dazu, bei
nicht eindeutigen Indizien eine Methode in einem als 'Stateless'
deklarierten EJB zu implementieren.
Bei einem häufigen
Aufruf irgendeiner Methode des EJB bleibt die Instanz des EJB ständig
im Hauptspeicher.
In vielen Fällen ist dann die Wartezeit
eines Client, der eine (als 'synchronized' deklarierte) Methode, die
gerade von einem anderen Client blockiert wird, ausführen will,
kürzer als wenn der JAS (Java Application Server) eine neue
Instanz der EJB-Klasse in den Hauptspeicher laden muss.
Sollte
sich im Betrieb ergeben, dass die Methode häufig von mehreren
Clients annähernd gleichzeitig aufgerufen wird, kann die
betroffene Methode immer noch zusätzlich in einem als 'Stateful'
deklarierten EJB implementiert werden.
Als Änderung auf der
Client-Seite der Anwendung ist die Änderung der
Client-Side-Klasse des Business Object (BOC) notwendig.
In dieser
BOC-Klasse muss der Aufruf zur Instanziierung des EJB geändert
werden.
Wurde die Methode in einer komplett neuen EJB-Klasse
implementiert dann ist im Start-Frame (CommandCenter) entsprechend
dem Muster-Code eine Methode zur Instanziierung des EJB zu
implementieren.
Eine
größere Anzahl an EJB-Klassen für ein
Anwendungsprogramm bedeutet aber auch einen höheren Aufwand bei
Entwurf, Implementierung und Ausführung des
Anwendungsprogramms.
Die 'Rückseite der Medaille' ist,
dass ein – vielleicht aus einem Sicherheitsdenken
hervorgegangenes – Erhöhen der Anzahl der EJB-Klassen auch
einen erhöhten Arbeitsaufwand bei der Erstellung des
Anwendungsprogramms als auch zusätzliche Kapazität des
Computers bei der Ausführung der einzelnen EJB bedeutet.
Diese Anforderung wird bei einer Software-Anwendung am häufigsten auftreten.
Als
kurze Laufzeit ist eine Zeit bis zu einer Sekunde definiert.
Dieser
Zeit ist gerade so kurz, dass bei einem Anwender die Konzentration
auf seine Tätigkeit nicht nachlässt.
Bei einer
Standard-Software, wo zum Zeitpunkt der Analyse die
Leistungsfähigkeit des Computers im Echtbetrieb nicht bekannt
ist, ist es empfehlenswert, die Laufzeit auf einem relativ langsamen
Personal-Computer (500 MHz CPU-Takt, 256 MB Hauptspeicher,
IDE-Festplatte) zu ermitteln.
Der Entwurf enthält damit eine Sicherheit, dass bei stärkerer Auslastung eines leistungsfähigeren Computers – und damit eventueller generell langsamerer Verarbeitung – die Laufzeit von maximal einer Sekunde nicht wesentlich überschritten wird.
Haupt-Aufgabe dieser Methoden ist die Erfassung oder Abfrage von Daten durch mehrere Anwender nahezu gleichzeitig.
Damit ist die Wahrscheinlichkeit groß, dass viele Clients ein EJB instanziieren. Dies ist der klassische Fall für die Deklaration eines EJB als 'Stateful'.
Beim
Entwurf des EJB ist aber zu beachten, dass – abhängig von
der Anzahl der Clients – viele Instanzen des EJB im
Hauptspeicher vorhanden sind.
Nachdem der JAS eine komplette
Klasse laden muss, ist es sinnvoll in ein EJB nur eine Methode zu
implementieren oder nur Methoden, die – durch den Arbeitsablauf
bedingt – annähernd gleichzeitig aufgerufen werden; z.B.
zu einer bestimmten Tageszeit.
Diese Methoden sind notwendig für Verarbeitungen, die in früheren Zeiten als 'Batch'-Jobs bezeichnet wurden – z.B. das periodische Drucken von Rechnungen.
Dass
die Methoden in diesem EJB eine lange Laufzeit haben bedeutet nicht
unbedingt, dass sie viel Platz im Hauptspeicher benötigen.
Die
größte Gefahr eines Fehlers im Entwurf ist, dass eine
Methode in einem als 'Stateless' deklarierten EJB doch von einem
zweiten Client aufgerufen wird während ein anderer Client noch
auf das Ende der Verarbeitung wartet.
Wenn der Anwender des
zweiten Clients nicht darüber informiert ist, dass der
gewünschte 'Geschäftsfall' (z.B. das Drucken von Rechnungen
für einen bestimmten Kundenkreis) nur einmal gleichzeitig
ausgeführt werden kann, wird vielleicht ein 'Fehler' reklamiert
und es entstehen vermeidbare Kosten für die Suche der
'Fehlerursache'.
Bei
der Überlegung, ob das EJB als 'Stateful' oder 'Stateless'
deklariert werden soll, ist Folgendes zu bedenken:
* Wie hoch ist
die Wahrscheinlichkeit, dass eine Methode (Geschäftsfall) nahezu
gleichzeitig von mehr als einem Anwender aufgerufen wird.
* Ist es
dem zweiten Anwender zumutbar, die Ausführung der Methode für
den ersten Anwender abzuwarten.
* Kann den Anwendern vermittelt
werden warum der Geschäftsfall nicht von mehreren Anwendern
gleichzeitig ausgeführt werden kann.
* Ist damit zu rechnen,
dass einzelne Anwender einen 'Fehler' bemängeln wenn sie auf die
Ausführung des Geschäftsfalls einmal länger als
gewohnt warten müssen.
Dokument |
Inhalt |
Muster-Codes für die Klasse eines EJB (Enterprise Java Bean) mit Datenbankzugriff |
Diese Anleitung zum Codieren von EJB ist Teil des Leitfaden für die Entwicklung von Heavyweight-Clients mit dem JS-FCF. |
Die in diesem Dokument gelisteten Tutorials behandeln die Entwicklung von Enterprise Java Beans (EJB) und sind hilfreich, wenn Sie sich mit den Grundlagen verschiedener Arten von EJB (ohne oder mit Zugriff auf Datenbanken) vertraut machen wollen. |