You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
686 lines
34 KiB
686 lines
34 KiB
<?xml version="1.0" encoding="UTF-8"?> |
|
<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" |
|
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"> |
|
<section id="beans-factory-scopes"> |
|
<title>Bean scopes</title> |
|
|
|
<para>When you create a bean definition, you create a |
|
<emphasis>recipe</emphasis> for creating actual instances of the class |
|
defined by that bean definition. The idea that a bean definition is a recipe |
|
is important, because it means that, as with a class, you can create many |
|
object instances from a single recipe.</para> |
|
|
|
<para>You can control not only the various dependencies and configuration |
|
values that are to be plugged into an object that is created from a |
|
particular bean definition, but also the <firstterm>scope</firstterm> of the |
|
objects created from a particular bean definition. This approach is powerful |
|
and flexible in that you can <emphasis>choose</emphasis> the scope of the |
|
objects you create through configuration instead of having to bake in the |
|
scope of an object at the Java class level. Beans can be defined to be |
|
deployed in one of a number of scopes: out of the box, the Spring Framework |
|
supports five scopes, three of which are available only if you use a |
|
web-aware <interfacename>ApplicationContext</interfacename>.</para> |
|
|
|
<para>The following scopes are supported out of the box. You can also create |
|
<link linkend="beans-factory-scopes-custom">a custom scope.</link></para> |
|
|
|
<table id="beans-factory-scopes-tbl"> |
|
<title>Bean scopes</title> |
|
|
|
<tgroup cols="2"> |
|
<thead> |
|
<row> |
|
<entry align="center">Scope</entry> |
|
|
|
<entry align="center">Description</entry> |
|
</row> |
|
</thead> |
|
|
|
<tbody> |
|
<row> |
|
<entry><para> <link linkend="beans-factory-scopes-singleton" |
|
>singleton</link> </para></entry> |
|
|
|
<entry><para>(Default) Scopes a single bean definition to a single |
|
object instance per Spring IoC container.</para></entry> |
|
</row> |
|
|
|
<row> |
|
<entry><para> <link linkend="beans-factory-scopes-prototype" |
|
>prototype</link> </para></entry> |
|
|
|
<entry><para>Scopes a single bean definition to any number of object |
|
instances.</para></entry> |
|
</row> |
|
|
|
<row> |
|
<entry><para> <link linkend="beans-factory-scopes-request" |
|
>request</link> </para></entry> |
|
|
|
<entry><para>Scopes a single bean definition to the lifecycle of a |
|
single HTTP request; that is, each HTTP request has its own instance |
|
of a bean created off the back of a single bean definition. Only |
|
valid in the context of a web-aware Spring |
|
<interfacename>ApplicationContext</interfacename>.</para></entry> |
|
</row> |
|
|
|
<row> |
|
<entry><para> <link linkend="beans-factory-scopes-session" |
|
>session</link> </para></entry> |
|
|
|
<entry><para>Scopes a single bean definition to the lifecycle of an |
|
HTTP <interfacename>Session</interfacename>. Only valid in the |
|
context of a web-aware Spring |
|
<interfacename>ApplicationContext</interfacename>.</para></entry> |
|
</row> |
|
|
|
<row> |
|
<entry><para> <link linkend="beans-factory-scopes-global-session" |
|
>global session</link> </para></entry> |
|
|
|
<entry><para>Scopes a single bean definition to the lifecycle of a |
|
global HTTP <interfacename>Session</interfacename>. Typically only |
|
valid when used in a portlet context. Only valid in the context of a |
|
web-aware Spring |
|
<interfacename>ApplicationContext</interfacename>.</para></entry> |
|
</row> |
|
</tbody> |
|
</tgroup> |
|
</table> |
|
|
|
<note> |
|
<title>Thread-scoped beans</title> |
|
|
|
<para>As of Spring 3.0, a <emphasis>thread scope</emphasis> is available, |
|
but is not registered by default. For more information, see the |
|
documentation for <ulink |
|
url="http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/context/support/SimpleThreadScope.html" |
|
>SimpleThreadScope</ulink>. For instructions on how to register this or |
|
any other custom scope, see <xref |
|
linkend="beans-factory-scopes-custom-using"/>.</para> |
|
</note> |
|
|
|
<section id="beans-factory-scopes-singleton"> |
|
<title>The singleton scope</title> |
|
|
|
<para>Only one <emphasis>shared</emphasis> instance of a singleton bean is |
|
managed, and all requests for beans with an id or ids matching that bean |
|
definition result in that one specific bean instance being returned by the |
|
Spring container.</para> |
|
|
|
<para>To put it another way, when you define a bean definition and it is |
|
scoped as a singleton, the Spring IoC container creates <emphasis>exactly |
|
one</emphasis> instance of the object defined by that bean definition. |
|
This single instance is stored in a cache of such singleton beans, and |
|
<emphasis>all subsequent requests and references</emphasis> for that named |
|
bean return the cached object.</para> |
|
|
|
<para><mediaobject> |
|
<imageobject role="fo"> |
|
<imagedata align="center" fileref="images/singleton.png" format="PNG"/> |
|
</imageobject> |
|
|
|
<imageobject role="html"> |
|
<imagedata align="center" fileref="images/singleton.png" format="PNG"/> |
|
</imageobject> |
|
</mediaobject></para> |
|
|
|
<para>Spring's concept of a singleton bean differs from the Singleton |
|
pattern as defined in the Gang of Four (GoF) patterns book. The GoF |
|
Singleton hard-codes the scope of an object such that one <emphasis>and |
|
only one</emphasis> instance of a particular class is created<emphasis> |
|
per <classname>ClassLoader</classname></emphasis>. The scope of the Spring |
|
singleton is best described as <emphasis>per container and per |
|
bean</emphasis>. This means that if you define one bean for a particular |
|
class in a single Spring container, then the Spring container creates one |
|
<emphasis>and only one</emphasis> instance of the class defined by that |
|
bean definition. <emphasis>The singleton scope is the default scope in |
|
Spring</emphasis>. To define a bean as a singleton in XML, you would |
|
write, for example:</para> |
|
|
|
<programlisting language="xml"><bean id="accountService" class="com.foo.DefaultAccountService"/> |
|
|
|
<lineannotation><!-- the following is equivalent, though redundant (singleton scope is the default) --></lineannotation> |
|
<bean id="accountService" class="com.foo.DefaultAccountService" scope="singleton"/></programlisting> |
|
</section> |
|
|
|
<section id="beans-factory-scopes-prototype"> |
|
<title>The prototype scope</title> |
|
|
|
<para>The non-singleton, prototype scope of bean deployment results in the |
|
<emphasis>creation of a new bean instance</emphasis> every time a request |
|
for that specific bean is made. That is, the bean is injected into another |
|
bean or you request it through a <literal>getBean()</literal> method call |
|
on the container. As a rule, use the prototype scope for all stateful |
|
beans and the singleton scope for stateless beans.</para> |
|
|
|
<para>The following diagram illustrates the Spring prototype scope. |
|
<emphasis>A data access object (DAO) is not typically configured as a |
|
prototype, because a typical DAO does not hold any conversational state; |
|
it was just easier for this author to reuse the core of the singleton |
|
diagram.</emphasis><!--First it says diagram illustrates scope, but then says it's not typical of a prototype scope. Why not use realistic one? --></para> |
|
|
|
<para><mediaobject> |
|
<imageobject role="fo"> |
|
<imagedata align="center" fileref="images/prototype.png" format="PNG"/> |
|
</imageobject> |
|
|
|
<imageobject role="html"> |
|
<imagedata align="center" fileref="images/prototype.png" format="PNG"/> |
|
</imageobject> |
|
</mediaobject></para> |
|
|
|
<para>The following example defines a bean as a prototype in XML:</para> |
|
|
|
<programlisting language="xml"><lineannotation><!-- using <literal>spring-beans-2.0.dtd</literal> --></lineannotation> |
|
<bean id="accountService" class="com.foo.DefaultAccountService" scope="prototype"/></programlisting> |
|
|
|
<para>In contrast to the other scopes, Spring does not manage the complete |
|
lifecycle of a prototype bean: the container instantiates, configures, and |
|
otherwise assembles a prototype object, and hands it to the client, with |
|
no further record of that prototype instance. Thus, although |
|
<emphasis>initialization</emphasis> lifecycle callback methods are called |
|
on all objects regardless of scope, in the case of prototypes, configured |
|
<emphasis>destruction</emphasis> lifecycle callbacks are |
|
<emphasis>not</emphasis> called. The client code must clean up |
|
prototype-scoped objects and release expensive resources that the |
|
prototype bean(s) are holding. To get the Spring container to release |
|
resources held by prototype-scoped beans, try using a custom <link |
|
linkend="beans-factory-extension-bpp">bean post-processor</link>, which |
|
holds a reference to beans that need to be cleaned up.</para> |
|
|
|
<para>In some respects, the Spring container's role in regard to a |
|
prototype-scoped bean is a replacement for the Java <literal>new</literal> |
|
operator. All lifecycle management past that point must be handled by the |
|
client. (For details on the lifecycle of a bean in the Spring container, |
|
see <xref linkend="beans-factory-lifecycle"/>.)</para> |
|
</section> |
|
|
|
<section id="beans-factory-scopes-sing-prot-interaction"> |
|
<title>Singleton beans with prototype-bean dependencies</title> |
|
|
|
<para>When you use singleton-scoped beans with dependencies on prototype |
|
beans, be aware that <emphasis>dependencies are resolved at instantiation |
|
time</emphasis>. Thus if you dependency-inject a prototype-scoped bean |
|
into a singleton-scoped bean, a new prototype bean is instantiated and |
|
then dependency-injected into the singleton bean. The prototype instance |
|
is the sole instance that is ever supplied to the singleton-scoped |
|
bean.</para> |
|
|
|
<para>However, suppose you want the singleton-scoped bean to acquire a new |
|
instance of the prototype-scoped bean repeatedly at runtime. You cannot |
|
dependency-inject a prototype-scoped bean into your singleton bean, |
|
because that injection occurs only <emphasis>once</emphasis>, when the |
|
Spring container is instantiating the singleton bean and resolving and |
|
injecting its dependencies. If you need a new instance of a prototype bean |
|
at runtime more than once, see <xref |
|
linkend="beans-factory-method-injection"/></para> |
|
</section> |
|
|
|
<section id="beans-factory-scopes-other"> |
|
<title>Request, session, and global session scopes</title> |
|
|
|
<para>The <literal>request</literal>, <literal>session</literal>, and |
|
<literal>global session</literal> scopes are <emphasis>only</emphasis> |
|
available if you use a web-aware Spring |
|
<interfacename>ApplicationContext</interfacename> implementation (such as |
|
<classname>XmlWebApplicationContext</classname>). If you use these scopes |
|
with regular Spring IoC containers such as the |
|
<classname>ClassPathXmlApplicationContext</classname>, you get an |
|
<classname>IllegalStateException</classname> complaining about an unknown |
|
bean scope.</para> |
|
|
|
<section id="beans-factory-scopes-other-web-configuration"> |
|
<title>Initial web configuration</title> |
|
|
|
<para>To support the scoping of beans at the <literal>request</literal>, |
|
<literal>session</literal>, and <literal>global session</literal> levels |
|
(web-scoped beans), some minor initial configuration is required before |
|
you define your beans. (This initial setup is <emphasis>not</emphasis> |
|
required for the standard scopes, singleton and prototype.)</para> |
|
|
|
<para>How you accomplish this initial setup depends on your particular |
|
Servlet environment..</para> |
|
|
|
<para>If you access scoped beans within Spring Web MVC, in effect, within |
|
a request that is processed by the Spring |
|
<classname>DispatcherServlet</classname>, or |
|
<classname>DispatcherPortlet</classname>, then no special setup is |
|
necessary: <classname>DispatcherServlet</classname> and |
|
<classname>DispatcherPortlet</classname> already expose all relevant |
|
state.</para> |
|
|
|
<para>If you use a Servlet 2.4+ web container, with requests processed |
|
outside of Spring's DispatcherServlet (for example, when using JSF or |
|
Struts), you need to add the following |
|
<interfacename>javax.servlet.ServletRequestListener</interfacename> to |
|
the declarations in your web applications <literal>web.xml</literal> |
|
file:</para> |
|
|
|
<programlisting language="xml"><web-app> |
|
... |
|
<listener> |
|
<listener-class> |
|
org.springframework.web.context.request.RequestContextListener |
|
</listener-class> |
|
</listener> |
|
... |
|
</web-app></programlisting> |
|
|
|
<para>If you use an older web container (Servlet 2.3), use the provided |
|
<interfacename>javax.servlet.Filter</interfacename> implementation. The |
|
following snippet of XML configuration must be included in the |
|
<literal>web.xml</literal> file of your web application if you want to |
|
access web-scoped beans in requests outside of Spring's |
|
DispatcherServlet on a Servlet 2.3 container. (The filter mapping |
|
depends on the surrounding web application configuration, so you must |
|
change it as appropriate.)</para> |
|
|
|
<programlisting language="xml"><web-app> |
|
.. |
|
<filter> |
|
<filter-name>requestContextFilter</filter-name> |
|
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-class> |
|
</filter> |
|
<filter-mapping> |
|
<filter-name>requestContextFilter</filter-name> |
|
<url-pattern>/*</url-pattern> |
|
</filter-mapping> |
|
... |
|
</web-app></programlisting> |
|
|
|
<para><classname>DispatcherServlet</classname>, |
|
<classname>RequestContextListener</classname> and |
|
<classname>RequestContextFilter</classname> all do exactly the same |
|
thing, namely bind the HTTP request object to the |
|
<classname>Thread</classname> that is servicing that request. This makes |
|
beans that are request- and session-scoped available further down the |
|
call chain.</para> |
|
</section> |
|
|
|
<section id="beans-factory-scopes-request"> |
|
<title>Request scope</title> |
|
|
|
<para>Consider the following bean definition:</para> |
|
|
|
<programlisting language="xml"><bean id="loginAction" class="com.foo.LoginAction" scope="request"/></programlisting> |
|
|
|
<para>The Spring container creates a new instance of the |
|
<classname>LoginAction</classname> bean by using the |
|
<literal>loginAction</literal> bean definition for each and every HTTP |
|
request. That is, the <literal>loginAction</literal> bean is scoped at |
|
the HTTP request level. You can change the internal state of the |
|
instance that is created as much as you want, because other instances |
|
created from the same <literal>loginAction</literal> bean definition |
|
will not see these changes in state; they are particular to an |
|
individual request. When the request completes processing, the bean that |
|
is scoped to the request is discarded.</para> |
|
</section> |
|
|
|
<section id="beans-factory-scopes-session"> |
|
<title>Session scope</title> |
|
|
|
<para>Consider the following bean definition:</para> |
|
|
|
<programlisting language="xml"><bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/></programlisting> |
|
|
|
<para>The Spring container creates a new instance of the |
|
<classname>UserPreferences</classname> bean by using the |
|
<literal>userPreferences</literal> bean definition for the lifetime of a |
|
single HTTP <interfacename>Session</interfacename>. In other words, the |
|
<literal>userPreferences</literal> bean is effectively scoped at the |
|
HTTP <interfacename>Session</interfacename> level. As with |
|
<literal>request-scoped</literal> beans, you can change the internal |
|
state of the instance that is created as much as you want, knowing that |
|
other HTTP <interfacename>Session</interfacename> instances that are |
|
also using instances created from the same |
|
<literal>userPreferences</literal> bean definition do not see these |
|
changes in state, because they are particular to an individual HTTP |
|
<interfacename>Session</interfacename>. When the HTTP |
|
<interfacename>Session</interfacename> is eventually discarded, the bean |
|
that is scoped to that particular HTTP |
|
<interfacename>Session</interfacename> is also discarded.</para> |
|
</section> |
|
|
|
<section id="beans-factory-scopes-global-session"> |
|
<title>Global session scope</title> |
|
|
|
<para>Consider the following bean definition:</para> |
|
|
|
<programlisting language="xml"><bean id="userPreferences" class="com.foo.UserPreferences" scope="globalSession"/></programlisting> |
|
|
|
<para>The <literal>global session</literal> scope is similar to the |
|
standard HTTP <interfacename>Session</interfacename> scope (<link |
|
linkend="beans-factory-scopes-session">described above</link>), and |
|
applies only in the context of portlet-based web applications. The |
|
portlet specification defines the notion of a global |
|
<interfacename>Session</interfacename> that is shared among all portlets |
|
that make up a single portlet web application. Beans defined at the |
|
<literal>global session</literal> scope are scoped (or bound) to the |
|
lifetime of the global portlet |
|
<interfacename>Session</interfacename>.</para> |
|
|
|
<para>If you write a standard Servlet-based web application and you define |
|
one or more beans as having <literal>global session</literal> scope, the |
|
standard HTTP <interfacename>Session</interfacename> scope is used, and |
|
no error is raised.</para> |
|
</section> |
|
|
|
<section id="beans-factory-scopes-other-injection"> |
|
<title>Scoped beans as dependencies</title> |
|
|
|
<para>The Spring IoC container manages not only the instantiation of your |
|
objects (beans), but also the wiring up of collaborators (or |
|
dependencies). If you want to inject (for example) an HTTP request |
|
scoped bean into another bean, you must inject an AOP proxy in place of |
|
the scoped bean. That is, you need to inject a proxy object that exposes |
|
the same public interface as the scoped object but that can also |
|
retrieve the real, target object from the relevant scope (for example, |
|
an HTTP request) and delegate method calls onto the real object.</para> |
|
|
|
<note> |
|
<para>You <emphasis>do not</emphasis> need to use the |
|
<literal><aop:scoped-proxy/></literal> in conjunction with beans |
|
that are scoped as <literal>singletons</literal> or |
|
<literal>prototypes</literal>. If you try to create a scoped proxy for |
|
a singleton bean, the |
|
<exceptionname>BeanCreationException</exceptionname> is raised.</para> |
|
</note> |
|
|
|
<para>The configuration in the following example is only one line, but it |
|
is important to understand the <quote>why</quote> as well as the |
|
<quote>how</quote> behind it.</para> |
|
|
|
<!--What is this example supposed to show?--> |
|
|
|
<programlisting language="xml"><?xml version="1.0" encoding="UTF-8"?> |
|
<beans xmlns="http://www.springframework.org/schema/beans" |
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|
xmlns:aop="http://www.springframework.org/schema/aop" |
|
xsi:schemaLocation="http://www.springframework.org/schema/beans |
|
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd |
|
http://www.springframework.org/schema/aop |
|
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> |
|
|
|
<lineannotation><!-- an HTTP <interfacename>Session</interfacename>-scoped bean exposed as a proxy --></lineannotation> |
|
<bean id="userPreferences" class="com.foo.UserPreferences" <emphasis role="bold">scope="session"</emphasis>> |
|
|
|
<lineannotation><!-- instructs the container to proxy the surrounding bean --></lineannotation> |
|
<emphasis role="bold"><aop:scoped-proxy/></emphasis> |
|
</bean> |
|
|
|
<lineannotation><!-- a singleton-scoped bean <emphasis role="bold">injected with a proxy to the above bean</emphasis> --></lineannotation> |
|
<bean id="userService" class="com.foo.SimpleUserService"> |
|
|
|
<lineannotation><!-- a reference to the <emphasis role="bold">proxied</emphasis> <literal>userPreferences</literal> bean --></lineannotation> |
|
<property name="userPreferences" ref="userPreferences"/> |
|
|
|
</bean> |
|
</beans> |
|
</programlisting> |
|
|
|
<para>To create such a proxy, you insert a child |
|
<literal><aop:scoped-proxy/></literal> element into a scoped bean |
|
definition. |
|
<!--To create what such proxy? Is the proxy created above? Also, below added an x-ref that seems relevant.-->(If |
|
you choose class-based proxying, you also need the CGLIB library in your |
|
classpath. See <xref |
|
linkend="beans-factory-scopes-other-injection-proxies"/> and <xref |
|
linkend="xsd-config"/>.) Why do definitions of beans scoped at the |
|
<literal>request</literal>, <literal>session</literal>, |
|
<literal>globalSession</literal> and custom-scope levels require the |
|
<literal><aop:scoped-proxy/></literal> element ? Let's examine the |
|
following singleton bean definition and contrast it with what you need |
|
to define for the aforementioned scopes. (The following |
|
<literal>userPreferences</literal> bean definition as it stands is |
|
<emphasis>incomplete.)</emphasis></para> |
|
|
|
<programlisting language="xml"><bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/> |
|
|
|
<bean id="userManager" class="com.foo.UserManager"> |
|
<property name="userPreferences" ref="userPreferences"/> |
|
</bean></programlisting> |
|
|
|
<para>In the preceding example, the singleton bean |
|
<literal>userManager</literal> is injected with a reference to the HTTP |
|
<interfacename>Session</interfacename>-scoped bean |
|
<literal>userPreferences</literal>. The salient point here is that the |
|
<literal>userManager</literal> bean is a singleton: it will be |
|
instantiated <emphasis>exactly once</emphasis> per container, and its |
|
dependencies (in this case only one, the |
|
<literal>userPreferences</literal> bean) are also injected only once. |
|
This means that the <literal>userManager</literal> bean will only |
|
operate on the exact same <literal>userPreferences</literal> object, |
|
that is, the one that it was originally injected with.</para> |
|
|
|
<!-- MLP: Beverly to review paragraph --> |
|
|
|
<para>This is <emphasis>not</emphasis> the behavior you want when |
|
injecting a shorter-lived scoped bean into a longer-lived scoped bean, |
|
for example injecting an HTTP |
|
<interfacename>Session</interfacename>-scoped collaborating bean as a |
|
dependency into singleton bean. Rather, you need a single |
|
<literal>userManager</literal> object, and for the lifetime of an HTTP |
|
<interfacename>Session</interfacename>, you need a |
|
<literal>userPreferences</literal> object that is specific to said HTTP |
|
<interfacename>Session</interfacename>. Thus the container creates an |
|
object that exposes the exact same public interface as the |
|
<classname>UserPreferences</classname> class (ideally an object that |
|
<emphasis>is a</emphasis> <classname>UserPreferences</classname> |
|
instance) which can fetch the real |
|
<classname>UserPreferences</classname> object from the scoping mechanism |
|
(HTTP request, <interfacename>Session</interfacename>, etc.). The |
|
container injects this proxy object into the |
|
<literal>userManager</literal> bean, which is unaware that this |
|
<classname>UserPreferences</classname> reference is a proxy. In this |
|
example, when a <interfacename>UserManager</interfacename> instance |
|
invokes a method on the dependency-injected |
|
<classname>UserPreferences</classname> object, it actually is invoking a |
|
method on the proxy. The proxy then fetches the real |
|
<classname>UserPreferences</classname> object from (in this case) the |
|
HTTP <interfacename>Session</interfacename>, and delegates the method |
|
invocation onto the retrieved real |
|
<classname>UserPreferences</classname> object.</para> |
|
|
|
<para>Thus you need the following, correct and complete, configuration |
|
when injecting <literal>request-</literal>, <literal>session-</literal>, |
|
and <literal>globalSession-scoped</literal> beans into collaborating |
|
objects:</para> |
|
|
|
<programlisting language="xml"><bean id="userPreferences" class="com.foo.UserPreferences" scope="session"> |
|
<emphasis role="bold"><literal><aop:scoped-proxy/></literal></emphasis> |
|
</bean> |
|
|
|
<bean id="userManager" class="com.foo.UserManager"> |
|
<property name="userPreferences" ref="userPreferences"/> |
|
</bean></programlisting> |
|
|
|
<section id="beans-factory-scopes-other-injection-proxies"> |
|
<title>Choosing the type of proxy to create</title> |
|
|
|
<para>By default, when the Spring container creates a proxy for a bean |
|
that is marked up with the |
|
<literal><aop:scoped-proxy/></literal> element, <emphasis>a |
|
CGLIB-based class proxy is created</emphasis>. This means that you |
|
need to have the CGLIB library in the classpath of your |
|
application.</para> |
|
|
|
<para><emphasis>Note: CGLIB proxies only intercept public method |
|
calls!</emphasis> Do not call non-public methods on such a proxy; they |
|
will not be delegated to the scoped target object.</para> |
|
|
|
<para>Alternatively, you can configure the Spring container to create |
|
standard JDK interface-based proxies for such scoped beans, by |
|
specifying <literal>false</literal> for the value of the |
|
<literal>proxy-target-class</literal> attribute of the |
|
<literal><aop:scoped-proxy/></literal> element. Using JDK |
|
interface-based proxies means that you do not need additional |
|
libraries in your application classpath to effect such proxying. |
|
However, it also means that the class of the scoped bean must |
|
implement at least one interface, and <emphasis>that all</emphasis> |
|
collaborators into which the scoped bean is injected must reference |
|
the bean through one of its interfaces.</para> |
|
|
|
<programlisting language="xml"><lineannotation><!-- <classname>DefaultUserPreferences</classname> implements the <interfacename>UserPreferences</interfacename> interface --></lineannotation> |
|
<bean id="userPreferences" class="com.foo.DefaultUserPreferences" scope="session"> |
|
<aop:scoped-proxy <emphasis role="bold">proxy-target-class="false"<literal/></emphasis>/> |
|
</bean> |
|
|
|
<bean id="userManager" class="com.foo.UserManager"> |
|
<property name="userPreferences" ref="userPreferences"/> |
|
</bean></programlisting> |
|
|
|
<para>For more detailed information about choosing class-based or |
|
interface-based proxying, see <xref linkend="aop-proxying"/>.</para> |
|
</section> |
|
</section> |
|
</section> |
|
|
|
<section id="beans-factory-scopes-custom"> |
|
<title>Custom scopes</title> |
|
|
|
<para>As of Spring 2.0, the bean scoping mechanism is extensible. You can |
|
define your own scopes, or even redefine existing scopes, although the |
|
latter is considered bad practice and you <emphasis>cannot</emphasis> |
|
override the built-in <literal>singleton</literal> and |
|
<literal>prototype</literal> scopes.</para> |
|
|
|
<section id="beans-factory-scopes-custom-creating"> |
|
<title>Creating a custom scope</title> |
|
|
|
<para>To integrate your custom scope(s) into the Spring container, you |
|
need to implement the |
|
<interfacename>org.springframework.beans.factory.config.Scope</interfacename> |
|
interface, which is described in this section. For an idea of how to |
|
implement your own scopes, see the <interfacename>Scope</interfacename> |
|
implementations that are supplied with the Spring Framework itself and |
|
the <ulink |
|
url="http://static.springframework.org/spring/docs/3.0.x/javadoc-api/org/springframework/beans/factory/config/Scope.html" |
|
>Scope Javadoc</ulink>, which explains the methods you need to implement |
|
in more detail.</para> |
|
|
|
<para>The <literal>Scope</literal> interface has four methods to get |
|
objects from the scope, remove them from the scope, and allow them to be |
|
destroyed.</para> |
|
|
|
<para>The following method returns the object from the underlying scope. |
|
The session scope implementation, for example, returns the |
|
session-scoped bean (and if it does not exist, the method returns a new |
|
instance of the bean, after having bound it to the session for future |
|
reference).<!--How can it return a a new instance of a bean that doesn't exist? Revise to clarify.--></para> |
|
|
|
<programlisting language="java">Object get(String name, ObjectFactory objectFactory)</programlisting> |
|
|
|
<para>The following method removes the object from the underlying scope. |
|
The session scope implementation for example, removes the session-scoped |
|
bean from the underlying session. The object should be returned, but you |
|
can return null if the object with the specified name is not |
|
found.</para> |
|
|
|
<programlisting language="java">Object remove(String name)</programlisting> |
|
|
|
<para>The following method registers the callbacks the scope should |
|
execute when it is destroyed or when the specified object in the scope |
|
is destroyed. Refer to the Javadoc or a Spring scope implementation for |
|
more information on destruction callbacks.</para> |
|
|
|
<programlisting language="java">void registerDestructionCallback(String name, Runnable destructionCallback)</programlisting> |
|
|
|
<para>The following method obtains the conversation identifier for the |
|
underlying scope. This identifier is different for each scope. For a |
|
session scoped implementation, this identifier can be the session |
|
identifier.</para> |
|
|
|
<programlisting language="java">String getConversationId()</programlisting> |
|
</section> |
|
|
|
<section id="beans-factory-scopes-custom-using"> |
|
<title>Using a custom scope</title> |
|
|
|
<para>After you write and test one or more custom |
|
<interfacename>Scope</interfacename> implementations, you need to make |
|
the Spring container aware of your new scope(s). The following method is |
|
the central method to register a new |
|
<interfacename>Scope</interfacename> with the Spring container:</para> |
|
|
|
<programlisting language="java">void registerScope(String scopeName, Scope scope);</programlisting> |
|
|
|
<para>This method is declared on the |
|
<interfacename>ConfigurableBeanFactory</interfacename> interface, which |
|
is available on most of the concrete |
|
<interfacename>ApplicationContext</interfacename> implementations that |
|
ship with Spring via the BeanFactory property.</para> |
|
|
|
<para>The first argument to the <methodname>registerScope(..)</methodname> |
|
method is the unique name associated with a scope; examples of such |
|
names in the Spring container itself are <literal>singleton</literal> |
|
and <literal>prototype</literal>. The second argument to the |
|
<methodname>registerScope(..)</methodname> method is an actual instance |
|
of the custom <interfacename>Scope</interfacename> implementation that |
|
you wish to register and use.</para> |
|
|
|
<para>Suppose that you write your custom |
|
<interfacename>Scope</interfacename> implementation, and then register |
|
it as below.</para> |
|
|
|
<note> |
|
<para>The example below uses <literal>SimpleThreadScope</literal> which |
|
is included with Spring, but not registered by default. The |
|
instructions would be the same for your own custom |
|
<literal>Scope</literal> implementations.</para> |
|
</note> |
|
|
|
<programlisting language="java"> |
|
Scope threadScope = new SimpleThreadScope(); |
|
beanFactory.registerScope("<emphasis role="bold">thread</emphasis>", threadScope);</programlisting> |
|
|
|
<para>You then create bean definitions that adhere to the scoping rules of |
|
your custom <interfacename>Scope</interfacename>:</para> |
|
|
|
<programlisting language="xml"><bean id="..." class="..." scope="thread"></programlisting> |
|
|
|
<para>With a custom <interfacename>Scope</interfacename> implementation, |
|
you are not limited to programmatic registration of the scope. You can |
|
also do the <interfacename>Scope</interfacename> registration |
|
declaratively, using the <classname>CustomScopeConfigurer</classname> |
|
class:</para> |
|
|
|
<programlisting language="xml"><?xml version="1.0" encoding="UTF-8"?> |
|
<beans xmlns="http://www.springframework.org/schema/beans" |
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|
xmlns:aop="http://www.springframework.org/schema/aop" |
|
xsi:schemaLocation="http://www.springframework.org/schema/beans |
|
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd |
|
http://www.springframework.org/schema/aop |
|
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> |
|
|
|
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> |
|
<property name="scopes"> |
|
<map><emphasis role="bold"> |
|
<entry key="thread"> |
|
<bean class="org.springframework.context.support.SimpleThreadScope"/> |
|
</entry></emphasis> |
|
</map> |
|
</property> |
|
</bean> |
|
|
|
<bean id="bar" class="x.y.Bar" scope="thread"> |
|
<property name="name" value="Rick"/> |
|
<aop:scoped-proxy/> |
|
</bean> |
|
|
|
<bean id="foo" class="x.y.Foo"> |
|
<property name="bar" ref="bar"/> |
|
</bean> |
|
|
|
</beans></programlisting> |
|
|
|
<note> |
|
<para>When you place <aop:scoped-proxy/> in a |
|
<interfacename>FactoryBean</interfacename> implementation, it is the |
|
factory bean itself that is scoped, not the object returned from |
|
<methodname>getObject()</methodname>.</para> |
|
</note> |
|
</section> |
|
</section> |
|
</section>
|
|
|