Hawlitzek GmbH/ Veröffentlichungen/ EJB im Wandel/
 

Hawlitzek IT-Consulting GmbH ©Foto Kirsten Literski-Hawlitzek

EJB im Wandel

Dieser Artikel ist im JavaSpektrum 5/00 erschienen. Vielen Dank an SIGS für die Genehmigung zur Veröffentlichung auf dieser Webseite!

In den letzen Jahren haben sich die EJBs von der objektorientierten Hülle verteilter Prozeduraufrufe (RMI) zum universellen Mittel der Serverprogrammierung und Legacy-Integration entwickelt. In der neuesten Version des Standards, die sich gerade im Status eine Public Drafts befindet, wurden die Fähigkeiten des Komponentenmodells noch einmal deutlich erweitert und auch auf viele Kritikpunkte von Anwendern und Herstellern reagiert.

Die folgende Tabelle stellt die wichtigsten Unterschiede der einzelnen Spec-Versionen gegenüber:

 

1.0

1.1

2.0

Bean-Typen

Session,
Entity (optional)

Session,
Entity (verpflichtend)

Session,
Entity,
Message-driven

Aufrufe

synchron

synchron

synchron,
asynchron

Deployment Deskriptor

serialisierte Klasse

XML

XML

empfohlenes Protokoll

RMI

RMI/IIOP
CORBA/IIOP optional

RMI/IIOP
CORBA/IIOP verpflichtend

Umgebungsvariablen

via EJBContext

via JNDI

via JNDI

geforderte Java-Version

1.1

1.2 (1.1 möglich)

1.3

Bei container-managed persistence beans:

Relationen zw. EJBs

nicht spezifiziert

nicht spezifiziert

ja

Nutzung von Nicht-EJB-Klassen

ja, aber Persistenzierung nicht spezifiziert

ja, aber Persistenzierung nicht spezifiziert

ja, inkl. Persistenzierung und Relationen

CMP DB-Mapping

container-spez. Tools (optional)

container-spez. Tools

via EJB QL und Persistance Manager

Zugriff auf CMP-Felder

public-Felder

public-Felder

get/set-Methoden

abstrahierter Persistenz-Lookup

finder-Methoden

finder-Methoden

finder-Methoden,
select-Methoden (intern)

 

Methoden auf Home-Ebene

nur Lifecycle

nur Lifecycle

Lifecycle und objektunabhängige Businessmethoden

Vererbung auf Komponentenbasis

nein

nein

nein

Zunächst einmal ist ein Trend weg von proprietären Protokollen und Formaten zu Standards erkennbar. So wird beispielsweise der Deployment Deskriptor seit 1.1 im XML-Format gespeichert, Umgebungsvariablen werden wie die Homes über das Java Naming und Directory Interface (JNDI) abgefragt und für die Kommunikation wird die Unterstützung des CORBA-Protokolls IIOP verpflichtend. Damit wird der Einsatz von Komponenten in unterschiedlichen Servern möglich. Bislang konnte man zwar eine EJB plattform- und serverunabhängig entwickeln, eine Kommunikation zwischen Beans in Containern unterschiedlicher Hersteller klappt aber in den seltesten Fällen und eine Möglichkeit, eine Mappingvorgabe für persistente Entity Beans in relationale Datenbanken zu spezifizieren gibt es vor Version 2.0 auch nicht.

EJB-Typen

Abbildung : EJB-Arten in EJB-Version 2.0

In der ersten Version der EJB-Spezifikation (1.0) war nur die Unterstützung von Session Beans vorgeschrieben. Das sind EJBs, die genau einem Client (z. B. einem Servlet oder einer Anwendung) zugeordnet sind. Diese Beans können einen internen Zustand haben, der über mehrere Aufrufe derselben Bean hinweg existiert. Dieser Zustand wird aber in der Regel nur im Hauptspeicher gehalten (oder temporär auf die Platte ausgelagert), überlebt aber einen Absturz oder Neustart des Server nicht.

Entity Beans sind hingegen persistent in einem Backendsystem gespeichert, das Methoden zum Erzeugen, Lesen, Schreiben und Löschen der Objekte bereitstellt (CRUD = create, read, update, delete). In der Regel übernehmen diese Aufgaben relationale Datenbanken, es sind aber auch andere Systeme möglich (z.B. CICS, SAP...). Bei letzteren wird man die Zugriffsmethoden in der Regel selbst implementieren müssen (BMP = bean-managed persistance), bei ersteren können Sie rein abstrakt vorgeben, welche Felder persistent sein sollen und die Mapping-Tools der EJB-Servers generieren den tatsächlichen Zugriffscode (CMP = container-managed persistance). Somit bleibt die Komponente unabhängig von Datenbankspezifika (DB2, Oracle, Sybase...) und den Implementierungen der eingesetzten Container für Transaktionen, Connection Pools usw. Gerade bei den CMP Beans hat sich in der Spec 2.0 viel geändert, eine Beschreibung finden Sie unten.

