Java EE ist eine Sammlung von Spezifikationen, APIs und Implementierungen für komponentenorientierte, verteilte Anwendungen entwickelt von Sun Microsystems (inzwischen: Oracle), 1999. Richtig umgesetzt zeichnen sich Anwendungen auf der Basis von Java EE durch eine Reihe von Besonderheiten aus, für die es meines Erachtens kein Konkurrenzprodukt gibt.
Wenn Sie die folgenden Eigenschaften Ihrer Geschäftsanwendung für wichtig erachten, dann sollten Sie den Einsatz von Java EE in Betracht ziehen:
- modularisierbare Fachlogik
- Plattformunabhängigkeit
- Skalierbarkeit
- Herstellerunabhängigkeit
- Sicherheit, Transaktionalität und Persistenz per Konfiguration und/oder Deklaration
- breite Unterstützung durch die Open Source Entwicklergemeinde
- Ein klar gefasstes Ziel der Java EE Spezifikation war die Vereinfachung der Entwicklung serverseitiger Geschäftslogik. Dieses ehrgeizige Ziel entstand aus der richtigen Beobachtung, dass es leichter ist, viele Fachanwender mit (allgemeingültigen) Java-Grundkenntnissen auszustatten, als wenige Java-Spezialisten mit (projektspezifischem) Fachwissen. Das Ziel ist klar verfehlt: bei der Umsetzung einer Geschäftsapplikation auf Basis von Java EE müssen Sie bei Ihren Mitarbeitern eine hohe Java- und Java EE-Kompetenz voraussetzen. Ist das gegeben, werden Sie diese Entwickler möglichst effizient mit dem Wissen um Ihre fachlichen Daten und Prozesse versorgen. Anders ausgedrückt: Ihr Java EE Projekt funktioniert dann, wenn Sie viel Java EE-Kompetenz vereinen mit einem kraftvollen Anforderungsmanagement. Hinzufügen möchte ich noch, dass das auch für andere Frameworks für die Umsetzung zentraler Geschäftslogik gilt. Vertrauen Sie hier ihrem gesunden Menschenverstand und nicht den Versprechungen der Vertriebler.
- Die Modularisierung der Entwicklung von Java EE Komponenten ist stark eingeschränkt, da die Java EE Spezifikation nicht vollständig die Konfiguration der Module regelt. Diese Konfiguration müsste klar vorgeben, welche Abhängigkeiten der Module untereinander und zu externen Ressourcen bestehen und vor allem, wie das Classloading diese Abhängigkeiten berücksichtigt. Näheres dazu im Kapitel Classloading in Java EE Umgebungen.
Inzwischen gibt es sehr reife Konzepte, wie eine solche Modularisierung von Anfang an hätte geregelt sein können (siehe dazu: saubere Architekturen mit Dependency Injection). Leider ist die Verknüpfung solcher Konzepte mit der Java EE Spezifikation nur in Ausnahmefällen möglich und nicht immer portabel (siehe dazu: OSGi im Java EE Server).
- Die EJB Schicht bietet keine Möglichkeit zur Umsetzung des Singleton-Patterns, zum Beispiel für Cache-Implementierungen. Wie ich zu dieser Aussage kommen finden Sie im Kapitel Singletons in Java EE Umgebungen. Auch der Container bietet keine speicherbasierte, gemeinsam nutzbare Resource mit einer vom Server überwachten Transaktionalität und Thread-Sicherheit. In der Webschicht ist die Situation entspannter. Jedes Servlet wird vom Webcontainer laut Spezifikation nur einmal erzeugt (es sei denn es implementiert SingleThreadModel) und kann damit als Quasi-Singleton benutzt werden.
- Die Umsetzung für asynchrone Verarbeitung ist schwergewichtig und erfolgt über JMS, Message-Driven Beans und Web Services. Mehr dazu unter Asynchrone Verarbeitung in Java EE Umgebungen. All das ist Bestandteil der aktuellen Spezifikation, in der Praxis wünscht man sich allerdings oft leichtgewichtige Varianten innerhalb der Web- und EJB-Schicht.
- Das remove in EJBObject zeigt je nach Beantyp serverseitig folgendes zum Teil drastisch unterschiedliches Verhalten:
- Stateless Session Beans, Message Driven Beans: Keine (für den Client sichtbare) Wirkung.
- Stateful Session Beans: Die Beaninstanz wird beseitigt, alle Resourcen der Session können freigegeben werden.
- Entity Beans: Der Datensatz, den die Bean repräsentiert, wird gelöscht.
Hier entstehen Missverständnisse, die vor allem Anfänger zu schaffen machen. Gleiches gilt für die create-Methoden des HomeInterfaces. Anmerkungen: i) Der clientseitige Effekt ist freilich für alle Beansorten identisch: create beschafft die Stub-Instanz des Bean-Proxy, remove gibt diese Instanz wieder frei. ii) Für das remove(Object) und remove(Handle) in EJBHome gilt das gleiche wie für remove in EJBObject.
- Die EJB Spezifikation verschleiert den Unterschied zwischen Stateful und Stateless Session Beans. Beide Beantypen besitzen daher die gleiche Schnittstelle und zwischen beiden Typen kann mittels Konfiguration gewechselt werden. Dieser Wechsel ist aber in der Praxis unsinnig. Das unterschiedliche Laufzeit- und Skalierverhalten beider Beantypen impliziert eine unterschiedliche fachliche Semantik und Implementierung. Auch hier führt die gemeinsame Behandlung von Dingen die eigentlich nicht zusammen gehören zu Missverständnissen. Alternativ dazu wäre ein Session-Management analog zur Servlet-Spezifiaktion denkbar gewesen. Man beschafft sich also bei Bedarf eine Session (und nur dann), diese wird vom Server verwaltet und kann beispielsweise auch von Beans gemeinsam benutzt werden. Solche Implementierungen skalieren gut und besitzen eine besser verständliche API. Stateful Session Beans wären dann überflüssig (und damit ejbActivate und ejbPassivate).
- Das Home-Interface für Stateless Session Beans ist ohne Semantik.
Die genannten Kritikpunkte betreffen alle die EJB Spezifikation, diese wiederum ist nur ein Teil der gesamten Java EE Spezifikation. Viele der aufgelisteten Probleme ließen sich schon immer mit den geeigneten Werkzeugen abschwächen (namentlich XDoclet hat hier im professionellen Einsatz enorme Vorteile gebracht). Mit der Einführung von Java5 und dem darauf basierenden Programmiermodell in EJB 3.0 wurde ein Schritt in die richtige Richtung getätigt. Einige der genannten Kritikpunkte treffen nun garnicht mehr zu (5, 7), andere sind deutlich abgeschwächt (1, 4).
Mit Service Loading kann mit gewissen Einschränkungen eine Modularisierung der EJB-Funktionen erreicht werden (2).
Des weiteren schließe ich mich der allgemeinen Kritik der Entity Beans in EJB 2.1 ausdrücklich nicht an. Dennoch begrüße ich die starke Vereinfachung bei der Arbeit mit EntityBeans und die Einführung eines objektrelationalen Mappers in EJB 3.0 (Java Persistence API, JPA, JSR 220), der übrigens auch in J2SE Umgebungen zur Verfügung steht.
EJB 3.1 (JSR318) bringt weitere Vereinfachungen:
- Stateless Session Beans können per JVM als Singletons deklariert werden, der Kontainer wird nur eine Instanz per Anwendung erzeugen. (3)
- Unter gewissen Umständen können Beans lokal direkt (und nicht über ein Business-Interface) gerufen werden.
- Session Beans können asynchron gerufen werden. Das Returnobjekt Future<V> ist eine remote Referenz auf den asynchron ablaufenden Thread des Aufrufs und gibt dem Client eine gewisse Kontrolle. Dazu gehören ein Zeiger auf die Resultate, Ausnahmen und Abbruch der nebenläufigen Verarbeitung.(4)
EAI Designpattern