scopescontexts.xml
18.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [ ]>
<chapter id="scopescontexts">
<title>Scopes and contexts</title>
<para>
So far, we've seen a few examples of <emphasis>scope type annotations</emphasis>. The scope of a bean determines
the lifecycle of instances of the bean. The scope also determines which clients refer to which instances of the
bean. According to the CDI specification, a scope determines:
</para>
<blockquote>
<itemizedlist>
<listitem>
<para>When a new instance of any bean with that scope is created</para>
</listitem>
<listitem>
<para>When an existing instance of any bean with that scope is destroyed</para>
</listitem>
<listitem>
<para>Which injected references refer to any instance of a bean with that scope</para>
</listitem>
</itemizedlist>
</blockquote>
<para>
For example, if we have a session-scoped bean, <literal>CurrentUser</literal>, all beans that are called in the
context of the same <literal>HttpSession</literal> will see the same instance of <literal>CurrentUser</literal>.
This instance will be automatically created the first time a <literal>CurrentUser</literal> is needed in that
session, and automatically destroyed when the session ends.
</para>
<tip>
<para>
JPA entities aren't a great fit for this model. Entities have their whole own lifecycle and identity model
which just doesn't map naturally to the model used in CDI. Therefore, we recommend against treating entities
as CDI beans. You're certainly going to run into problems if you try to give an entity a scope other than
the default scope <literal>@Dependent</literal>. The client proxy will get in the way if you try to pass
an injected instance to the JPA <literal>EntityManager</literal>.
</para>
</tip>
<section>
<title>Scope types</title>
<para>
CDI features an <emphasis>extensible context model</emphasis>. It's possible to define new scopes by creating
a new scope type annotation:
</para>
<programlisting role="JAVA"><![CDATA[@ScopeType
@Retention(RUNTIME)
@Target({TYPE, METHOD})
public @interface ClusterScoped {}]]></programlisting>
<para>
Of course, that's the easy part of the job. For this scope type to be useful, we will also need to define a
<literal>Context</literal> object that implements the scope! Implementing a <literal>Context</literal> is
usually a very technical task, intended for framework development only. You can expect an implementation of the
business scope, for instance, in a future version of Seam.
</para>
<para>
We can apply a scope type annotation to a bean implementation class to specify the scope of the bean:
</para>
<programlisting role="JAVA"><![CDATA[@ClusterScoped
public class SecondLevelCache { ... }]]></programlisting>
<para>Usually, you'll use one of CDI's built-in scopes.</para>
</section>
<section>
<title>Built-in scopes</title>
<para>CDI defines four built-in scopes:</para>
<itemizedlist>
<listitem>
<para><literal>@RequestScoped</literal></para>
</listitem>
<listitem>
<para><literal>@SessionScoped</literal></para>
</listitem>
<listitem>
<para><literal>@ApplicationScoped</literal></para>
</listitem>
<listitem>
<para><literal>@ConversationScoped</literal></para>
</listitem>
</itemizedlist>
<para>For a web application that uses CDI:</para>
<itemizedlist>
<listitem>
<para>
any servlet request has access to active request, session and application scopes, and, additionally
</para>
</listitem>
<listitem>
<para>any JSF request has access to an active conversation scope.</para>
</listitem>
</itemizedlist>
<note>
<para>A CDI extension can implement support for the conversation scope in other web frameworks.</para>
</note>
<para>The request and application scopes are also active:</para>
<itemizedlist>
<listitem>
<para>during invocations of EJB remote methods,</para>
</listitem>
<listitem>
<para>during invocations of EJB asynchronous methods,</para>
</listitem>
<listitem>
<para>during EJB timeouts,</para>
</listitem>
<listitem>
<para>during message delivery to a message-driven bean,</para>
</listitem>
<listitem>
<para>during message delivery to a <literal>MessageListener</literal>, and</para>
</listitem>
<listitem>
<para>during web service invocations.</para>
</listitem>
</itemizedlist>
<para>
If the application tries to invoke a bean with a scope that does not have an active context, a
<literal>ContextNotActiveException</literal> is thrown by the container at runtime.
</para>
<para>
Managed beans with scope <literal>@SessionScoped</literal> or <literal>@ConversationScoped</literal> must be
serializable, since the container passivates the HTTP session from time to time.
</para>
<para>
Three of the four built-in scopes should be extremely familiar to every Java EE developer, so let's not waste
time discussing them here. One of the scopes, however, is new.
</para>
</section>
<section>
<title>The conversation scope</title>
<para>
The conversation scope is a bit like the traditional session scope in that it holds state associated with a
user of the system, and spans multiple requests to the server. However, unlike the session scope, the
conversation scope:
</para>
<itemizedlist>
<listitem>
<para>is demarcated explicitly by the application, and</para>
</listitem>
<listitem>
<para>
holds state associated with a particular web browser tab in a JSF application (browsers tend to share
domain cookies, and hence the session cookie, between tabs, so this is not the case for the session scope).
</para>
</listitem>
</itemizedlist>
<para>
A conversation represents a task—a unit of work from the point of view of the user. The conversation context
holds state associated with what the user is currently working on. If the user is doing multiple things at the
same time, there are multiple conversations.
</para>
<para>
The conversation context is active during any JSF request. Most conversations are destroyed at the end of the
request. If a conversation should hold state across multiple requests, it must be explicitly promoted to a
<emphasis>long-running conversation</emphasis>.
</para>
<section>
<title>Conversation demarcation</title>
<para>
CDI provides a built-in bean for controlling the lifecycle of conversations in a JSF application. This bean
may be obtained by injection:
</para>
<programlisting role="JAVA">@Inject Conversation conversation;</programlisting>
<para>
To promote the conversation associated with the current request to a long-running conversation, call the
<literal>begin()</literal> method from application code. To schedule the current long-running conversation
context for destruction at the end of the current request, call <literal>end()</literal>.
</para>
<para>
In the following example, a conversation-scoped bean controls the conversation with which it is associated:
</para>
<programlisting role="JAVA"><![CDATA[@ConversationScoped @Stateful
public class OrderBuilder {
private Order order;
private @Inject 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() {}
}]]></programlisting>
<para>
This bean is able to control its own lifecycle through use of the <literal>Conversation</literal> API. But
some other beans have a lifecycle which depends completely upon another object.
</para>
</section>
<section>
<title>Conversation propagation</title>
<para>
The conversation context automatically propagates with any JSF faces request (JSF form submission) or redirect.
It does not automatically propagate with non-faces requests, for example, navigation via a link.
</para>
<para>
We can force the conversation to propagate with a non-faces request by including the unique identifier of
the conversation as a request parameter. The CDI specification reserves the request parameter named
<literal>cid</literal> for this use. The unique identifier of the conversation may be obtained from the
<literal>Conversation</literal> object, which has the EL bean name <literal>conversation</literal>.
</para>
<para>
Therefore, the following link propagates the conversation:
</para>
<programlisting role="XML"><![CDATA[<a href="/addProduct.jsp?cid=#{conversation.id}">Add Product</a>]]></programlisting>
<para>
It's probably better to use one of the link components in JSF 2:
</para>
<programlisting role="XML"><![CDATA[<h:link outcome="/addProduct.xhtml value="Add Product">
<f:param name="cid" value="#{conversation.id}"/>
</h:link>]]></programlisting>
<tip>
<para>
The conversation context propagates across redirects, making it very easy to implement the common
POST-then-redirect pattern, without resort to fragile constructs such as a "flash" object. The container
automatically adds the conversation id to the redirect URL as a request parameter.
</para>
</tip>
</section>
<section>
<title>Conversation timeout</title>
<para>
The container is permitted to destroy a conversation and all state held in its context at any time in order
to conserve resources. A CDI implementation will normally do this on the basis of some kind of
timeout—though this is not required by the specification. The timeout is the period of inactivity before
the conversation is destroyed (as opposed to the amount of time the conversation is active).
</para>
<para>
The <literal>Conversation</literal> object provides a method to set the timeout. This is a hint to the
container, which is free to ignore the setting.
</para>
<programlisting role="JAVA">conversation.setTimeout(timeoutInMillis);</programlisting>
</section>
</section>
<section>
<title>The singleton pseudo-scope</title>
<para>
In addition to the four built-in scopes, CDI also supports two <emphasis>pseudo-scopes</emphasis>. The first
is the <emphasis>singleton pseudo-scope</emphasis>, which we specify using the annotation <literal>@Singleton</literal>.
</para>
<note>
<para>
Unlike the other scopes, which belong to the package <literal>javax.enterprise.context</literal>, the
<literal>@Singleton</literal> annotation is defined in the package <literal>javax.inject</literal>.
</para>
</note>
<para>
You can guess what "singleton" means here. It means a bean that is instantiated once. Unfortunately, there's
a little problem with this pseudo-scope. Beans with scope <literal>@Singleton</literal> don't have a proxy
object. Clients hold a direct reference to the singleton instance. So we need to consider the case of a client
that can be serialized, for example, any bean with scope <literal>@SessionScoped</literal> or
<literal>@ConversationScoped</literal>, any dependent object of a bean with scope <literal>@SessionScoped</literal>
or <literal>@ConversationScoped</literal>, or any stateful session bean.
</para>
<para>
Now, if the singleton instance is a simple, immutable, serializable object like a string, a number or a date,
we probably don't mind too much if it gets duplicated via serialization. However, that makes it no stop being a
true singleton, and we may as well have just declared it with the default scope.
</para>
<para>There are several ways to ensure that the singleton bean remains a singleton when its client gets serialized:</para>
<itemizedlist>
<listitem>
<para>
have the singleton bean implement <literal>writeResolve()</literal> and <literal>readReplace()</literal>
(as defined by the Java serialization specification),
</para>
</listitem>
<listitem>
<para>
make sure the client keeps only a transient reference to the singleton bean, or
</para>
</listitem>
<listitem>
<para>
give the client a reference of type <literal>Instance<X></literal> where <literal>X</literal> is the
bean type of the singleton bean.
</para>
</listitem>
</itemizedlist>
<para>A fourth, better solution is to instead use <literal>@ApplicationScoped</literal>, allowing the container to
proxy the bean, and take care of serialization problems automatically.</para>
</section>
<section>
<title>The dependent pseudo-scope</title>
<para>
Finally, CDI features the so-called <emphasis>dependent pseudo-scope</emphasis>.
This is the default scope for a bean which does not explicitly declare a scope type.
</para>
<para>
For example, this bean has the scope type <literal>@Dependent</literal>:
</para>
<programlisting role="JAVA"><![CDATA[public class Calculator { ... }]]></programlisting>
<para>
An instance of a dependent bean is never shared between different clients or different injection points. It is
strictly a <emphasis>dependent object</emphasis> of some other object. It is instantiated when the object it
belongs to is created, and destroyed when the object it belongs to is destroyed.
</para>
<para>
If a Unified EL expression refers to a dependent bean by EL name, an instance of the bean is instantiated
every time the expression is evaluated. The instance is not reused during any other expression evaluation.
</para>
<tip>
<para>
If you need to access a bean directly by EL name in a JSF page, you probably need to give it a scope other
than <literal>@Dependent</literal>. Otherwise, any value that gets set to the bean by a JSF input will be
lost immediately. That's why CDI features the <literal>@Model</literal> stereotype; it lets you give a bean
a name, and set its scope to <literal>@RequestScoped</literal> in one stroke. If you need to access a bean
that really <emphasis>has</emphasis> to have the scope <literal>@Dependent</literal> from a JSF page,
inject it into a different bean, and expose it to EL via a getter method.
</para>
</tip>
<para>
Beans with scope <literal>@Dependent</literal> don't need a proxy object. The client holds a direct reference
to its instance.
</para>
<para>
CDI makes it easy to obtain a dependent instance of a bean, even if the bean is already declared as a bean with
some other scope type.
</para>
</section>
<section>
<title>The <literal>@New</literal> qualifier</title>
<para>
The built-in qualifier <literal>@New</literal> allows us to obtain a dependent object of a specified class.
</para>
<programlisting role="JAVA"><![CDATA[@Inject @New Calculator calculator;]]></programlisting>
<para>The class must be a valid managed bean or session bean, but need not be an enabled bean.</para>
<para>
This works even if <literal>Calculator</literal> is <emphasis>already</emphasis> declared with a different
scope type, for example:
</para>
<programlisting role="JAVA"><![CDATA[@ConversationScoped
public class Calculator { ... }]]></programlisting>
<para>
So the following injected attributes each get a different instance of <literal>Calculator</literal>:
</para>
<programlisting role="JAVA"><![CDATA[public class PaymentCalc {
@Inject Calculator calculator;
@Inject @New Calculator newCalculator;
}]]></programlisting>
<para>
The <literal>calculator</literal> field has a conversation-scoped instance of <literal>Calculator</literal>
injected. The <literal>newCalculator</literal> field has a new instance of <literal>Calculator</literal>
injected, with a lifecycle that is bound to the owning <literal>PaymentCalc</literal>.
</para>
<para>
This feature is particularly useful with producer methods, as we'll see in the next chapter.
</para>
</section>
<!--
vim:et:ts=3:sw=3:tw=120
-->
</chapter>