Bislang wurden alle Methodenaufrufe von EJBs synchron durchgeführt, das heißt der Client wartet bis ein Rückgabewert vom Server geliefert wurde. Bei Message-driven Beans (seit EJB 2.0) ist dies anders. Nun ist auch das asynchrone Auslösen von Aktionen durch den Java Messaging Service (JMS) möglich. Das bedeutet, die Clients stellen eine Nachricht in eine Warteschlange ein (JMS Topic oder Queue), für die der EJB-Server als Subscriber registriert ist. Jede EJB arbeitet nun anstehende Requests ab und ruft für jede Nachricht die onMessage-Methode auf. Die Clients warten nicht auf das Ende des Methodenaufrufes, können jedoch eine Rückmeldung (Acknowledgement) erhalten, wenn eine Message-driven Bean den Auftrag bearbeitet hat.

Beispiel

import javax.ejb.*;
import javax.jms.*;

public class LogBean implements MessageDrivenBean
{

 public void onMessage(Message message)
 {
  // Nachricht analysieren und in Standardausgabedatei
  // des Applikationserver ausgeben:

  ObjectMessage om = (ObjectMessage)message;
  System.out.print(om.getJMSMessageID() + "(" +
   java.text.DateFormat.getInstance().format(om.getJMSTimestamp()) +
   "): ");
  System.out.println(om.getObject()) ;
 }
}

Die Message-driven Beans ähneln vom Verhalten zustandslosen (stateless) Session Beans. Sie müssen allerdings nicht explizit mit create-Methoden erzeugt werden und besitzen weder ein Home noch eine Remote Interface. Im Gegensatz zu bisherigen JMS-Servern können auch mehrere EJBs gleichzeitig aktiv sein und eine große Anzahl Requests parallel bearbeiten. Die Client-Programmierer müssen sich dabei aber bewusst sein, dass die Aufträge unter Umständen nicht streng sequentiell abgearbeitet werden.

Daneben können natürlich auch alle EJB-Typen wie jeder J2EE-Client selbst JMS-Nachrichten an beliebige Topics oder Queues schicken.

Life Cycle

Alle anderen EJB-Arten unterliegen einem festen Lebenszyklus, der mit dem einer Klasse vergleichbar ist. Allerdings werden EJB-Objekte im Server aus Effizienzgründen nicht bei jedem Aufruf neu erzeugt, sondern aus einem Pool inaktiver Objekte mit dem aktuellen Zustand versorgt. Daher können die von Objekten bekannten Mechanismen nicht 1:1 übernommen werden, sondern werden über spezielle Methoden realisiert, die im Home Interface definiert und in der Bean-Klasse implementiert sind:

 

Klasse

EJB

Erzeugung

Konstruktor

ejbCreate()
ejbCreate<METHOD>() (2.0)

optionale Bereinigung

finalize()

ejbRemove()

Klassenmethoden

Modifier static

ejbHome<METHOD>() (2.0)

Serialisierung

via ObjectOutputStream.writeObject(o),
ObjectInputStream.readObject(o)

nach ejbPassivate() bzw.
ejbActivate()

Persistenz

via java.sql.Statement

nach bzw. mit ejbLoad() bzw. ejbStore()

In der EJB-Version 2.0 kam die Möglichkeit hinzu, auch Businessmethoden zu definieren, die unabhängig von einer einzelnen EJB-Instanz sind, sich also beispielsweise auf alle Objekte gleichzeitig auswirken. Diese Funktionalität ist vergleichbar zu Klassenmethoden und wird mit Methoden mit dem Präfix ejbHome realisiert.

Ebenfalls neu ist die Möglichkeit, create-Methoden mit unterschiedlichen Namenszusätzen zu erzeugen. Sie können damit mehrere Methoden schreiben, die zwar die gleichen Parametertypen haben, sich in der Funktionalität jedoch unterscheiden.

Container-managed persitance

