SeamFramework.orgCommunity Documentation
Können Sie es jetzt kaum erwarten Ihr erstes Web Bean zu schreiben? Oder sind Sie etwas skeptisch und fragen sich, welche Hürden Ihnen bei der Web Beans Spezifikation bevorstehen? Die gute Nachricht ist, dass Sie wahrscheinlich schon hunderte, wenn nicht tausende von Web Beans geschrieben haben. Vielleicht erinnern Sie sich nicht einmal an das erste Web Bean, das Sie je geschrieben haben.
Mit bestimmten, ganz besonderen Ausnahmen ist jede Java-Klasse mit einem Konstruktor, die keine Parameter akzeptiert ein Web Bean. Das beinhaltet jedes JavaBean. Desweiteren ist jedes EJB 3-artige Session Bean ein Web Bean. Sicher, die von Ihnen täglich geschriebenen JavaBeans und EJBs konnten die neuen, in der Web Beans Spezifikation definierten Dienste nicht nutzen, aber Sie werden diese allesamt benutzen können können, das Web Beans diese in andere Web Beans einspeisen, diese via der Web Beans XML-Konfigurationseinrichtung konfigurieren und diesen sogar Interzeptoren und Dekoratoren hinzufügen, ohne den bestehenden Code anzurühren.
Nehmen wir an, Sie besitzen zwei bestehende Java Klassen, die bis dato in verschiedenen Anwendungen verwendet wurden. Die erste Klasse parst einen String in eine Liste von Sätzen:
public class SentenceParser {
public List<String
> parse(String text) { ... }
}
Bei der zweiten bestehenden Klasse handelt es sich um das Front-End eines "stateless Session Beans" für ein externes System, das in der Lage ist Sätze von einer Sprache in eine andere zu übersetzen:
@Stateless
public class SentenceTranslator implements Translator {
public String translate(String sentence) { ... }
}
Wo Translator
das lokale Interface ist:
@Local
public interface Translator {
public String translate(String sentence);
}
Leider besitzen wir keine bereits bestehende Klasse die ganze Textdokumente übersetzt. Schreiben wir also ein Web Bean, das diesen Job übernimmt:
public class TextTranslator {
private SentenceParser sentenceParser;
private Translator sentenceTranslator;
@Initializer
TextTranslator(SentenceParser sentenceParser, Translator sentenceTranslator) {
this.sentenceParser = sentenceParser;
this.sentenceTranslator = sentenceTranslator;
}
public String translate(String text) {
StringBuilder sb = new StringBuilder();
for (String sentence: sentenceParser.parse(text)) {
sb.append(sentenceTranslator.translate(sentence));
}
return sb.toString();
}
}
Wir erhalten eine Instanz von TextTranslator
durch dessen Einspeisung in ein Web Bean, Servlet oder EJB:
@Initializer
public setTextTranslator(TextTranslator textTranslator) {
this.textTranslator = textTranslator;
}
Alternativ erhalten wir eine Instanz durch direkten Aufruf einer Methode des Web Bean Managers:
TextTranslator tt = manager.getInstanceByType(TextTranslator.class);
Aber warten Sie: TextTranslator
besitzt keinen Konstruktor ohne Parameter! Handelt es sich noch um ein Web Bean? Nun, eine Klasse, die keinen Konstruktor ohne Parameter besitzt, kann nach wie vor Web Bean sein, falls es einen mit @Initializer
annotierten Konstruktor besitzt.
Wie Sie wahrscheinlich bereits erraten haben, hat die @Initializer
-Annotation etwas mit Dependency-Einspeisung zu tun! @Initializer
kann am Konstruktor oder der Methode eines Web Beans angewendet werden und teilt dem Web Bean Manager mit, diesen Konstruktor oder diese Methode bei Instantiierung des Web Beans aufzurufen. Der Web Bean Manager speist andere Web Beans in die Parameter des Konstruktors oder der Methode ein.
Zum Zeitpunkt der Systeminitialisierung muss der Web Bean Manager validieren, dass genau ein Web Bean existiert, das jedem Einspeisungspunkt gerecht wird. Für unser Beispiel bedeutet das, wenn keine Implementierung von Translator
verfügbar ist wenn der SentenceTranslator
EJB nicht deployt wurde dass der Web Bean Manager eine UnsatisfiedDependencyException
melden würde. Wäre mehr als eine Implementierung von Translator
verfügbar, so würde der Web Bean Manager eine AmbiguousDependencyException
melden.
Was also genau ist ein Web Bean?
Bei einem Web Bean handelt es sich um eine Anwendungsklasse, die Business Logik enthält. Ein Web Bean kann direkt von Java Code oder via Unified EL aufgerufen werden. Ein Web Bean kann auf transaktionale Ressourcen zugreifen. Abhängigkeiten zwischen Web Beans werden automatisch durch den Web Bean Manager verwaltet. Die meisten Web Beans sind stateful und kontextbezogen. Der Lebenszyklus eines Web Beans wird immer durch den Web Bean Manager verwaltet.
Erinnern wir uns. Was genau bedeutet es, "kontextuell" zu sein? Da Web Beans "stateful" sein können, ist es relevant welche Bean-Instanz ich besitze. Anders als ein Komponentenmodell, das "stateless" ist (etwas "stateless" Session Beans) oder ein Singleton Komponentenmodell (wie Servlets oder Singleton Beans), sehen verschiedene Clients eines Web Beans das Web Bean in unterschiedlichen Stati. Der Client-sichtbare Status ist abhängig davon, auf welche Instanz des Web Beans der Client verweist (eine Referenz besitzt).
Wie beim "stateless" oder "singleton" Modell anders jedoch als bei "stateful" Session Beans, steuert der Client den Lebenszyklus der Instanz nicht durch expliziertes Erstellen und Löschen. Stattdessen bestimmt der Geltungsbereich des Web Beans:
der Lebenszyklus jeder Instanz des Web Beans und
Welche Clients teilen sich eine Referenz zu einer bestimmten Instanz des Web Beans.
Für einen bestimmten Thread in einer Web Beans Anwendung kann ein aktiver Kontext mit dem Geltungsbereich des Web Beans assoziiert sein. Dieser Kontext kann eindeutig für den Thread sein (etwa wenn für die Web Bean Anfrage ein Geltungsbereich gilt) oder aber kann mit anderen Threads (etwa wenn für die Web Bean ein Session-Geltungsbereich gilt) oder gar allen Threads (falls ein Anwendungs-Geltungsbereich gilt) geteilt werden.
Clients (etwa andere Web Beans), die in demselben Kontext ausführen sehen dieselbe Instanz des Web Beans. Clients in einem anderen Kontext aber sehen eine andere Instanz.
Ein großer Vorteil des kontextuellen Modells ist es, dass es uns gestattet, stateful Web Beans wie Dienste zu behandeln! Der Client muss sich keine Gedanken um das Management des Lebenszyklus des verwendeten Web Beans machen und muss nicht einmal wissen was der Lebenszyklus ist. Web Beans interagieren durch Weitergabe von Nachrichten und die Web Bean Implementierungen definieren den Lebenszyklus ihres eigenen Status. Die Web Beans sind lose gepaart, weil:
sie interagieren über gut definierte öffentliche APIs
ihre Lebenszyklen sind vollständig abgekuppelt
Wir können ein Web Bean durch ein anderes Web Bean ersetzen, das dasselbe API und einen anderen Lebenszyklus (einen anderen Geltungsbereich) besitzt, ohne dass die übrige Web Bean Implementierung hiervon betroffen ist. Genau genommen definieren Web Beans eine raffinierte Einrichtung zur Außerkraftsetzung von Web Bean Implementierungen zum Zeitpunkt des Deployment wie wir in Abschnitt 4.2, „Deployment Typen“ noch sehen werden.
Beachten Sie, dass es sich nicht bei allen Clients eines Web Beans um Web Beans handelt. Andere Objekte wie Servlets oder Message-Driven Beans die ihrem Wesen nach nicht einspeisbar sind, kontextuelle Objekte können durch Einspeisung ebenfalls Verweise auf ein Web Beans erhalten.
Formeller gilt, gemäß der Spezifikation:
Ein Web Bean besteht aus:
Einem (nicht leeren) Satz von API-Typen
Einem (nicht leeren) Satz von bindenden Annotationstypen
Einem Geltungsbereich
Einem Deployment-Typ
Optional einem Web Bean Namen
Ein Satz Interzeptor Binding-Typen
Einer Web Bean Implementierung
Sehen wir uns jetzt genauer an, was diese Begriffe für einen Entwickler von Web Beans bedeuten.
Web Beans erhalten Verweise auf andere Web Beans in der Regel via "Dependency"-Einspeisung. Jedes eingespeiste Attribut legt einen "Vertrag" fest, der vom einzuspeisenden Web Bean erfüllt sein muss. Der Vertrag lautet:
ein API-Typ, zusammen mit
einem Satz von Binding-Typen.
Bei einem API handelt es sich um eine benutzerdefinierte Klasse oder Interface. (Falls es sich bei dem Web Bean um ein EJB Session Bean handelt, so ist der API-Typ das @Local
-Interface oder Bean-Klasse lokale Ansicht). Ein Binding-Typ repräsentiert Client-sichtbare Semantik, die von einigen Implementierungen des API erfüllt wird, von anderen wiederum nicht.
Binding-Typen werden durch benutzerdefinierte Annotationen repräsentiert, die ihrerseits mit @BindingType
annotiert sind. Zum Beispiel besitzt der folgende Einspeisungspunkt den API-Typ PaymentProcessor
und Binding-Typ @CreditCard
:
@CreditCard PaymentProcessor paymentProcessor
Wird an einem Einspeisungspunkt kein Binding-Typ explizit festgelegt, so wird vom standardmäßigen Binding-Typ @Current
ausgegangen.
Für jeden Einspeisungspunkt sucht der Web Bean Manager nach einem Web Bean, das den Vertrag erfüllt (das API implementiert und alle Binding-Typen besitzt) und speist dieses Web Bean ein.
Das folgende Web Bean besitzt den Binding-Typ @CreditCard
und implementiert den API-Typ PaymentProcessor
. Es könnte daher am Beispiel-Einspeisungspunkt eingespeist werden:
@CreditCard
public class CreditCardPaymentProcessor
implements PaymentProcessor { ... }
Falls ein Web Bean nicht explizit einen Satz von Binding-Typen festlegt, so besitzt es genau einen Binding-Typ: den standardmäßigen Binding-Typ @Current
.
Web Beans definiert einen fortgeschrittenen aber intuitiven Auflösungsalgorithmus, der dem Container dabei hilft zu entscheiden was geschehen soll, wenn mehr als ein Web Bean einen bestimmten Vertrag erfüllt. Wir gehen in Kapitel 4, Dependency-Einspeisung näher darauf ein.
Deployment-Typen gestatten die Klassifizierung unserer Web Beans mittels Deployment Szenario. Ein Deployment-Typ ist eine Annotation, die ein bestimmtes Deployment-Szenario repräsentiert, etwa @Mock
, @Staging
oder @AustralianTaxLaw
. Wir setzen die Annotation bei Web Beans ein, die in diesem Szenario deployt werden sollten. Ein Deployment-Typ gestattet mit nur einer einzelnen Konfigurationszeile einem ganzen Satz von Web Beans unter Vorbehalt in diesem Szenario deployt zu werden.
Viele Web Beans verwenden nur den standardmäßigen Deployment-Typ @Production
, in welchem Fall kein Deployment-Typ explizit festgelegt werden muss. Alle drei Web Beans in unserem Beispiel besitzen den Deployment-Typ @Production
.
In einer Testumgebung können wir das SentenceTranslator
Web Bean durch ein "mock object" ersetzen:
@Mock
public class MockSentenceTranslator implements Translator {
public String translate(String sentence) {
return "Lorem ipsum dolor sit amet";
}
}
Wir würden den Deployment-Typ @Mock
in unserer Testumgebung aktivieren, um anzuzeigen, dass MockSentenceTranslator
und ein beliebiges anderes mit @Mock
annotiertes Web Bean verwendet werden sollen.
In Abschnitt 4.2, „Deployment Typen“ gehen wir näher auf dieses einzigartige und leistungsfähige Feature ein.
Der Geltungsbereich definiert den Lebenszyklus und die Sichtbarkeit von Instanzen des Web Beans. Das Web Beans Kontextmodell ist erweiterbar, um arbiträre Geltungsbereiche zu ermöglichen. Jedoch sind bestimmte wichtige Geltungsbereiche in die Spezifikation eingebaut und werden vom Web Bean bereitgestellt. Ein Geltungsbereich wird durch einen Annotationstyp repräsentiert.
Web-Anwendungen können zum Beispiel Session-begrenzte Web Beans besitzen:
@SessionScoped
public class ShoppingCart { ... }
Eine Instanz eines sessionbegrenzten Web Beans wird an eine Benutzer-Session gebunden und wird von allen im Kontext dieser Session ausführenden Anfragen geteilt.
Standardmäßig gehören Web Beans zu einem bestimmten Geltungsbereich namens abhängiger Pseudo-Geltungsbereich (sog. "dependent pseudo-scope"). Web Beans mit diesem Geltungsbereich sind reine abhängige Objekte von demjenigen Objekt, in das sie eingespeist werden und ihr Lebenszyklus ist an den Lebenszyklus eben dieses Objekts gebunden.
In Kapitel 5, Geltungsbereiche und Kontexte gehen wir näher auf Geltungsbereiche ein.
Ein Web Bean kann einen Namen besitzen, wodurch es möglich ist, dieses in Unified EL Ausdrücken einzusetzen. Das Festlegen eines Namens für ein Web Bean ist ganz einfach:
@SessionScoped @Named("cart")
public class ShoppingCart { ... }
Jetzt können wir das Web Bean einfach in einer beliebigen JSF- oder JSP-Seite verwenden:
<h:dataTable value="#{cart.lineItems}" var="item"> .... </h:dataTable >
Es ist sogar noch einfacher den Name vom Web Bean Manager standardisieren zu lassen:
@SessionScoped @Named
public class ShoppingCart { ... }
In diesem Fall wird der Name standardmäßig zu shoppingCart
dem nicht vollständigen Klassennamen, wobei der erste Buchstabe klein geschrieben wird.
Web Beans unterstützt die von EJB 3 definierte Interzeptor-Funktionalität nicht nur für EJB-Beans, sondern auch für einfache Java-Klassen. Desweiteren bietet Web Beans eine neue Herangehensweise bei der Bindung von Interzeptoren an EJB-Beans und andere Web-Beans.
Es bleibt weiterhin möglich, die Interzeptorklasse mittels Verwendung der @Interceptors
-Annotation direkt festzulegen:
@SessionScoped
@Interceptors(TransactionInterceptor.class)
public class ShoppingCart { ... }
Es ist aber eleganter und generell besser das Interzeptor-Binding durch einen Interzeptor-Binding-Typ umzuleiten:
@SessionScoped @Transactional
public class ShoppingCart { ... }
Wir gehen in Kapitel 7, Interzeptoren and Kapitel 8, Dekoratoren näher auf Web Beans Interzeptoren und Dekoratoren ein.
Wir haben bereits gesehen, dass JavaBeans, EJBs und einige andere Java-Klassen Web Beans sein können. Aber um was für Objekte genau handelt es sich bei Web Beans?
Die Web Beans Spezifikation besagt, dass eine konkrete Java-Klasse ein einfaches Web Bean ist, wenn:
Es es sich nicht um eine EE Container-gemanagte Komponente wie ein EJB, ein Servlet oder eine JPA-Entity handelt,
es sich nicht um eine nicht-statische statische innere Klasse handelt,
es sich nicht um einen parametisierten Typ handelt und
ein Konstruktor ohne Parameter oder ein mit @Initializer
annotierter Konstruktor vorhanden ist.
Daher handelt es sich bei fast jedem JavaBean um ein einfaches Web Bean.
Jedes direkt oder indirekt durch ein einfaches Web Bean implementierte Interface ist ein API-Typ des einfachen Web Beans. Die Klasse und deren Superklassen sind ebenfalls API-Typen.
Die Spezifikation besagt, dass alle EJB 3-style Session und Singleton Beans Enterprise Web Beans sind. Message-driven Beans sind keine Web Beans da sie nicht zur Einspeisung in andere Objekte vorgesehen sind aber sie können den größten Teil der Funktionalität von Web Beans nutzen, darunter auch "Dependency"-Einspeisung und Interzeptoren.
Jedes lokale Interface eines Enterprise Web Beans und jedes seiner Super-Interfaces, das keinen Platzhaltertyp-Parameter oder eine Typenvariable besitzt, ist ein API-Typ des Enterprise Web Beans. Falls das EJB-Bean eine lokale Ansicht der Bean-Klasse besitzt, so handelt es sich auch bei der Bean-Klasse und jede von deren Super-Klassen um einen API-Typ.
Stateful Session Beans sollten eine Entfernungsmethode ("remove method") ohne Parameter oder eine Entfernungsmethode mit der Annotation @Destructor
deklarieren. Der Web Bean Manager ruft diese Methode auf, um die Instanz des stateful Session Beans am Ende von deren Lebenszyklus zu löschen. Diese Methode nennt sich Destructor-Methode des Enterprise Web Beans.
@Stateful @SessionScoped
public class ShoppingCart {
...
@Remove
public void destroy() {}
}
Sollten wir also ein Enterprise Web Bean statt eines einfachen Web Beans verwenden? Nun, wenn wir ausgefeilte, durch EJB bereitgestellte Enterprise-Dienste benötigen, wie etwa:
Transaktionsmanagement und Sicherheit auf Methodenebene,
Nebenläufigkeits-Management,
Passivation für stateful Session Beans und Instance-Pooling für stateless Session Beans auf Instanzebene
Remote und Web-Service Aufruf und
Timer und asynchrone Methoden,
so sollten wir ein Enterprise Web Bean verwenden. Wenn wir nichts von alledem brauchen, so reicht ein einfaches Web Bean vollkommen aus.
Viele Web Beans (einschließlich session- oder anwendungsbegrenzte Web Beans) sind für nebenläufigen Zugriff verfügbar. Daher ist das durch EJB 3.1 bereitgestellte Nebenläufigkeits-Management besonders nützlich. Die meisten session- oder anwendungsbegrenzten Web Beans sollten EJBs sein.
Web Beans, die Verweise auf schwergewichtige Ressourcen oder eine Menge internen Status besitzen, haben Vorteile durch den fortgeschrittenen, Container-gemanagten, durch das EJB @Stateless
/@Stateful
/@Singleton
-Modell definierten Lebenszyklus und dessen Support von Passivation und Instanz-Pooling.
Schließlich ist es offenkundig, wenn Transaktions-Management auf Methodenebene, Sicherheit auf Methodenebene, Timer, Remote-Methoden oder asynchrone Methoden benötigt werden.
Es ist in der Regel leicht, mit einem einfachen Web Bean zu beginnen und es dann zu einem EJB zu machen, indem man eine Annotation: @Stateless
, @Stateful
oder @Singleton
hinzufügt.
Eine Producer-Methode ist eine Methode, die vom Web Bean Manager aufgerufen wird, um eine Instanz des Web Beans zu erhalten, wenn im aktuellen Kontext keine existiert. Eine Producer-Methodübernehmen, statt die Instantiierung dem Web Bean Manager zu überlassen. Zum Beispiel:
@ApplicationScoped
public class Generator {
private Random random = new Random( System.currentTimeMillis() );
@Produces @Random int next() {
return random.nextInt(100);
}
}
Einspeisung des Ergebnisses einer Producer-Methode erfolgt wie bei einem regulären Web Bean.
@Random int randomNumber
Der Methodenwiedergabetyp ("Method Return Type") und alle Interfaces, die er direkt oder indirekt erweitert/implementiert sind API-Typen der Producer-Methode. Handelt es sich beim Wiedergabetyp um eine Klasse, so sind alle Superklassen ebenfalls API-Typen.
Einige Producer-Methoden geben Objekte wieder, die explizite Löschung erfordern:
@Produces @RequestScoped Connection connect(User user) {
return createConnection( user.getId(), user.getPassword() );
}
Diese Producer-Methoden können übereinstimmende Disposal Methods (Entsorgungsmethoden) definieren:
void close(@Disposes Connection connection) {
connection.close();
}
Diese Entsorgungsmethode wird am Ende der Anfrage automatisch vom Web Bean Manager aufgerufen.
In Kapitel 6, Producer-Methoden erfahren Sie mehr über Producer-Methoden.
Auch eine JMS-Warteschlange oder ein Topic können Web Beans sein. Web Beans nimmt dem Entwickler die Arbeit des Management der Lebenszyklen aller verschiedener JMS-Objekte ab, die zum Senden von Nachrichten an Warteschlangen und Topics erforderlich sind. Wir gehen in Abschnitt 13.4, „JMS Endpunkte“ auf JMS-Endpunkte ein.