SeamFramework.orgCommunity Documentation
Bis jetzt haben wir ein paar Beispiele von Geltungsbereichtyp-Annotationen gesehen. Der Geltungsbereich eines Web Beans bestimmt den Lebenszyklus der Instanzen des Web Beans. Der Geltungsbereich bestimmt auch, welche Clients sich auf welche Instanzen des Web Beans beziehen. Gemäß der Web Beans Spezifikation bestimmt ein Geltungsbereich:
Wann eine neue Instanz eines beliebigen Web Beans mit diesem Geltungsbereich erstellt wird
Wenn eine bestehende Instanz eines beliebigen Web Beans mit diesem Geltungsbereich gelöscht wird
Welche eingespeisten Referenzen auf eine beliebige Instanz eines Web Beans mit diesem Geltungsbereich verweisen
Wenn wir etwa ein session-begrenztes Web Bean CurrentUser
haben, so sehen alle Web Beans, die im Kontext derselben HttpSession
aufgerufen werden, dieselbe Instanz von CurrentUser
. Diese Instanz wird automatisch erstellt, wenn CurrentUser
erstmals in dieser Session benötigt wird und automatisch gelöscht, wenn die Session endet.
Web Beans besitzen ein erweiterbares Kontextmodell. Es ist möglich, neue Geltungsbereiche zu definieren, indem man eine neue Annotation für einen Geltungsbereich-Typ erstellt:
@Retention(RUNTIME)
@Target({TYPE, METHOD})
@ScopeType
public @interface ClusterScoped {}
Natürlich ist dies der einfache Teil des Jobs. Damit dieser Typ von Geltungsbereich von Nutzen ist, müssen wir außerdem ein Context
-Objekt definieren, das den Geltungsbereich implementiert! Die Implementierung eines Context
ist in der Regel ein sehr technisches Unterfangen, das nur für Framework-Entwicklung vorgesehen ist.
Wir können eine Annotation eines Geltungsbereich-Typs an einer Web Bean Implementierungsklasse anwenden, um den Geltungsbereich des Web Beans festzulegen:
@ClusterScoped
public class SecondLevelCache { ... }
In der Regel verwenden Sie einen der eingebauten Geltungsbereiche der Web Beans.
Web Beans definiert vier eingebaute Geltungsbereiche:
@RequestScoped
@SessionScoped
@ApplicationScoped
@ConversationScoped
Für eine Web Beans verwendende Webanwendung:
Jede Servlet-Anfrage hat Zugriff auf die aktuelle Anfrage, Session und Geltungsbereiche der Anwendung und zusätzlich
hat jede JSF-Anfrage Zugriff auf einen aktiven Konversations-Geltungsbereich.
Die Geltungsbereiche von Anfrage und Applikation sind ebenfalls aktiv:
während Aufrufen von EJB Remote-Methoden,
während EJB-Timeouts,
während Message Delivery an ein message-betriebenes Bean und
während Aufrufen von Webdiensten.
Versucht die Applikation ein Web Bean aufzurufen, das keinen aktiven Kontext besitzt, so wird zur Runtime eine ContextNotActiveException
vom Web Bean Manager gemeldet.
Drei der vier eingebauten Geltungsbereiche solltem jedem Java EE Entwickler sehr vertraut sein, daher wollen wir hier nicht weiter auf diese eingehen. Einer der Geltungsbereiche jedoch ist neu.
Der Web Beans Geltungsbereich der Konversation ähnelt dem herkömmlichen Geltungsbereich der Session dahingehend, dass er den mit einem Benutzer des Systems assoziierten Status verwahrt und mehrere Anfragen zum Server umfasst. Anders als für den Geltungsbereich der Session gilt für den Geltungsbereich der Konversation jedoch:
ist explizit durch die Applikation demarkiert und
verwahrt den mit einem bestimmten Webbrowser assoziierten Status in einer JSF-Applikation.
Eine Konversation repräsentiert aus Perspektive des Benutzers eine Aufgabe, eine Arbeitseinheit. Der Konversationskontext enthält den Status dessen, woran der Benutzer gerade arbeitet. Arbeitet der Benutzer gleichzeitig an mehreren Dingen, so existieren mehrere Konversationen.
Der Konversation skontext ist während jeder JSF-Anfrage aktiv. Jedoch werden die meisten Konversationen am Ende der Anfrage gelöscht. Soll eine Konversation den Status über mehrere Anfragen hinweg verwahren, so muss sie explizit zu einer lange laufenden Konversation fortgepflanzt werden.
Web Beans liefert ein eingebautes Web Bean für die Steuerung des Lebenszyklus von Konversationen in einer JSF-Applikation. Dieses Web Bean kann durch Einspeisung erhalten werden:
@Current Conversation Konversation;
Um die mit der aktuellen Anfrage assoziierte Konversation an eine lange laufende Konversation fortzupflanzen, rufen Sie die begin()
-Methode vom Applikationscode auf. Um den aktuellen, lange laufenden Konversationskontext für die Löschung am Ende der aktuellen Anfrage zu terminieren, rufen Sie end()
auf.
IIm folgenden Beispiel steuert ein konversationsbegrenztes Web Bean die Konversation, mit der es assoziiert ist:
@ConversationScoped @Stateful
public class OrderBuilder {
private Order order;
private @Current Conversation conversation;
private @PersistenceContext(type=EXTENDED) EntityManager em;
@Produces public Order getOrder() {
return order;
}
public Order createOrder() {
order = new Order();
conversation.begin();
return order;
}
public void addLineItem(Product product, int quantity) {
order.add( new LineItem(product, quantity) );
}
public void saveOrder(Order order) {
em.persist(order);
conversation.end();
}
@Remove
public void destroy() {}
}
Dieses Web Bean ist in der Lage, seinen eigenen Lebenszyklus durch Verwendung der Conversation
-API zu steuern. Aber einige andere Web Beans besitzen einen Lebenszyklus, der komplett von einem anderen Objekt abhängt.
Der Konversationskontext wird automatisch mit allen JSF Faces Anfragen fortgepflanzt(JSF-Formulareinreichung). Nicht-Faces Anfragen werden nicht automatisch fortgepflanzt, zum Beispiel Navigation via einem Link.
Wir können die Konversation zwingen, mit einer nicht-Faces Anfrage fortzupflanzen, indem wir den eindeutigen Bezeichner der Konversation als einen Anfragenparameter mit einschließen. Die Web Beans Spezifikation reserviert den Anfragenparameter namens cid
für diesen Gebrauch. Den eindeutigen Bezeichner der Konversation erhält man vom Conversation
-Objekt, welches den Web Beans Namen conversation
besitzt.
Daher pflanzt das folgende Link die Konversation fort:
<a href="/addProduct.jsp?cid=#{conversation.id}" >Add Product</a >
Der Web Bean Manager muss auch Konversationen über ein Redirect fortpflanzen, selbst wenn die Konversation nicht als lange laufend gekennzeichnet ist. Dies macht die Implementierung des POST-then-redirect Musters sehr einfach, ohne dass man sich auf anfällige Konstrukte wie etwa ein "Flash"-Objekt stützen müsste. In tdiesem Fall fügt der Web Bean Manager automatisch einen Anfragenparameter hinzu, um die URL umzuleiten.
Dem Web Bean Manager ist gestattet, eine Konversation und alle Stati innerhalb seines Kontexts zu jedem Zeitpunkt zu löschen, um Ressourcen zu schonen. Eine Implementierung des Web Bean Managers wird dies in der Regel auf der Basis einer Art von Timeout tun, obwohl dies nicht durch die Web Beans Spezifikation gefordert wird. Beim Timeout handelt es sich um den Zeitraum von Inaktivität, ehe die Konversation gelöscht wird.
Das Conversation
-Objekt liefert eine Methode, mit der der Timeout eingestellt werden kann. Dies ist ein Tipp an den Web Bean Manager, der die Einstellung ignorieren kann.
conversation.setTimeout(timeoutInMillis);
Neben den vier eingebauten Geltungsbereichen bieten Web Beans den sogenanntenabhängigen Pseudo-Geltungsbereich. Dies ist der standardmäßige Geltungsbereich für ein Web Bean, das nicht expliziet einen Typ von Geltungsbereich deklariert.
Zum Beispiel besitzt dieses Web Bean den Geltungsbereich-Typ @Dependent
:
public class Calculator { ... }
Wenn der Einspeisungspunkt eines Web Bean zu einem abhängigen Web Bean hin aufgelöst wird, so wird jedes Mal, wenn das erste Web Bean instantiiert wird, eine neue Instanz des abhängigen Web Beans erstellt. Instanzen abhängiger Web Beans werden nie von unterschiedlichen Web Beans oder unterschiedlichen Einspeisungspunkten geteilt. Sie sind abhängige Objekte einer anderen Web Bean Instanz.
Abhängige Web Bean Instanzen werden gelöscht, wenn die Instanz von der sie abhängen gelöscht wird.
Web Beans machen es einfach, eine unabhängige Instanz einer Java-Klasse oder eines EJB-Beans zu erhalten, selbst wenn die Klasse oder das EJB-Bean bereits als ein Web Bean mit einem anderen Typ von Geltungsbereich deklariert sind.
Die eingebaute @New
Binding-Annotation gestattet die implizite Definition eines abhängigen Web Beans an einem Einspeisungspunkt. Nehmen wir an, wir deklarieren das folgende eingespeiste Feld:
@New Calculator calculator;
Dann wird ein Web Bean mit Geltungsbereich @Dependent
, Binding-Typ @New
, API-Typ Calculator
, Implementierungsklasse Calculator
und Deployment-Typ @Standard
impliziert definiert.
Dies ist wahr, selbst wenn Calculator
bereits mit einem anderen Typ von Geltungsbereich definiert ist, zum Beispiel:
@ConversationScoped
public class Calculator { ... }
Die folgenden eingespeisten Attribute erhalten also jeweils eine unterschiedliche Instanz von Calculator
:
public class PaymentCalc {
@Current Calculator calculator;
@New Calculator newCalculator;
}
In das calculator
-Feld wird eine konversationsbegrenzte Instanz von Calculator
eingespeist. In das newCalculator
-Feld wird eine neue Instanz von Calculator
eingespeist, mit einem Lebenszyklus, der an den besitzenden PaymentCalc
gebunden ist.
Dieses Feature ist insbesondere im Zusammenhang mit Producer-Methoden von Nutzen, wie wir im folgenden Kapitel noch sehen werden.