CMP Beans implementieren die Logik zur Speicherung in einer Datenbank nicht selbst. Die Methoden ejbLoad(), ejbStore() und ejbRemove() haben in der Regel einen leerem Methodenrumpf, denn der tatsächliche Zugriffscode wird erst beim Deployment, also beim Einbringen in den Container generiert. Dazu müssen die Generatortools aber wissen, welche Felder der Bean persistent gespeichert werden sollen. Dies gibt man im Deployment Deskriptor an, der seit EJB 1.1 folgende Form hat:

<ejb-jar>
...
<enterprise-beans>
<entity>
  <ejb-name>Kunde</ejb-name>
  <home>de.hawlitzek.ejb.KundeHome</home>
  <remote>de.hawlitzek.ejb.Kunde</remote>
  <ejb-class>de.hawlitzek.ejb.KundeBean</ejb-class>
  <persistence-type>Container</persistence-type>
  <prim-key-class>java.lang.String</prim-key-class>
  <reentrant>False</reentrant>

  <cmp-field><field-name>ID</field-name></cmp-field>
  <cmp-field><field-name>vorname</field-name></cmp-field>
  <cmp-field><field-name>nachname</field-name></cmp-field>
</entity>
</enterprise-beans>
</ejb-jar>

Die Attribute sehen in der Implementierungsklasse nach EJB 1.x folgendermaßen aus:

import javax.ejb.*;
public class KundeBean implements EntityBean
{
 public int ID;
 public String vorname;
 public String nachname;
 …
}

Seit EJB 2.0 werden die Zugriffe nur noch mit abstrakten Zugriffsmethoden angegeben:

import javax.ejb.*;
public abstract class KundeBean implements EntityBean
{
 public abstract int getID();
 public abstract void setID(int id);
 public abstract String getVorname();
 public abstract void setVorname(String vorname);
 public abstract String getNachname();
 public abstract void setNachname(String nachname);
 …
}

Alle CMP-Felder werden seit mittels öffentlicher Get- und Set-Methoden angesprochen, die allerdings abstract definiert sein müssen und dem Client nicht im Remote Interface direkt zur Verfügung gestellt werden dürfen.

Die drei Felder ID, vorname und nachname sind in diesem Beispiel vom Container auf eine Datenbank abzubilden. Es ist aber nicht vorgegeben, auf welche Tabellenstruktur die Abbildung vorgesehen ist und welche SQL-Datentypen dafür benutzt werden sollen. Ein ähnliches Problem ergibt sich bei den finder-Methoden, die dazu dienen, Objekte nach bestimmten Kriterien in der Datenbank zu finden und als EJB-Objekte zu instanziieren. Diese müssen auf SQL-SELECT-Statements abgebildet werden, es ist nicht vorgegeben, wie diese Query aussieht. Der Deployer ist mit diesen vagen Vorgaben oft überfordert.

Deshalb gibt es seit EJB 2.0 mehrere Erweiterungen:

  • Neben den Rollen des Container und Server Providers wurde der Persistance Manager Provider eingeführt, der das Framework für das Mapping der EJBs in ein nicht-objektorientiertes Backend bereitstellt.
  • Im Deployment Descriptor kann eine abstrakte Schema-Beschreibung angegeben werden, die beschreibt, wie das objekt-relationale Mapping durchgeführt werden soll. Diese enthält die persistenten Felder der Bean und der von ihr abhängigen Klassen sowie von Relationen.
  • Es wurde eine SQL-ähnliche Sprache mit dem Namen EJB QL geschaffen, mit der die Queries für finder-Methoden definiert werden können, ohne Datenbankspezifika zu berücksichtigen (wie Datenbanktyp, -namen, Indexe, Trigger...). Diese ermöglicht auch, über sogenannte Pfade in den Queries zu navigieren, also Relationen zwischen EJBs.

Ist für obige Kunden-EJB eine Methode

public abstract Collection findByNachname(String name) throws FinderException

definiert, so kann diese im Deployment Deskriptor durch folgendes EJB QL Statement abgebildet werden:

<query>
 <query-method>
  <method-name>findByNachname</method-name>
  <method-params>java.lang.String</method-params>
 </query-method>

 <ejb-ql><![CDATA[WHERE nachname = ?1]]></ejb-ql>
</query>

In der Query kann auf alle CMP-Felder der Bean zugegriffen werden. Neben diesen direkt in der Entity Bean definierten Feldern kann man auch Objekte anderer Klassen persistenzieren, deren Lebenszyklus komplett durch die EJB gesteuert werden, die dependent objects. Für diese können analog zu den finder-Methoden die sogenannten select-Methoden spezifiziert werden, die ebenfalls in EJB QL formuliert werden, aber nicht in der öffentlichen Schnittstelle der Bean in Erscheinung treten.

Relationen

Neu in EJB 2.0 sind verschiedene Arten von Relationen zwischen Enterprise JavaBeans untereinander sowie zu anderen Objekten, die nun auch im Deployment Deskriptor angegeben werden können. Nicht alle Business-Objekte modelliert man als Enterprise JavaBeans. Oft hat eine EJB zusammengesetzte Attribute, wie zum Beispiel eine Adresse im obigen Kundenbeispiel. Diese wird man als Klasse modellieren, jedoch nicht als EJB, da die Objekte dieser Klassen nur im Kontext der EJB benötigt werden und ihr Lebenszyklus allein durch diese gesteuert wird. Es gibt zwei Arten dieser abhängigen (dependent) Objekte:

  • dependent value classes sind serialisierbar und können z. B. auch als Copy Helper benutzt werden, um die Inhalte mehrerer Felder einer EJB en bloc zum Client zu übertragen. Falls ein solches Objekt persistent gespeichert wird, dann in der Regel in ein Binärfeld (BLOB) einer Datenbanktabelle.
  • dependent object classes hingegen sind strukturiert und ihre Attribute können separat in Tabellenspalten der Datenbank gemappt werden. Sie können auch in Relationen teilnehmen und zur Navigation in EJB Queries genutzt werden.

Daneben gibt es natürlich auch Relationen zwischen Enterprise JavaBeans, zum Beispiel zwischen einem Kunden und seinen Bestellungen. Relationen treten als 1:1, 1:n und n:m-Beziehungen auf, wobei vor allem letztere schwer zu persistenzieren sind, da dies zusätzliche Datenbanktabellen erfordert. Die Modellierung einer 1:n Relation sieht in EJB QL so aus:

<relationships>
 <ejb-relation>
  <ejb-relation-name>Kunde-Adresse</ejb-relation-name>
  <ejb-relationship-role>
   <ejb-relationship-role-name>
     kunde-hat-adressen
   </ejb-relationship-role-name>
   <multiplicity>one</multiplicity>
   <role-source><ejb-name>Kunde</ejb-name></role-source>
   <cmr-field>
    <cmr-field-name>adressen</cmr-field-name>
    <cmr-field-type>java.util.Collection</cmr-field-type>
   </cmr-field>
  </ejb-relationship-role>

  <ejb-relationship-role>
   <ejb-relationship-role-name>
    adresse_gehoert_zu_kunde
   </ejb-relationship-role-name>
   <multiplicity>many</multiplicity>
   <role-source><dependent-name>Adresse<dependent-name></role-source>
   <cmr-field>
    <cmr-field-name>person</cmr-field-name>
   </cmr-field>
  </ejb-relationship-role>
 </ejb-relation>
<relationships>

Fazit

Der neue Entwurf der EJB-Spezifikation erfüllt viele Wünsche und ergibt ein sehr mächtiges und flexibles Komponentenmodell. Offene Punkte und bestehende Inkompatibilitäten zwischen Applikationsservern werden durch die präzisen Vorgaben beseitigt. So werden zum Beispiel proprietäre Ansätze zur Definition von finder-Methoden wir BEAs WLQL oder IBMs FinderHelper-Klassen durch die EJB QL abgelöst. Mit einer Preview von BEA WebLogic gibt es bereit den ersten Container, der EJB 2.0 unterstützt, obwohl diese Version noch nicht einmal als Standard verabschiedet wurde (allerdings ohne Unterstützung von Relationen).

Es ist zu hoffen, dass die Spezifikation bald abgeschlossen und von allen Herstellern von Java Applikationsservern unterstützt wird. Dies würde die heute noch häufig zu hörende Kritik der Enterprise JavaBean als zu junge, noch unreife Technologie schnell vergessen lassen.

 

 

Literatur

 

[Sun] Sun Enterprise JavaBeans 2.0 Public Draft, http://www.javasoft.com

 

[Mon] Richard Monson-Haefel : Read all about EJB 2.0, http://www.monson-haefel.com

 

[BEA] EJB 2.0 for BEA WebLogic Server, http://www.beasys.com

 

© 2006 Hawlitzek IT-Consulting GmbH,
Marketing&Design Kirsten Literski-Hawlitzek

Seitenanfang

Hawlitzek GmbH
Die Gründer
Dienstleistungen
Java Downloads
Vorträge
Veröffentlichungen
Kontakt
International
Sitemap