Split IoC chapter DocBook XML into multiple files (SPR-7467)
All <section/> elements in beans.xml >=~ 500 lines have been broken out into separate documents with DOCTYPE 'section'. This refactoring makes working with these files much easier in wysiwyg editors (namely oXygen Author). For consistency, this same refactoring should be applied to all other chapters much larger than 1500 lines, such as aop.xml (3861), mvc.xml (3466), jdbc.xml (3042), and so on. beans.xml and the new section files have also been formatted for consistency and to avoid whitespace diffs as much as possible into the future.
This commit is contained in:
parent
2f980d95ff
commit
9ab2c6628b
|
|
@ -0,0 +1,804 @@
|
|||
<?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-annotation-config">
|
||||
<title>Annotation-based container configuration</title>
|
||||
|
||||
<sidebar>
|
||||
<title>Are annotations better than XML for configuring Spring?</title>
|
||||
|
||||
<para>The introduction of annotation-based configurations raised the
|
||||
question of whether this approach is 'better' than XML. The short answer
|
||||
is <emphasis>it depends</emphasis>. The long answer is that each approach
|
||||
has its pros and cons, and usually it is up to the developer to decide
|
||||
which strategy suits her better. Due to the way they are defined,
|
||||
annotations provide a lot of context in their declaration, leading to
|
||||
shorter and more concise configuration. However, XML excels at wiring up
|
||||
components without touching their source code or recompiling them. Some
|
||||
developers prefer having the wiring close to the source while others argue
|
||||
that annotated classes are no longer POJOs and, furthermore, that the
|
||||
configuration becomes decentralized and harder to control.</para>
|
||||
|
||||
<para>No matter the choice, Spring can accommodate both styles and even mix
|
||||
them together. It's worth pointing out that through its <link
|
||||
linkend="beans-java">JavaConfig</link> option, Spring allows annotations
|
||||
to be used in a non-invasive way, without touching the target components
|
||||
source code and that in terms of tooling, all configuration styles are
|
||||
supported by the <ulink url="http://www.springsource.com/products/sts"
|
||||
>SpringSource Tool Suite</ulink>.</para>
|
||||
</sidebar>
|
||||
|
||||
<para>An alternative to XML setups is provided by annotation-based
|
||||
configuration which rely on the bytecode metadata for wiring up components
|
||||
instead of angle-bracket declarations. Instead of using XML to describe a
|
||||
bean wiring, the developer moves the configuration into the component class
|
||||
itself by using annotations on the relevant class, method, or field
|
||||
declaration. As mentioned in <xref
|
||||
linkend="beans-factory-extension-bpp-examples-rabpp"/>, using a
|
||||
<interfacename>BeanPostProcessor</interfacename> in conjunction with
|
||||
annotations is a common means of extending the Spring IoC container. For
|
||||
example, Spring 2.0 introduced the possibility of enforcing required
|
||||
properties with the <link linkend="beans-required-annotation"
|
||||
>@Required</link> annotation. As of Spring 2.5, it is now possible to follow
|
||||
that same general approach to drive Spring's dependency injection.
|
||||
Essentially, the <interfacename>@Autowired</interfacename> annotation
|
||||
provides the same capabilities as described in <xref
|
||||
linkend="beans-factory-autowire"/> but with more fine-grained control and
|
||||
wider applicability. Spring 2.5 also adds support for JSR-250 annotations
|
||||
such as <interfacename>@Resource</interfacename>,
|
||||
<interfacename>@PostConstruct</interfacename>, and
|
||||
<interfacename>@PreDestroy</interfacename>. Spring 3.0 adds support for
|
||||
JSR-330 (Dependency Injection for Java) annotations contained in the
|
||||
javax.inject package such as <classname>@Inject</classname>,
|
||||
<literal>@Qualifier, @Named, and @Provider</literal> if the JSR330 jar is
|
||||
present on the classpath. Use of these annotations also requires that
|
||||
certain <interfacename>BeanPostProcessors</interfacename> be registered
|
||||
within the Spring container. <note> Annotation injection is performed
|
||||
<emphasis>before</emphasis> XML injection, thus the latter configuration
|
||||
will override the former for properties wired through both approaches.
|
||||
</note> As always, you can register them as individual bean definitions, but
|
||||
they can also be implicitly registered by including the following tag in an
|
||||
XML-based Spring configuration (notice the inclusion of the
|
||||
<literal>context</literal> namespace):</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"
|
||||
<lineannotation>xmlns:context="http://www.springframework.org/schema/context"</lineannotation>
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/context
|
||||
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
|
||||
|
||||
<lineannotation><context:annotation-config/></lineannotation>
|
||||
|
||||
</beans></programlisting>
|
||||
|
||||
<para>(The implicitly registered post-processors include <ulink
|
||||
url="http://static.springframework.org/spring/docs/3.0.x/javadoc-api/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.html"
|
||||
><classname>AutowiredAnnotationBeanPostProcessor</classname></ulink>, <ulink
|
||||
url="http://static.springframework.org/spring/docs/3.0.x/javadoc-api/org/springframework/context/annotation/CommonAnnotationBeanPostProcessor.html"
|
||||
><classname>CommonAnnotationBeanPostProcessor</classname></ulink>, <ulink
|
||||
url="http://static.springframework.org/spring/docs/3.0.x/javadoc-api/org/springframework/orm/jpa/support/PersistenceAnnotationBeanPostProcessor.html"
|
||||
><classname>PersistenceAnnotationBeanPostProcessor</classname></ulink>, as
|
||||
well as the aforementioned <ulink
|
||||
url="http://static.springframework.org/spring/docs/3.0.x/javadoc-api/org/springframework/beans/factory/annotation/RequiredAnnotationBeanPostProcessor.html"
|
||||
><classname>RequiredAnnotationBeanPostProcessor</classname></ulink>.)</para>
|
||||
|
||||
<note>
|
||||
<para><literal><context:annotation-config/></literal> only looks for
|
||||
annotations on beans in the same application context in which it is
|
||||
defined. This means that, if you put
|
||||
<literal><context:annotation-config/></literal> in a
|
||||
<interfacename>WebApplicationContext</interfacename> for a
|
||||
<classname>DispatcherServlet</classname>, it only checks for
|
||||
<interfacename>@Autowired</interfacename> beans in your controllers, and
|
||||
not your services. See <xref linkend="mvc-servlet"/> for more
|
||||
information.</para>
|
||||
</note>
|
||||
|
||||
<section id="beans-required-annotation">
|
||||
<title><interfacename>@Required</interfacename></title>
|
||||
|
||||
<para>The <interfacename>@Required</interfacename> annotation applies to
|
||||
bean property setter methods, as in the following example:</para>
|
||||
|
||||
<programlisting language="java">public class SimpleMovieLister {
|
||||
|
||||
private MovieFinder movieFinder;
|
||||
|
||||
@Required
|
||||
public void setMovieFinder(MovieFinder movieFinder) {
|
||||
this.movieFinder = movieFinder;
|
||||
}
|
||||
|
||||
<lineannotation>// ...</lineannotation>
|
||||
}</programlisting>
|
||||
|
||||
<para>This annotation simply indicates that the affected bean property must
|
||||
be populated at configuration time, through an explicit property value in
|
||||
a bean definition or through autowiring. The container throws an exception
|
||||
if the affected bean property has not been populated; this allows for
|
||||
eager and explicit failure, avoiding
|
||||
<classname>NullPointerException</classname>s or the like later on. It is
|
||||
still recommended that you put assertions into the bean class itself, for
|
||||
example, into an init method. Doing so enforces those required references
|
||||
and values even when you use the class outside of a container.</para>
|
||||
</section>
|
||||
|
||||
<section id="beans-autowired-annotation">
|
||||
<title><interfacename>@Autowired and @Inject</interfacename></title>
|
||||
|
||||
<para>As expected, you can apply the
|
||||
<interfacename>@Autowired</interfacename> annotation to "traditional"
|
||||
setter methods:</para>
|
||||
|
||||
<note>
|
||||
<para>JSR 330's @Inject annotation can be used in place of Spring's
|
||||
<interfacename>@Autowired</interfacename> in the examples below.
|
||||
<interfacename>@Inject</interfacename> does not have a required property
|
||||
unlike Spring's <interfacename>@Autowired</interfacename> annotation
|
||||
which has a <literal>required</literal> property to indicate if the
|
||||
value being injected is optional. This behavior is enabled automatically
|
||||
if you have the JSR 330 JAR on the classpath.</para>
|
||||
</note>
|
||||
|
||||
<programlisting language="java">public class SimpleMovieLister {
|
||||
|
||||
private MovieFinder movieFinder;
|
||||
|
||||
@Autowired
|
||||
public void setMovieFinder(MovieFinder movieFinder) {
|
||||
this.movieFinder = movieFinder;
|
||||
}
|
||||
|
||||
<lineannotation>// ...</lineannotation>
|
||||
}</programlisting>
|
||||
|
||||
<para>You can also apply the annotation to methods with arbitrary names
|
||||
and/or multiple arguments:</para>
|
||||
|
||||
<programlisting language="java">public class MovieRecommender {
|
||||
|
||||
private MovieCatalog movieCatalog;
|
||||
|
||||
private CustomerPreferenceDao customerPreferenceDao;
|
||||
|
||||
@Autowired
|
||||
public void prepare(MovieCatalog movieCatalog,
|
||||
CustomerPreferenceDao customerPreferenceDao) {
|
||||
this.movieCatalog = movieCatalog;
|
||||
this.customerPreferenceDao = customerPreferenceDao;
|
||||
}
|
||||
|
||||
<lineannotation>// ...</lineannotation>
|
||||
}</programlisting>
|
||||
|
||||
<para>You can apply <interfacename>@Autowired</interfacename> to
|
||||
constructors and fields:</para>
|
||||
|
||||
<programlisting language="java">public class MovieRecommender {
|
||||
|
||||
@Autowired
|
||||
private MovieCatalog movieCatalog;
|
||||
|
||||
private CustomerPreferenceDao customerPreferenceDao;
|
||||
|
||||
@Autowired
|
||||
public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
|
||||
this.customerPreferenceDao = customerPreferenceDao;
|
||||
}
|
||||
|
||||
<lineannotation>// ...</lineannotation>
|
||||
}</programlisting>
|
||||
|
||||
<para>It is also possible to provide <emphasis>all</emphasis> beans of a
|
||||
particular type from the <interfacename>ApplicationContext</interfacename>
|
||||
by adding the annotation to a field or method that expects an array of
|
||||
that type:</para>
|
||||
|
||||
<programlisting language="java">public class MovieRecommender {
|
||||
|
||||
@Autowired
|
||||
private MovieCatalog[] movieCatalogs;
|
||||
|
||||
<lineannotation>// ...</lineannotation>
|
||||
}</programlisting>
|
||||
|
||||
<para>The same applies for typed collections:</para>
|
||||
|
||||
<programlisting language="java">public class MovieRecommender {
|
||||
|
||||
private Set<MovieCatalog> movieCatalogs;
|
||||
|
||||
@Autowired
|
||||
public void setMovieCatalogs(Set<MovieCatalog> movieCatalogs) {
|
||||
this.movieCatalogs = movieCatalogs;
|
||||
}
|
||||
|
||||
<lineannotation>// ...</lineannotation>
|
||||
}</programlisting>
|
||||
|
||||
<para>Even typed Maps can be autowired as long as the expected key type is
|
||||
<classname>String</classname>. The Map values will contain all beans of
|
||||
the expected type, and the keys will contain the corresponding bean
|
||||
names:</para>
|
||||
|
||||
<programlisting language="java">public class MovieRecommender {
|
||||
|
||||
private Map<String, MovieCatalog> movieCatalogs;
|
||||
|
||||
@Autowired
|
||||
public void setMovieCatalogs(Map<String, MovieCatalog> movieCatalogs) {
|
||||
this.movieCatalogs = movieCatalogs;
|
||||
}
|
||||
|
||||
<lineannotation>// ...</lineannotation>
|
||||
}</programlisting>
|
||||
|
||||
<para>By default, the autowiring fails whenever <emphasis>zero</emphasis>
|
||||
candidate beans are available; the default behavior is to treat annotated
|
||||
methods, constructors, and fields as indicating
|
||||
<emphasis>required</emphasis> dependencies. This behavior can be changed
|
||||
as demonstrated below.</para>
|
||||
|
||||
<programlisting language="java">public class SimpleMovieLister {
|
||||
|
||||
private MovieFinder movieFinder;
|
||||
|
||||
@Autowired(required=false)
|
||||
public void setMovieFinder(MovieFinder movieFinder) {
|
||||
this.movieFinder = movieFinder;
|
||||
}
|
||||
|
||||
<lineannotation>// ...</lineannotation>
|
||||
}</programlisting>
|
||||
|
||||
<note>
|
||||
<para>Only <emphasis>one annotated constructor per-class</emphasis> can be
|
||||
marked as <emphasis>required</emphasis>, but multiple non-required
|
||||
constructors can be annotated. In that case, each is considered among
|
||||
the candidates and Spring uses the <emphasis>greediest</emphasis>
|
||||
constructor whose dependencies can be satisfied, that is the constructor
|
||||
that has the largest number of arguments.</para>
|
||||
|
||||
<para><interfacename>@Autowired</interfacename>'s
|
||||
<emphasis>required</emphasis> attribute is recommended over the
|
||||
<interfacename>@Required</interfacename> annotation. The
|
||||
<emphasis>required</emphasis> attribute indicates that the property is
|
||||
not required for autowiring purposes, the property is ignored if it
|
||||
cannot be autowired. <interfacename>@Required</interfacename>, on the
|
||||
other hand, is stronger in that it enforces the property that was set by
|
||||
any means supported by the container. If no value is injected, a
|
||||
corresponding exception is raised.</para>
|
||||
</note>
|
||||
|
||||
<para>You can also use <interfacename>@Autowired</interfacename> for
|
||||
interfaces that are well-known resolvable dependencies:
|
||||
<interfacename>BeanFactory</interfacename>,
|
||||
<interfacename>ApplicationContext</interfacename>,
|
||||
<interfacename>ResourceLoader</interfacename>,
|
||||
<interfacename>ApplicationEventPublisher</interfacename>, and
|
||||
<interfacename>MessageSource</interfacename>. These interfaces and their
|
||||
extended interfaces, such as
|
||||
<interfacename>ConfigurableApplicationContext</interfacename> or
|
||||
<interfacename>ResourcePatternResolver</interfacename>, are automatically
|
||||
resolved, with no special setup necessary.</para>
|
||||
|
||||
<programlisting language="java">public class MovieRecommender {
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext context;
|
||||
|
||||
public MovieRecommender() {
|
||||
}
|
||||
|
||||
<lineannotation>// ...</lineannotation>
|
||||
}</programlisting>
|
||||
</section>
|
||||
|
||||
<section id="beans-autowired-annotation-qualifiers">
|
||||
<title>Fine-tuning annotation-based autowiring with qualifiers</title>
|
||||
|
||||
<para>Because autowiring by type may lead to multiple candidates, it is
|
||||
often necessary to have more control over the selection process. One way
|
||||
to accomplish this is with Spring's
|
||||
<interfacename>@Qualifier</interfacename> annotation. You can associate
|
||||
qualifier values with specific arguments, narrowing the set of type
|
||||
matches so that a specific bean is chosen for each argument. In the
|
||||
simplest case, this can be a plain descriptive value:</para>
|
||||
|
||||
<note>
|
||||
<para>JSR 330's <interfacename>@Qualifier</interfacename> annotation can
|
||||
only be applied as a meta-annotation unlike Spring's @Qualifier which
|
||||
takes a string property to discriminate among multiple injection
|
||||
candidates and can be placed on annotations as well as types, fields,
|
||||
methods, constructors, and parameters.</para>
|
||||
</note>
|
||||
|
||||
<programlisting language="java">public class MovieRecommender {
|
||||
|
||||
@Autowired
|
||||
<emphasis role="bold">@Qualifier("main")</emphasis>
|
||||
private MovieCatalog movieCatalog;
|
||||
|
||||
<lineannotation>// ...</lineannotation>
|
||||
}</programlisting>
|
||||
|
||||
<para>The <interfacename>@Qualifier</interfacename> annotation can also be
|
||||
specified on individual constructor arguments or method parameters:</para>
|
||||
|
||||
<programlisting language="java">public class MovieRecommender {
|
||||
|
||||
private MovieCatalog movieCatalog;
|
||||
|
||||
private CustomerPreferenceDao customerPreferenceDao;
|
||||
|
||||
@Autowired
|
||||
public void prepare(<emphasis role="bold">@Qualifier("main")</emphasis> MovieCatalog movieCatalog,
|
||||
CustomerPreferenceDao customerPreferenceDao) {
|
||||
this.movieCatalog = movieCatalog;
|
||||
this.customerPreferenceDao = customerPreferenceDao;
|
||||
}
|
||||
|
||||
<lineannotation>// ...</lineannotation>
|
||||
}</programlisting>
|
||||
|
||||
<para>The corresponding bean definitions appear as follows. The bean with
|
||||
qualifier value "main" is wired with the constructor argument that is
|
||||
qualified with the same value.</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:context="http://www.springframework.org/schema/context"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/context
|
||||
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
|
||||
|
||||
<context:annotation-config/>
|
||||
|
||||
<bean class="example.SimpleMovieCatalog">
|
||||
<emphasis role="bold"><qualifier value="main"/></emphasis>
|
||||
<lineannotation><!-- inject any dependencies required by this bean --></lineannotation>
|
||||
</bean>
|
||||
|
||||
<bean class="example.SimpleMovieCatalog">
|
||||
<emphasis role="bold"><qualifier value="action"/></emphasis>
|
||||
<lineannotation><!-- inject any dependencies required by this bean --></lineannotation>
|
||||
</bean>
|
||||
|
||||
<bean id="movieRecommender" class="example.MovieRecommender"/>
|
||||
|
||||
</beans>
|
||||
</programlisting>
|
||||
|
||||
<para>For a fallback match, the bean name is considered a default qualifier
|
||||
value. Thus you can define the bean with an id "main" instead of the
|
||||
nested qualifier element, leading to the same matching result. However,
|
||||
although you can use this convention to refer to specific beans by name,
|
||||
<interfacename>@Autowired</interfacename> is fundamentally about
|
||||
type-driven injection with optional semantic qualifiers. This means that
|
||||
qualifier values, even with the bean name fallback, always have narrowing
|
||||
semantics within the set of type matches; they do not semantically express
|
||||
a reference to a unique bean id. Good qualifier values are "main" or
|
||||
"EMEA" or "persistent", expressing characteristics of a specific component
|
||||
that are independent from the bean id, which may be auto-generated in case
|
||||
of an anonymous bean definition like the one in the preceding
|
||||
example.</para>
|
||||
|
||||
<para>Qualifiers also apply to typed collections, as discussed above, for
|
||||
example, to <literal>Set<MovieCatalog></literal>. In this case, all
|
||||
matching beans according to the declared qualifiers are injected as a
|
||||
collection. This implies that qualifiers do not have to be unique; they
|
||||
rather simply constitute filtering criteria. For example, you can define
|
||||
multiple <classname>MovieCatalog</classname> beans with the same qualifier
|
||||
value "action"; all of which would be injected into a
|
||||
<literal>Set<MovieCatalog></literal> annotated with
|
||||
<literal>@Qualifier("action")</literal>.</para>
|
||||
|
||||
<tip>
|
||||
<para>If you intend to express annotation-driven injection by name, do not
|
||||
primarily use <interfacename>@Autowired</interfacename>, even if is
|
||||
technically capable of referring to a bean name through
|
||||
<interfacename>@Qualifier</interfacename> values. Instead, use the
|
||||
JSR-250 <interfacename>@Resource</interfacename> annotation, which is
|
||||
semantically defined to identify a specific target component by its
|
||||
unique name, with the declared type being irrelevant for the matching
|
||||
process.</para>
|
||||
|
||||
<para>As a specific consequence of this semantic difference, beans that
|
||||
are themselves defined as a collection or map type cannot be injected
|
||||
through <interfacename>@Autowired</interfacename>, because type matching
|
||||
is not properly applicable to them. Use
|
||||
<interfacename>@Resource</interfacename> for such beans, referring to
|
||||
the specific collection or map bean by unique name.</para>
|
||||
|
||||
<para><interfacename>@Autowired</interfacename> applies to fields,
|
||||
constructors, and multi-argument methods, allowing for narrowing through
|
||||
qualifier annotations at the parameter level. By contrast,
|
||||
<interfacename>@Resource</interfacename> is supported only for fields
|
||||
and bean property setter methods with a single argument. As a
|
||||
consequence, stick with qualifiers if your injection target is a
|
||||
constructor or a multi-argument method.</para>
|
||||
</tip>
|
||||
|
||||
<para>You can create your own custom qualifier annotations. Simply define an
|
||||
annotation and provide the <interfacename>@Qualifier</interfacename>
|
||||
annotation within your definition:</para>
|
||||
|
||||
<note>
|
||||
<para>You can use JSR 330's <interfacename>@Qualifier
|
||||
</interfacename>annotation in the manner described below in place of
|
||||
Spring's <interfacename>@Qualifier</interfacename> annotation. This
|
||||
behavior is enabled automatically if you have the JSR 330 jar on the
|
||||
classpath.</para>
|
||||
</note>
|
||||
|
||||
<programlisting language="java">@Target({ElementType.FIELD, ElementType.PARAMETER})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
<emphasis role="bold">@Qualifier</emphasis>
|
||||
public @interface Genre {
|
||||
|
||||
String value();
|
||||
}</programlisting>
|
||||
|
||||
<para>Then you can provide the custom qualifier on autowired fields and
|
||||
parameters:</para>
|
||||
|
||||
<programlisting language="java">public class MovieRecommender {
|
||||
|
||||
@Autowired
|
||||
<emphasis role="bold">@Genre("Action")</emphasis>
|
||||
private MovieCatalog actionCatalog;
|
||||
|
||||
private MovieCatalog comedyCatalog;
|
||||
|
||||
@Autowired
|
||||
public void setComedyCatalog(<emphasis role="bold">@Genre("Comedy")</emphasis> MovieCatalog comedyCatalog) {
|
||||
this.comedyCatalog = comedyCatalog;
|
||||
}
|
||||
|
||||
<lineannotation>// ...</lineannotation>
|
||||
}</programlisting>
|
||||
|
||||
<para>Next, provide the information for the candidate bean definitions. You
|
||||
can add <literal><qualifier/></literal> tags as sub-elements of the
|
||||
<literal><bean/></literal> tag and then specify the
|
||||
<literal>type</literal> and <literal>value</literal> to match your custom
|
||||
qualifier annotations. The type is matched against the fully-qualified
|
||||
class name of the annotation. Or, as a convenience if no risk of
|
||||
conflicting names exists, you can use the short class name. Both
|
||||
approaches are demonstrated in the following example.</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:context="http://www.springframework.org/schema/context"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/context
|
||||
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
|
||||
|
||||
<context:annotation-config/>
|
||||
|
||||
<bean class="example.SimpleMovieCatalog">
|
||||
<emphasis role="bold"><qualifier type="Genre" value="Action"/></emphasis>
|
||||
<lineannotation><!-- inject any dependencies required by this bean --></lineannotation>
|
||||
</bean>
|
||||
|
||||
<bean class="example.SimpleMovieCatalog">
|
||||
<emphasis role="bold"><qualifier type="example.Genre" value="Comedy"/></emphasis>
|
||||
<lineannotation><!-- inject any dependencies required by this bean --></lineannotation>
|
||||
</bean>
|
||||
|
||||
<bean id="movieRecommender" class="example.MovieRecommender"/>
|
||||
|
||||
</beans>
|
||||
</programlisting>
|
||||
|
||||
<para>In <xref linkend="beans-classpath-scanning"/>, you will see an
|
||||
annotation-based alternative to providing the qualifier metadata in XML.
|
||||
Specifically, see <xref linkend="beans-scanning-qualifiers"/>.</para>
|
||||
|
||||
<para>In some cases, it may be sufficient to use an annotation without a
|
||||
value. This may be useful when the annotation serves a more generic
|
||||
purpose and can be applied across several different types of dependencies.
|
||||
For example, you may provide an <emphasis>offline</emphasis> catalog that
|
||||
would be searched when no Internet connection is available. First define
|
||||
the simple annotation:</para>
|
||||
|
||||
<programlisting language="java">@Target({ElementType.FIELD, ElementType.PARAMETER})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Qualifier
|
||||
public @interface Offline {
|
||||
|
||||
}</programlisting>
|
||||
|
||||
<para>Then add the annotation to the field or property to be
|
||||
autowired:</para>
|
||||
|
||||
<programlisting language="java">public class MovieRecommender {
|
||||
|
||||
@Autowired
|
||||
<emphasis role="bold">@Offline</emphasis>
|
||||
private MovieCatalog offlineCatalog;
|
||||
|
||||
<lineannotation>// ...</lineannotation>
|
||||
}</programlisting>
|
||||
|
||||
<para>Now the bean definition only needs a qualifier
|
||||
<literal>type</literal>:</para>
|
||||
|
||||
<programlisting language="xml"><bean class="example.SimpleMovieCatalog">
|
||||
<emphasis role="bold"><qualifier type="Offline"/></emphasis>
|
||||
<lineannotation><!-- inject any dependencies required by this bean --></lineannotation>
|
||||
</bean></programlisting>
|
||||
|
||||
<para>You can also define custom qualifier annotations that accept named
|
||||
attributes in addition to or instead of the simple
|
||||
<literal>value</literal> attribute. If multiple attribute values are then
|
||||
specified on a field or parameter to be autowired, a bean definition must
|
||||
match <emphasis>all</emphasis> such attribute values to be considered an
|
||||
autowire candidate. As an example, consider the following annotation
|
||||
definition:</para>
|
||||
|
||||
<programlisting language="java">@Target({ElementType.FIELD, ElementType.PARAMETER})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Qualifier
|
||||
public @interface MovieQualifier {
|
||||
|
||||
String genre();
|
||||
|
||||
Format format();
|
||||
}</programlisting>
|
||||
|
||||
<para>In this case <literal>Format</literal> is an enum:</para>
|
||||
|
||||
<programlisting language="java">public enum Format {
|
||||
|
||||
VHS, DVD, BLURAY
|
||||
}</programlisting>
|
||||
|
||||
<para>The fields to be autowired are annotated with the custom qualifier and
|
||||
include values for both attributes: <literal>genre</literal> and
|
||||
<literal>format</literal>.</para>
|
||||
|
||||
<programlisting language="java">public class MovieRecommender {
|
||||
|
||||
@Autowired
|
||||
@MovieQualifier(format=Format.VHS, genre="Action")
|
||||
private MovieCatalog actionVhsCatalog;
|
||||
|
||||
@Autowired
|
||||
@MovieQualifier(format=Format.VHS, genre="Comedy")
|
||||
private MovieCatalog comedyVhsCatalog;
|
||||
|
||||
@Autowired
|
||||
@MovieQualifier(format=Format.DVD, genre="Action")
|
||||
private MovieCatalog actionDvdCatalog;
|
||||
|
||||
@Autowired
|
||||
@MovieQualifier(format=Format.BLURAY, genre="Comedy")
|
||||
private MovieCatalog comedyBluRayCatalog;
|
||||
|
||||
<lineannotation>// ...</lineannotation>
|
||||
}</programlisting>
|
||||
|
||||
<para>Finally, the bean definitions should contain matching qualifier
|
||||
values. This example also demonstrates that bean <emphasis>meta</emphasis>
|
||||
attributes may be used instead of the
|
||||
<literal><qualifier/></literal> sub-elements. If available, the
|
||||
<literal><qualifier/></literal> and its attributes take precedence,
|
||||
but the autowiring mechanism falls back on the values provided within the
|
||||
<literal><meta/></literal> tags if no such qualifier is present, as
|
||||
in the last two bean definitions in the following example.</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:context="http://www.springframework.org/schema/context"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/context
|
||||
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
|
||||
|
||||
<context:annotation-config/>
|
||||
|
||||
<bean class="example.SimpleMovieCatalog">
|
||||
<qualifier type="MovieQualifier">
|
||||
<attribute key="format" value="VHS"/>
|
||||
<attribute key="genre" value="Action"/>
|
||||
</qualifier>
|
||||
<lineannotation><!-- inject any dependencies required by this bean --></lineannotation>
|
||||
</bean>
|
||||
|
||||
<bean class="example.SimpleMovieCatalog">
|
||||
<qualifier type="MovieQualifier">
|
||||
<attribute key="format" value="VHS"/>
|
||||
<attribute key="genre" value="Comedy"/>
|
||||
</qualifier>
|
||||
<lineannotation><!-- inject any dependencies required by this bean --></lineannotation>
|
||||
</bean>
|
||||
|
||||
<bean class="example.SimpleMovieCatalog">
|
||||
<meta key="format" value="DVD"/>
|
||||
<meta key="genre" value="Action"/>
|
||||
<lineannotation><!-- inject any dependencies required by this bean --></lineannotation>
|
||||
</bean>
|
||||
|
||||
<bean class="example.SimpleMovieCatalog">
|
||||
<meta key="format" value="BLURAY"/>
|
||||
<meta key="genre" value="Comedy"/>
|
||||
<lineannotation><!-- inject any dependencies required by this bean --></lineannotation>
|
||||
</bean>
|
||||
|
||||
</beans></programlisting>
|
||||
</section>
|
||||
|
||||
<section id="beans-custom-autowire-configurer">
|
||||
<title><classname>CustomAutowireConfigurer</classname></title>
|
||||
|
||||
<para>The <ulink
|
||||
url="http://static.springframework.org/spring/docs/3.0.x/javadoc-api/org/springframework/beans/factory/annotation/CustomAutowireConfigurer.html"
|
||||
><classname>CustomAutowireConfigurer</classname></ulink> is a
|
||||
<interfacename>BeanFactoryPostProcessor</interfacename> that enables you
|
||||
to register your own custom qualifier annotation types even if they are
|
||||
not annotated with Spring's <interfacename>@Qualifier</interfacename>
|
||||
annotation.</para>
|
||||
|
||||
<programlisting language="xml"><bean id="customAutowireConfigurer"
|
||||
class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">
|
||||
<property name="customQualifierTypes">
|
||||
<set>
|
||||
<value>example.CustomQualifier</value>
|
||||
</set>
|
||||
</property>
|
||||
</bean></programlisting>
|
||||
|
||||
<para>The particular implementation of
|
||||
<interfacename>AutowireCandidateResolver</interfacename> that is activated
|
||||
for the application context depends on the Java version. In versions
|
||||
earlier than Java 5, the qualifier annotations are not supported, and
|
||||
therefore autowire candidates are solely determined by the
|
||||
<literal>autowire-candidate</literal> value of each bean definition as
|
||||
well as by any <literal>default-autowire-candidates</literal> pattern(s)
|
||||
available on the <literal><beans/></literal> element. In Java 5 or
|
||||
later, the presence of <interfacename>@Qualifier</interfacename>
|
||||
annotations and any custom annotations registered with the
|
||||
<classname>CustomAutowireConfigurer</classname> will also play a
|
||||
role.</para>
|
||||
|
||||
<para>Regardless of the Java version, when multiple beans qualify as
|
||||
autowire candidates, the determination of a "primary" candidate is the
|
||||
same: if exactly one bean definition among the candidates has a
|
||||
<literal>primary</literal> attribute set to <literal>true</literal>, it
|
||||
will be selected.</para>
|
||||
</section>
|
||||
|
||||
<section id="beans-resource-annotation">
|
||||
<title><interfacename>@Resource</interfacename></title>
|
||||
|
||||
<para>Spring also supports injection using the JSR-250
|
||||
<interfacename>@Resource</interfacename> annotation on fields or bean
|
||||
property setter methods. This is a common pattern in Java EE 5 and 6, for
|
||||
example in JSF 1.2 managed beans or JAX-WS 2.0 endpoints. Spring supports
|
||||
this pattern for Spring-managed objects as well.</para>
|
||||
|
||||
<para><interfacename>@Resource</interfacename> takes a name attribute, and
|
||||
by default Spring interprets that value as the bean name to be injected.
|
||||
In other words, it follows <emphasis>by-name</emphasis> semantics, as
|
||||
demonstrated in this example:</para>
|
||||
|
||||
<programlisting language="java">public class SimpleMovieLister {
|
||||
|
||||
private MovieFinder movieFinder;
|
||||
|
||||
<emphasis role="bold">@Resource(name="myMovieFinder")</emphasis>
|
||||
public void setMovieFinder(MovieFinder movieFinder) {
|
||||
this.movieFinder = movieFinder;
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<para>If no name is specified explicitly, the default name is derived from
|
||||
the field name or setter method. In case of a field, it takes the field
|
||||
name; in case of a setter method, it takes the bean property name. So the
|
||||
following example is going to have the bean with name "movieFinder"
|
||||
injected into its setter method:</para>
|
||||
|
||||
<programlisting language="java">public class SimpleMovieLister {
|
||||
|
||||
private MovieFinder movieFinder;
|
||||
|
||||
<emphasis role="bold">@Resource</emphasis>
|
||||
public void setMovieFinder(MovieFinder movieFinder) {
|
||||
this.movieFinder = movieFinder;
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<note>
|
||||
<para>The name provided with the annotation is resolved as a bean name by
|
||||
the <interfacename>ApplicationContext</interfacename> of which the
|
||||
<classname>CommonAnnotationBeanPostProcessor</classname> is aware. The
|
||||
names can be resolved through JNDI if you configure Spring's <ulink
|
||||
url="http://static.springframework.org/spring/docs/3.0.x/javadoc-api/org/springframework/jndi/support/SimpleJndiBeanFactory.html"
|
||||
><classname>SimpleJndiBeanFactory</classname></ulink> explicitly.
|
||||
However, it is recommended that you rely on the default behavior and
|
||||
simply use Spring's JNDI lookup capabilities to preserve the level of
|
||||
indirection.</para>
|
||||
</note>
|
||||
|
||||
<para>In the exclusive case of <interfacename>@Resource</interfacename>
|
||||
usage with no explicit name specified, and similar to
|
||||
<interfacename>@Autowired</interfacename>,
|
||||
<interfacename>@Resource</interfacename> finds a primary type match
|
||||
instead of a specific named bean and resolves well-known resolvable
|
||||
dependencies: the
|
||||
<interfacename>BeanFactory</interfacename><interfacename>,
|
||||
ApplicationContext,</interfacename><interfacename> ResourceLoader,
|
||||
ApplicationEventPublisher</interfacename>, and
|
||||
<interfacename>MessageSource</interfacename> interfaces.</para>
|
||||
|
||||
<para>Thus in the following example, the
|
||||
<literal>customerPreferenceDao</literal> field first looks for a bean
|
||||
named customerPreferenceDao, then falls back to a primary type match for
|
||||
the type <classname>CustomerPreferenceDao</classname>. The "context" field
|
||||
is injected based on the known resolvable dependency type
|
||||
<interfacename>ApplicationContext</interfacename>.</para>
|
||||
|
||||
<programlisting language="java">public class MovieRecommender {
|
||||
|
||||
@Resource
|
||||
private CustomerPreferenceDao customerPreferenceDao;
|
||||
|
||||
@Resource
|
||||
private ApplicationContext context;
|
||||
|
||||
public MovieRecommender() {
|
||||
}
|
||||
|
||||
<lineannotation>// ...</lineannotation>
|
||||
}</programlisting>
|
||||
</section>
|
||||
|
||||
<section id="beans-postconstruct-and-predestroy-annotations">
|
||||
<title><interfacename>@PostConstruct</interfacename> and
|
||||
<interfacename>@PreDestroy</interfacename></title>
|
||||
|
||||
<para>The <classname>CommonAnnotationBeanPostProcessor</classname> not only
|
||||
recognizes the <interfacename>@Resource</interfacename> annotation but
|
||||
also the JSR-250 <emphasis>lifecycle</emphasis> annotations. Introduced in
|
||||
Spring 2.5, the support for these annotations offers yet another
|
||||
alternative to those described in <link
|
||||
linkend="beans-factory-lifecycle-initializingbean">initialization
|
||||
callbacks</link> and <link
|
||||
linkend="beans-factory-lifecycle-disposablebean">destruction
|
||||
callbacks</link>. Provided that the
|
||||
<classname>CommonAnnotationBeanPostProcessor</classname> is registered
|
||||
within the Spring <interfacename>ApplicationContext</interfacename>, a
|
||||
method carrying one of these annotations is invoked at the same point in
|
||||
the lifecycle as the corresponding Spring lifecycle interface method or
|
||||
explicitly declared callback method. In the example below, the cache will
|
||||
be pre-populated upon initialization and cleared upon destruction.</para>
|
||||
|
||||
<programlisting language="java">public class CachingMovieLister {
|
||||
|
||||
@PostConstruct
|
||||
public void populateMovieCache() {
|
||||
<lineannotation>// populates the movie cache upon initialization...</lineannotation>
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void clearMovieCache() {
|
||||
<lineannotation>// clears the movie cache upon destruction...</lineannotation>
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<note>
|
||||
<para>For details about the effects of combining various lifecycle
|
||||
mechanisms, see <xref linkend="beans-factory-lifecycle-combined-effects"
|
||||
/>.</para>
|
||||
</note>
|
||||
</section>
|
||||
</section>
|
||||
|
|
@ -0,0 +1,510 @@
|
|||
<?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-classpath-scanning">
|
||||
<title>Classpath scanning and managed components</title>
|
||||
|
||||
<!-- MLP: Beverly to review paragraph -->
|
||||
|
||||
<para>Most examples foo bar in this chapter use XML to specify the
|
||||
configuration metadata that produces each
|
||||
<interfacename>BeanDefinition</interfacename> within the Spring container.
|
||||
The previous section (<xref linkend="beans-annotation-config"/>)
|
||||
demonstrates how to provide a lot of the configuration metadata through
|
||||
source-level annotations. Even in those examples, however, the "base" bean
|
||||
definitions are explicitly defined in the XML file, while the annotations
|
||||
only drive the dependency injection. This section describes an option for
|
||||
implicitly detecting the <emphasis>candidate components</emphasis> by
|
||||
scanning the classpath. Candidate components are classes that match against
|
||||
a filter criteria and have a corresponding bean definition registered with
|
||||
the container. This removes the need to use XML to perform bean
|
||||
registration, instead you can use annotations (for example @Component),
|
||||
AspectJ type expressions, or your own custom filter criteria to select which
|
||||
classes will have bean definitions registered with the container.</para>
|
||||
|
||||
<note>
|
||||
<para>Starting with Spring 3.0, many features provided by the <ulink
|
||||
url="http://www.springsource.org/javaconfig">Spring JavaConfig
|
||||
project</ulink> are part of the core Spring Framework. This allows you to
|
||||
define beans using Java rather than using the traditional XML files. Take
|
||||
a look at the <interfacename>@Configuration</interfacename>,
|
||||
<interfacename>@Bean</interfacename>,
|
||||
<interfacename>@Import</interfacename>, and
|
||||
<interfacename>@DependsOn</interfacename> annotations for examples of how
|
||||
to use these new features.</para>
|
||||
</note>
|
||||
|
||||
<section id="beans-stereotype-annotations">
|
||||
<title><interfacename>@Component</interfacename> and further stereotype
|
||||
annotations</title>
|
||||
|
||||
<para>In Spring 2.0 and later, the
|
||||
<interfacename>@Repository</interfacename> annotation is a marker for any
|
||||
class that fulfills the role or <emphasis>stereotype</emphasis> (also
|
||||
known as Data Access Object or DAO) of a repository. Among the uses of
|
||||
this marker is the automatic translation of exceptions as described in
|
||||
<xref linkend="orm-exception-translation"/>.</para>
|
||||
|
||||
<para>Spring 2.5 introduces further stereotype annotations:
|
||||
<interfacename>@Component</interfacename>,
|
||||
<interfacename>@Service</interfacename>, and
|
||||
<interfacename>@Controller</interfacename>.
|
||||
<interfacename>@Component</interfacename> is a generic stereotype for any
|
||||
Spring-managed component. <interfacename>@Repository</interfacename>,
|
||||
<interfacename>@Service</interfacename>, and
|
||||
<interfacename>@Controller</interfacename> are specializations of
|
||||
<interfacename>@Component</interfacename> for more specific use cases, for
|
||||
example, in the persistence, service, and presentation layers,
|
||||
respectively. Therefore, you can annotate your component classes with
|
||||
<interfacename>@Component</interfacename>, but by annotating them with
|
||||
<interfacename>@Repository</interfacename>,
|
||||
<interfacename>@Service</interfacename>, or
|
||||
<interfacename>@Controller</interfacename> instead, your classes are more
|
||||
properly suited for processing by tools or associating with aspects. For
|
||||
example, these stereotype annotations make ideal targets for pointcuts. It
|
||||
is also possible that <interfacename>@Repository</interfacename>,
|
||||
<interfacename>@Service</interfacename>, and
|
||||
<interfacename>@Controller</interfacename> may carry additional semantics
|
||||
in future releases of the Spring Framework. Thus, if you are choosing
|
||||
between using <interfacename>@Component</interfacename> or
|
||||
<interfacename>@Service</interfacename> for your service layer,
|
||||
<interfacename>@Service</interfacename> is clearly the better choice.
|
||||
Similarly, as stated above, <interfacename>@Repository</interfacename> is
|
||||
already supported as a marker for automatic exception translation in your
|
||||
persistence layer.</para>
|
||||
</section>
|
||||
|
||||
<section id="beans-scanning-autodetection">
|
||||
<title>Automatically detecting classes and registering bean
|
||||
definitions</title>
|
||||
|
||||
<para>Spring can automatically detect stereotyped classes and register
|
||||
corresponding <interfacename>BeanDefinition</interfacename>s with the
|
||||
<interfacename>ApplicationContext</interfacename>. For example, the
|
||||
following two classes are eligible for such autodetection:</para>
|
||||
|
||||
<programlisting language="java">@Service
|
||||
public class SimpleMovieLister {
|
||||
|
||||
private MovieFinder movieFinder;
|
||||
|
||||
@Autowired
|
||||
public SimpleMovieLister(MovieFinder movieFinder) {
|
||||
this.movieFinder = movieFinder;
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<programlisting language="java">@Repository
|
||||
public class JpaMovieFinder implements MovieFinder {
|
||||
<lineannotation>// implementation elided for clarity</lineannotation>
|
||||
}</programlisting>
|
||||
|
||||
<para>To autodetect these classes and register the corresponding beans, you
|
||||
need to include the following element in XML, where the base-package
|
||||
element is a common parent package for the two classes. (Alternatively,
|
||||
you can specify a comma-separated list that includes the parent package of
|
||||
each 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:context="http://www.springframework.org/schema/context"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/context
|
||||
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
|
||||
|
||||
<context:component-scan base-package="org.example"/>
|
||||
|
||||
</beans></programlisting>
|
||||
|
||||
<note>
|
||||
<para>The scanning of classpath packages requires the presence of
|
||||
corresponding directory entries in the classpath. When you build JARs
|
||||
with Ant, make sure that you do <emphasis>not</emphasis> activate the
|
||||
files-only switch of the JAR task.</para>
|
||||
</note>
|
||||
|
||||
<para>Furthermore, the
|
||||
<interfacename>AutowiredAnnotationBeanPostProcessor</interfacename> and
|
||||
<interfacename>CommonAnnotationBeanPostProcessor</interfacename> are both
|
||||
included implicitly when you use the component-scan element. That means
|
||||
that the two components are autodetected <emphasis>and</emphasis> wired
|
||||
together - all without any bean configuration metadata provided in
|
||||
XML.</para>
|
||||
|
||||
<note>
|
||||
<para>You can disable the registration of
|
||||
<interfacename>AutowiredAnnotationBeanPostProcessor</interfacename> and
|
||||
<interfacename>CommonAnnotationBeanPostProcessor</interfacename> by
|
||||
including the <emphasis>annotation-config</emphasis> attribute with a
|
||||
value of false.</para>
|
||||
</note>
|
||||
|
||||
<!--
|
||||
<note>
|
||||
<para>In Spring 3.0 RC1 you can use JSR 330's
|
||||
<interfacename>@Named</interfacename> annotation in place of
|
||||
stereotpye annotations and they will be automatically detected during
|
||||
component-scanning. The value of the
|
||||
<interfacename>@Named</interfacename> property will be used as the
|
||||
Bean Name. At this time Spring defaults for bean scope will be applied
|
||||
when using @Named. This behavior as well as mapping of JSR 330 and JSR
|
||||
299 scopes is planned for Spring 3.0 GA assuming the JSRs are stable
|
||||
at that time.</para>
|
||||
</note>
|
||||
-->
|
||||
</section>
|
||||
|
||||
<section id="beans-scanning-filters">
|
||||
<title>Using filters to customize scanning</title>
|
||||
|
||||
<para>By default, classes annotated with
|
||||
<interfacename>@Component</interfacename>,
|
||||
<interfacename>@Repository</interfacename>,
|
||||
<interfacename>@Service</interfacename>,
|
||||
<interfacename>@Controller</interfacename>, or a custom annotation that
|
||||
itself is annotated with <interfacename>@Component</interfacename> are the
|
||||
only detected candidate components. However, you can modify and extend
|
||||
this behavior simply by applying custom filters. Add them as
|
||||
<emphasis>include-filter</emphasis> or <emphasis>exclude-filter</emphasis>
|
||||
sub-elements of the <literal>component-scan</literal> element. Each filter
|
||||
element requires the <literal>type</literal> and
|
||||
<literal>expression</literal> attributes. The following table describes
|
||||
the filtering options.</para>
|
||||
|
||||
<table id="beans-scanning-filters-tbl">
|
||||
<title>Filter Types</title>
|
||||
|
||||
<tgroup cols="3">
|
||||
<colspec colname="c1" colwidth="1*"/>
|
||||
|
||||
<colspec colname="c2" colwidth="3*"/>
|
||||
|
||||
<colspec colname="c" colwidth="4*"/>
|
||||
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Filter Type</entry>
|
||||
|
||||
<entry>Example Expression</entry>
|
||||
|
||||
<entry>Description</entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>annotation</entry>
|
||||
|
||||
<entry><literal>org.example.SomeAnnotation</literal></entry>
|
||||
|
||||
<entry>An annotation to be present at the type level in target
|
||||
components.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>assignable</entry>
|
||||
|
||||
<entry><literal>org.example.SomeClass</literal></entry>
|
||||
|
||||
<entry>A class (or interface) that the target components are
|
||||
assignable to (extend/implement).</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>aspectj</entry>
|
||||
|
||||
<entry><literal>org.example..*Service+</literal></entry>
|
||||
|
||||
<entry>An AspectJ type expression to be matched by the target
|
||||
components.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>regex</entry>
|
||||
|
||||
<entry><literal>org\.example\.Default.*</literal></entry>
|
||||
|
||||
<entry>A regex expression to be matched by the target components
|
||||
class names.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>custom</entry>
|
||||
|
||||
<entry><literal>org.example.MyTypeFilter</literal></entry>
|
||||
|
||||
<entry>A custom implementation of the
|
||||
<interfacename>org.springframework.core.type
|
||||
.TypeFilter</interfacename> interface.</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<para>The following example shows the XML configuration ignoring all
|
||||
<interfacename>@Repository</interfacename> annotations and using "stub"
|
||||
repositories instead.</para>
|
||||
|
||||
<programlisting language="xml"><beans>
|
||||
|
||||
<context:component-scan base-package="org.example">
|
||||
<context:include-filter type="regex" expression=".*Stub.*Repository"/>
|
||||
<context:exclude-filter type="annotation"
|
||||
expression="org.springframework.stereotype.Repository"/>
|
||||
</context:component-scan>
|
||||
|
||||
</beans></programlisting>
|
||||
|
||||
<note>
|
||||
<para>You can also disable the default filters by providing
|
||||
<emphasis>use-default-filters="false"</emphasis> as an attribute of the
|
||||
<component-scan/> element. This will in effect disable automatic
|
||||
detection of classes annotated with
|
||||
<interfacename>@Component</interfacename>,
|
||||
<interfacename>@Repository</interfacename>,
|
||||
<interfacename>@Service</interfacename>, or
|
||||
<interfacename>@Controller</interfacename>.</para>
|
||||
</note>
|
||||
</section>
|
||||
|
||||
<section id="beans-factorybeans-annotations">
|
||||
<title>Defining bean metadata within components</title>
|
||||
|
||||
<para>Spring components can also contribute bean definition metadata to the
|
||||
container. You do this with the same <literal>@Bean</literal> annotation
|
||||
used to define bean metadata within <literal>@Configuration</literal>
|
||||
annotated classes. Here is a simple example:</para>
|
||||
|
||||
<programlisting language="java">@Component
|
||||
public class FactoryMethodComponent {
|
||||
|
||||
@Bean @Qualifier("public")
|
||||
public TestBean publicInstance() {
|
||||
return new TestBean("publicInstance");
|
||||
}
|
||||
|
||||
public void doWork() {
|
||||
// Component method implementation omitted
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<para>This class is a Spring component that has application-specific code
|
||||
contained in its <methodname>doWork()</methodname> method. However, it
|
||||
also contributes a bean definition that has a factory method referring to
|
||||
the method <methodname>publicInstance()</methodname>. The
|
||||
<literal>@Bean</literal> annotation identifies the factory method and
|
||||
other bean definition properties, such as a qualifier value through the
|
||||
<classname>@Qualifier</classname> annotation. Other method level
|
||||
annotations that can be specified are <literal>@Scope</literal>,
|
||||
<literal>@Lazy</literal>, and custom qualifier annotations. Autowired
|
||||
fields and methods are supported as previously discussed, with additional
|
||||
support for autowiring of <literal>@Bean</literal> methods:</para>
|
||||
|
||||
<programlisting language="java">@Component
|
||||
public class FactoryMethodComponent {
|
||||
|
||||
private static int i;
|
||||
|
||||
@Bean @Qualifier("public")
|
||||
public TestBean publicInstance() {
|
||||
return new TestBean("publicInstance");
|
||||
}
|
||||
|
||||
// use of a custom qualifier and autowiring of method parameters
|
||||
|
||||
@Bean @BeanAge(1)
|
||||
protected TestBean protectedInstance(@Qualifier("public") TestBean spouse,
|
||||
@Value("#{privateInstance.age}") String country) {
|
||||
TestBean tb = new TestBean("protectedInstance", 1);
|
||||
tb.setSpouse(tb);
|
||||
tb.setCountry(country);
|
||||
return tb;
|
||||
}
|
||||
|
||||
@Bean @Scope(BeanDefinition.SCOPE_SINGLETON)
|
||||
private TestBean privateInstance() {
|
||||
return new TestBean("privateInstance", i++);
|
||||
}
|
||||
|
||||
@Bean @Scope(value = WebApplicationContext.SCOPE_SESSION,
|
||||
proxyMode = ScopedProxyMode.TARGET_CLASS)
|
||||
public TestBean requestScopedInstance() {
|
||||
return new TestBean("requestScopedInstance", 3);
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
|
||||
<para>The example autowires the <classname>String</classname> method
|
||||
parameter <literal>country</literal> to the value of the
|
||||
<literal>Age</literal> property on another bean named
|
||||
<literal>privateInstance</literal>. A Spring Expression Language element
|
||||
defines the value of the property through the notation <literal>#{
|
||||
<expression> }</literal>. For <literal>@Value</literal> annotations,
|
||||
an expression resolver is preconfigured to look for bean names when
|
||||
resolving expression text.</para>
|
||||
|
||||
<para>The <literal>@Bean</literal> methods in a Spring component are
|
||||
processed differently than their counterparts inside a Spring
|
||||
<literal>@Configuration</literal> class. The difference is that
|
||||
<literal>@Component</literal> classes are not enhanced with CGLIB to
|
||||
intercept the invocation of methods and fields. CGLIB proxying is the
|
||||
means by which invoking methods or fields within
|
||||
<literal>@Configuration</literal> classes <literal>@Bean</literal> methods
|
||||
create bean metadata references to collaborating objects. Methods are
|
||||
<emphasis>not</emphasis> invoked with normal Java semantics. In contrast,
|
||||
calling a method or field within a <literal>@Component</literal> classes
|
||||
<literal>@Bean</literal> method <emphasis>has</emphasis> standard Java
|
||||
semantics.</para>
|
||||
</section>
|
||||
|
||||
<section id="beans-scanning-name-generator">
|
||||
<title>Naming autodetected components</title>
|
||||
|
||||
<para>When a component is autodetected as part of the scanning process, its
|
||||
bean name is generated by the
|
||||
<interfacename>BeanNameGenerator</interfacename> strategy known to that
|
||||
scanner. By default, any Spring stereotype annotation
|
||||
(<interfacename>@Component</interfacename>,
|
||||
<interfacename>@Repository</interfacename>,
|
||||
<interfacename>@Service</interfacename>, and
|
||||
<interfacename>@Controller</interfacename>) that contains a
|
||||
<literal>name</literal> value will thereby provide that name to the
|
||||
corresponding bean definition.</para>
|
||||
|
||||
<note>
|
||||
<para>JSR 330's @Named annotation can be used as a means to both detect
|
||||
components and to provide them with a name. This behavior is enabled
|
||||
automatically if you have the JSR 330 JAR on the classpath.</para>
|
||||
</note>
|
||||
|
||||
<para>If such an annotation contains no <literal>name</literal> value or for
|
||||
any other detected component (such as those discovered by custom filters),
|
||||
the default bean name generator returns the uncapitalized non-qualified
|
||||
class name. For example, if the following two components were detected,
|
||||
the names would be myMovieLister and movieFinderImpl:</para>
|
||||
|
||||
<programlisting language="java">@Service("myMovieLister")
|
||||
public class SimpleMovieLister {
|
||||
<lineannotation>// ...</lineannotation>
|
||||
}</programlisting>
|
||||
|
||||
<programlisting language="java">@Repository
|
||||
public class MovieFinderImpl implements MovieFinder {
|
||||
<lineannotation>// ...</lineannotation>
|
||||
}</programlisting>
|
||||
|
||||
<note>
|
||||
<para>If you do not want to rely on the default bean-naming strategy, you
|
||||
can provide a custom bean-naming strategy. First, implement the <ulink
|
||||
url="http://static.springframework.org/spring/docs/3.0.x/javadoc-api/org/springframework/beans/factory/support/BeanNameGenerator.html"
|
||||
><interfacename>BeanNameGenerator</interfacename></ulink> interface, and
|
||||
be sure to include a default no-arg constructor. Then, provide the
|
||||
fully-qualified class name when configuring the scanner:</para>
|
||||
</note>
|
||||
|
||||
<programlisting language="xml"><beans>
|
||||
|
||||
<context:component-scan base-package="org.example"
|
||||
name-generator="org.example.MyNameGenerator" />
|
||||
|
||||
</beans></programlisting>
|
||||
|
||||
<para>As a general rule, consider specifying the name with the annotation
|
||||
whenever other components may be making explicit references to it. On the
|
||||
other hand, the auto-generated names are adequate whenever the container
|
||||
is responsible for wiring.</para>
|
||||
</section>
|
||||
|
||||
<section id="beans-scanning-scope-resolver">
|
||||
<title>Providing a scope for autodetected components</title>
|
||||
|
||||
<para>As with Spring-managed components in general, the default and most
|
||||
common scope for autodetected components is singleton. However, sometimes
|
||||
you need other scopes, which Spring 2.5 provides with a new
|
||||
<interfacename>@Scope</interfacename> annotation. Simply provide the name
|
||||
of the scope within the annotation:</para>
|
||||
|
||||
<programlisting language="java">@Scope("prototype")
|
||||
@Repository
|
||||
public class MovieFinderImpl implements MovieFinder {
|
||||
<lineannotation>// ...</lineannotation>
|
||||
}</programlisting>
|
||||
|
||||
<note>
|
||||
<para>To provide a custom strategy for scope resolution rather than
|
||||
relying on the annotation-based approach, implement the <ulink
|
||||
url="http://static.springframework.org/spring/docs/3.0.x/javadoc-api/org/springframework/context/annotation/ScopeMetadataResolver.html"
|
||||
><interfacename>ScopeMetadataResolver</interfacename></ulink> interface,
|
||||
and be sure to include a default no-arg constructor. Then, provide the
|
||||
fully-qualified class name when configuring the scanner:</para>
|
||||
</note>
|
||||
|
||||
<programlisting language="xml"><beans>
|
||||
|
||||
<context:component-scan base-package="org.example"
|
||||
scope-resolver="org.example.MyScopeResolver" />
|
||||
|
||||
</beans></programlisting>
|
||||
|
||||
<para>When using certain non-singleton scopes, it may be necessary to
|
||||
generate proxies for the scoped objects. The reasoning is described in
|
||||
<xref linkend="beans-factory-scopes-other-injection"/>. For this purpose,
|
||||
a <emphasis>scoped-proxy</emphasis> attribute is available on the
|
||||
component-scan element. The three possible values are: no, interfaces, and
|
||||
targetClass. For example, the following configuration will result in
|
||||
standard JDK dynamic proxies:</para>
|
||||
|
||||
<programlisting language="xml"><beans>
|
||||
|
||||
<context:component-scan base-package="org.example"
|
||||
scoped-proxy="interfaces" />
|
||||
|
||||
</beans></programlisting>
|
||||
</section>
|
||||
|
||||
<section id="beans-scanning-qualifiers">
|
||||
<title>Providing qualifier metadata with annotations</title>
|
||||
|
||||
<para>The <interfacename>@Qualifier</interfacename> annotation is discussed
|
||||
in <xref linkend="beans-autowired-annotation-qualifiers"/>. The examples
|
||||
in that section demonstrate the use of the
|
||||
<interfacename>@Qualifier</interfacename> annotation and custom qualifier
|
||||
annotations to provide fine-grained control when you resolve autowire
|
||||
candidates. Because those examples were based on XML bean definitions, the
|
||||
qualifier metadata was provided on the candidate bean definitions using
|
||||
the <literal>qualifier</literal> or <literal>meta</literal> sub-elements
|
||||
of the <literal>bean</literal> element in the XML. When relying upon
|
||||
classpath scanning for autodetection of components, you provide the
|
||||
qualifier metadata with type-level annotations on the candidate class. The
|
||||
following three examples demonstrate this technique:</para>
|
||||
|
||||
<programlisting language="java">@Component
|
||||
<emphasis role="bold">@Qualifier("Action")</emphasis>
|
||||
public class ActionMovieCatalog implements MovieCatalog {
|
||||
<lineannotation>// ...</lineannotation>
|
||||
}</programlisting>
|
||||
|
||||
<programlisting language="java">@Component
|
||||
<emphasis role="bold">@Genre("Action")</emphasis>
|
||||
public class ActionMovieCatalog implements MovieCatalog {
|
||||
<lineannotation>// ...</lineannotation>
|
||||
}</programlisting>
|
||||
|
||||
<programlisting language="java">@Component
|
||||
<emphasis role="bold">@Offline</emphasis>
|
||||
public class CachingMovieCatalog implements MovieCatalog {
|
||||
<lineannotation>// ...</lineannotation>
|
||||
}</programlisting>
|
||||
|
||||
<note>
|
||||
<para>As with most annotation-based alternatives, keep in mind that the
|
||||
annotation metadata is bound to the class definition itself, while the
|
||||
use of XML allows for multiple beans <emphasis>of the same
|
||||
type</emphasis> to provide variations in their qualifier metadata,
|
||||
because that metadata is provided per-instance rather than
|
||||
per-class.</para>
|
||||
</note>
|
||||
</section>
|
||||
</section>
|
||||
|
|
@ -0,0 +1,663 @@
|
|||
<?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="context-introduction">
|
||||
<title>Additional Capabilities of the
|
||||
<interfacename>ApplicationContext</interfacename></title>
|
||||
|
||||
<!-- MLP: Beverly to review paragraph and list -->
|
||||
|
||||
<para>As was discussed in the chapter introduction, the
|
||||
<literal>org.springframework.beans.factory</literal> package provides basic
|
||||
functionality for managing and manipulating beans, including in a
|
||||
programmatic way. The <literal>org.springframework.context</literal> package
|
||||
adds the <ulink
|
||||
url="http://static.springframework.org/spring/docs/3.0.x/javadoc-api/org/springframework/context/ApplicationContext.html"
|
||||
><interfacename>ApplicationContext</interfacename></ulink> interface, which
|
||||
extends the <interfacename>BeanFactory</interfacename> interface, in
|
||||
addition to extending other interfaces to provide additional functionality
|
||||
in a more <emphasis>application framework-oriented style</emphasis>. Many
|
||||
people use the <interfacename>ApplicationContext</interfacename> in a
|
||||
completely declarative fashion, not even creating it programmatically, but
|
||||
instead relying on support classes such as
|
||||
<classname>ContextLoader</classname> to automatically instantiate an
|
||||
<interfacename>ApplicationContext</interfacename> as part of the normal
|
||||
startup process of a J2EE web application.</para>
|
||||
|
||||
<para>To enhance <interfacename>BeanFactory</interfacename> functionality in a
|
||||
more framework-oriented style the context package also provides the
|
||||
following functionality:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><emphasis>Access to messages in i18n-style</emphasis>, through the
|
||||
<interfacename>MessageSource</interfacename> interface.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><emphasis>Access to resources</emphasis>, such as URLs and files,
|
||||
through the <interfacename>ResourceLoader</interfacename>
|
||||
interface.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><emphasis>Event publication</emphasis> to beans implementing the
|
||||
<interfacename>ApplicationListener</interfacename> interface, through
|
||||
the use of the <interfacename>ApplicationEventPublisher</interfacename>
|
||||
interface.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><emphasis>Loading of multiple (hierarchical) contexts</emphasis>,
|
||||
allowing each to be focused on one particular layer, such as the web
|
||||
layer of an application, through the
|
||||
<interfacename>HierarchicalBeanFactory</interfacename> interface.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<section id="context-functionality-messagesource">
|
||||
<title>Internationalization using
|
||||
<interfacename>MessageSource</interfacename></title>
|
||||
|
||||
<!-- MLP: Beverly to review this paragraph -->
|
||||
|
||||
<para>The <interfacename>ApplicationContext</interfacename> interface
|
||||
extends an interface called <interfacename>MessageSource</interfacename>,
|
||||
and therefore provides internationalization (i18n) functionality. Spring
|
||||
also provides the interface
|
||||
<classname>HierarchicalMessageSource</classname>, which can resolve
|
||||
messages hierarchically. Together these interfaces provide the foundation
|
||||
upon which Spring effects message resolution. The methods defined on these
|
||||
interfaces include:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><methodname>String getMessage(String code, Object[] args, String
|
||||
default, Locale loc)</methodname>: The basic method used to retrieve a
|
||||
message from the <interfacename>MessageSource</interfacename>. When no
|
||||
message is found for the specified locale, the default message is
|
||||
used. Any arguments passed in become replacement values, using the
|
||||
<interfacename>MessageFormat</interfacename> functionality provided by
|
||||
the standard library.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><methodname>String getMessage(String code, Object[] args, Locale
|
||||
loc)</methodname>: Essentially the same as the previous method, but
|
||||
with one difference: no default message can be specified; if the
|
||||
message cannot be found, a
|
||||
<classname>NoSuchMessageException</classname> is thrown.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><methodname>String getMessage(MessageSourceResolvable resolvable,
|
||||
Locale locale)</methodname>: All properties used in the preceding
|
||||
methods are also wrapped in a class named
|
||||
<interfacename>MessageSourceResolvable</interfacename>, which you can
|
||||
use with this method.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>When an <interfacename>ApplicationContext</interfacename> is loaded,
|
||||
it automatically searches for a
|
||||
<interfacename>MessageSource</interfacename> bean defined in the context.
|
||||
The bean must have the name <literal>messageSource</literal>. If such a
|
||||
bean is found, all calls to the preceding methods are delegated to the
|
||||
message source. If no message source is found, the
|
||||
<interfacename>ApplicationContext</interfacename> attempts to find a
|
||||
parent containing a bean with the same name. If it does, it uses that bean
|
||||
as the <interfacename>MessageSource</interfacename>. If the
|
||||
<interfacename>ApplicationContext</interfacename> cannot find any source
|
||||
for messages, an empty <classname>DelegatingMessageSource</classname> is
|
||||
instantiated in order to be able to accept calls to the methods defined
|
||||
above.</para>
|
||||
|
||||
<para>Spring provides two <interfacename>MessageSource</interfacename>
|
||||
implementations, <classname>ResourceBundleMessageSource</classname> and
|
||||
<classname>StaticMessageSource</classname>. Both implement
|
||||
<interfacename>HierarchicalMessageSource</interfacename> in order to do
|
||||
nested messaging. The <classname>StaticMessageSource</classname> is rarely
|
||||
used but provides programmatic ways to add messages to the source. The
|
||||
<classname>ResourceBundleMessageSource</classname> is shown in the
|
||||
following example:</para>
|
||||
|
||||
<programlisting language="xml"><beans>
|
||||
<bean id="messageSource"
|
||||
class="org.springframework.context.support.ResourceBundleMessageSource">
|
||||
<property name="basenames">
|
||||
<list>
|
||||
<value>format</value>
|
||||
<value>exceptions</value>
|
||||
<value>windows</value>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
</beans></programlisting>
|
||||
|
||||
<para>In the example it is assumed you have three resource bundles defined
|
||||
in your classpath called <literal>format</literal>,
|
||||
<literal>exceptions</literal> and <literal>windows</literal>. Any request
|
||||
to resolve a message will be handled in the JDK standard way of resolving
|
||||
messages through ResourceBundles. For the purposes of the example, assume
|
||||
the contents of two of the above resource bundle files are...</para>
|
||||
|
||||
<programlisting language="java"><lineannotation># in format.properties</lineannotation>
|
||||
message=Alligators rock!</programlisting>
|
||||
|
||||
<programlisting language="java"><lineannotation># in exceptions.properties</lineannotation>
|
||||
argument.required=The '{0}' argument is required.</programlisting>
|
||||
|
||||
<para>A program to execute the <classname>MessageSource</classname>
|
||||
functionality is shown in the next example. Remember that all
|
||||
<classname>ApplicationContext</classname> implementations are also
|
||||
<classname>MessageSource</classname> implementations and so can be cast to
|
||||
the <classname>MessageSource</classname> interface.</para>
|
||||
|
||||
<programlisting language="java">public static void main(String[] args) {
|
||||
MessageSource resources = new ClassPathXmlApplicationContext("beans.xml");
|
||||
String message = resources.getMessage("message", null, "Default", null);
|
||||
System.out.println(message);
|
||||
}</programlisting>
|
||||
|
||||
<para>The resulting output from the above program will be...</para>
|
||||
|
||||
<programlisting>Alligators rock!</programlisting>
|
||||
|
||||
<para>So to summarize, the <classname>MessageSource</classname> is defined
|
||||
in a file called <literal>beans.xml</literal>, which exists at the root of
|
||||
your classpath. The <literal>messageSource</literal> bean definition
|
||||
refers to a number of resource bundles through its
|
||||
<literal>basenames</literal> property. The three files that are passed in
|
||||
the list to the <literal>basenames</literal> property exist as files at
|
||||
the root of your classpath and are called
|
||||
<literal>format.properties</literal>,
|
||||
<literal>exceptions.properties</literal>, and
|
||||
<literal>windows.properties</literal> respectively.</para>
|
||||
|
||||
<para>The next example shows arguments passed to the message lookup; these
|
||||
arguments will be converted into Strings and inserted into placeholders in
|
||||
the lookup message.</para>
|
||||
|
||||
<programlisting language="xml"><beans>
|
||||
|
||||
<lineannotation><!-- this <interfacename>MessageSource</interfacename> is being used in a web application --></lineannotation>
|
||||
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
|
||||
<property name="basename" value="test-messages"/>
|
||||
</bean>
|
||||
|
||||
<lineannotation><!-- lets inject the above <interfacename>MessageSource</interfacename> into this POJO --></lineannotation>
|
||||
<bean id="example" class="com.foo.Example">
|
||||
<property name="messages" ref="messageSource"/>
|
||||
</bean>
|
||||
|
||||
</beans></programlisting>
|
||||
|
||||
<programlisting language="java">public class Example {
|
||||
|
||||
private MessageSource messages;
|
||||
|
||||
public void setMessages(MessageSource messages) {
|
||||
this.messages = messages;
|
||||
}
|
||||
|
||||
public void execute() {
|
||||
String message = this.messages.getMessage("argument.required",
|
||||
new Object [] {"userDao"}, "Required", null);
|
||||
System.out.println(message);
|
||||
}
|
||||
|
||||
}</programlisting>
|
||||
|
||||
<para>The resulting output from the invocation of the
|
||||
<methodname>execute()</methodname> method will be...</para>
|
||||
|
||||
<programlisting>The userDao argument is required.</programlisting>
|
||||
|
||||
<para>With regard to internationalization (i18n), Spring's various
|
||||
<classname>MessageResource</classname> implementations follow the same
|
||||
locale resolution and fallback rules as the standard JDK
|
||||
<classname>ResourceBundle</classname>. In short, and continuing with the
|
||||
example <literal>messageSource</literal> defined previously, if you want
|
||||
to resolve messages against the British (en-GB) locale, you would create
|
||||
files called <literal>format_en_GB.properties</literal>,
|
||||
<literal>exceptions_en_GB.properties</literal>, and
|
||||
<literal>windows_en_GB.properties</literal> respectively.</para>
|
||||
|
||||
<para>Typically, locale resolution is managed by the surrounding environment
|
||||
of the application. In this example, the locale against which (British)
|
||||
messages will be resolved is specified manually.</para>
|
||||
|
||||
<programlisting><lineannotation># in exceptions_en_GB.properties</lineannotation>
|
||||
argument.required=Ebagum lad, the '{0}' argument is required, I say, required.</programlisting>
|
||||
|
||||
<programlisting language="java">public static void main(final String[] args) {
|
||||
MessageSource resources = new ClassPathXmlApplicationContext("beans.xml");
|
||||
String message = resources.getMessage("argument.required",
|
||||
new Object [] {"userDao"}, "Required", Locale.UK);
|
||||
System.out.println(message);
|
||||
}</programlisting>
|
||||
|
||||
<para>The resulting output from the running of the above program will
|
||||
be...</para>
|
||||
|
||||
<programlisting>Ebagum lad, the 'userDao' argument is required, I say, required.</programlisting>
|
||||
|
||||
<para>You can also use the <classname>MessageSourceAware</classname>
|
||||
interface to acquire a reference to any
|
||||
<classname>MessageSource</classname> that has been defined. Any bean that
|
||||
is defined in an <classname>ApplicationContext</classname> that implements
|
||||
the <classname>MessageSourceAware</classname> interface is injected with
|
||||
the application context's <classname>MessageSource</classname> when the
|
||||
bean is created and configured.</para>
|
||||
|
||||
<note>
|
||||
<para><emphasis>As an alternative to
|
||||
<classname>ResourceBundleMessageSource</classname>, Spring provides a
|
||||
<classname>ReloadableResourceBundleMessageSource</classname> class. This
|
||||
variant supports the same bundle file format but is more flexible than
|
||||
the standard JDK based
|
||||
<classname>ResourceBundleMessageSource</classname>
|
||||
implementation.</emphasis> In particular, it allows for reading files
|
||||
from any Spring resource location (not just from the classpath) and
|
||||
supports hot reloading of bundle property files (while efficiently
|
||||
caching them in between). Check out the
|
||||
<classname>ReloadableResourceBundleMessageSource</classname> javadoc for
|
||||
details.</para>
|
||||
</note>
|
||||
</section>
|
||||
|
||||
<section id="context-functionality-events">
|
||||
<title>Standard and Custom Events</title>
|
||||
|
||||
<para>Event handling in the
|
||||
<interfacename>ApplicationContext</interfacename> is provided through the
|
||||
<classname>ApplicationEvent</classname> class and
|
||||
<interfacename>ApplicationListener</interfacename> interface. If a bean
|
||||
that implements the <interfacename>ApplicationListener</interfacename>
|
||||
interface is deployed into the context, every time an
|
||||
<classname>ApplicationEvent</classname> gets published to the
|
||||
<interfacename>ApplicationContext</interfacename>, that bean is notified.
|
||||
Essentially, this is the standard <emphasis>Observer</emphasis> design
|
||||
pattern. Spring provides the following standard events:</para>
|
||||
|
||||
<table id="beans-ctx-events-tbl">
|
||||
<title>Built-in Events</title>
|
||||
|
||||
<tgroup cols="2">
|
||||
<colspec colname="c1" colwidth="2*"/>
|
||||
|
||||
<colspec colname="c2" colwidth="5*"/>
|
||||
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Event</entry>
|
||||
|
||||
<entry>Explanation</entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><classname>ContextRefreshedEvent</classname></entry>
|
||||
|
||||
<entry>Published when the
|
||||
<interfacename>ApplicationContext</interfacename> is initialized
|
||||
or refreshed, for example, using the
|
||||
<methodname>refresh()</methodname> method on the
|
||||
<interfacename>ConfigurableApplicationContext</interfacename>
|
||||
interface. "Initialized" here means that all beans are loaded,
|
||||
post-processor beans are detected and activated, singletons are
|
||||
pre-instantiated, and the
|
||||
<interfacename>ApplicationContext</interfacename> object is ready
|
||||
for use. As long as the context has not been closed, a refresh can
|
||||
be triggered multiple times, provided that the chosen
|
||||
<interfacename>ApplicationContext</interfacename> actually
|
||||
supports such "hot" refreshes. For example,
|
||||
<classname>XmlWebApplicationContext</classname> supports hot
|
||||
refreshes, but <classname>GenericApplicationContext</classname>
|
||||
does not.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><classname>ContextStartedEvent</classname></entry>
|
||||
|
||||
<entry>Published when the
|
||||
<interfacename>ApplicationContext</interfacename> is started,
|
||||
using the <methodname>start()</methodname> method on the
|
||||
<interfacename>ConfigurableApplicationContext</interfacename>
|
||||
interface. "Started" here means that all
|
||||
<interfacename>Lifecycle</interfacename> beans receive an explicit
|
||||
start signal. Typically this signal is used to restart beans after
|
||||
an explicit stop, but it may also be used to start components that
|
||||
have not been configured for autostart , for example, components
|
||||
that have not already started on initialization.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><classname>ContextStoppedEvent</classname></entry>
|
||||
|
||||
<entry>Published when the
|
||||
<interfacename>ApplicationContext</interfacename> is stopped,
|
||||
using the <methodname>stop()</methodname> method on the
|
||||
<interfacename>ConfigurableApplicationContext</interfacename>
|
||||
interface. "Stopped" here means that all
|
||||
<interfacename>Lifecycle</interfacename> beans receive an explicit
|
||||
stop signal. A stopped context may be restarted through a
|
||||
<methodname>start()</methodname> call.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><classname>ContextClosedEvent</classname></entry>
|
||||
|
||||
<entry>Published when the
|
||||
<interfacename>ApplicationContext</interfacename> is closed, using
|
||||
the <methodname>close()</methodname> method on the
|
||||
<interfacename>ConfigurableApplicationContext</interfacename>
|
||||
interface. "Closed" here means that all singleton beans are
|
||||
destroyed. A closed context reaches its end of life; it cannot be
|
||||
refreshed or restarted.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><classname>RequestHandledEvent</classname></entry>
|
||||
|
||||
<entry>A web-specific event telling all beans that an HTTP request
|
||||
has been serviced. This event is published
|
||||
<emphasis>after</emphasis> the request is complete. This event is
|
||||
only applicable to web applications using Spring's
|
||||
<classname>DispatcherServlet</classname>.</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<para>You can also create and publish your own custom events. This example
|
||||
demonstrates a simple class that extends Spring's
|
||||
<classname>ApplicationEvent</classname> base class:</para>
|
||||
|
||||
<programlisting language="java">public class BlackListEvent extends ApplicationEvent {
|
||||
private final String address;
|
||||
private final String test;
|
||||
|
||||
public BlackListEvent(Object source, String address, String test) {
|
||||
super(source);
|
||||
this.address = address;
|
||||
this.test = test;
|
||||
}
|
||||
|
||||
<lineannotation>// accessor and other methods...</lineannotation>
|
||||
}</programlisting>
|
||||
|
||||
<para>To publish a custom <classname>ApplicationEvent</classname>, call the
|
||||
<methodname>publishEvent()</methodname> method on an
|
||||
<interfacename>ApplicationEventPublisher</interfacename>. Typically this
|
||||
is done by creating a class that implements
|
||||
<interfacename>ApplicationEventPublisherAware</interfacename> and
|
||||
registering it as a Spring bean. The following example demonstrates such a
|
||||
class:</para>
|
||||
|
||||
<programlisting language="java"><![CDATA[public class EmailService implements ApplicationEventPublisherAware {
|
||||
|
||||
private List<String> blackList;
|
||||
private ApplicationEventPublisher publisher;
|
||||
|
||||
public void setBlackList(List<String> blackList) {
|
||||
this.blackList = blackList;
|
||||
}
|
||||
|
||||
public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
|
||||
this.publisher = publisher;
|
||||
}
|
||||
|
||||
public void sendEmail(String address, String text) {
|
||||
if (blackList.contains(address)) {
|
||||
BlackListEvent event = new BlackListEvent(this, address, text);
|
||||
publisher.publishEvent(event);
|
||||
return;
|
||||
}
|
||||
]]><lineannotation>// send email...</lineannotation><![CDATA[
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
<para>At configuration time, the Spring container will detect that
|
||||
<classname>EmailService</classname> implements
|
||||
<interfacename>ApplicationEventPublisherAware</interfacename> and will
|
||||
automatically call
|
||||
<methodname>setApplicationEventPublisher()</methodname>. In reality, the
|
||||
parameter passed in will be the Spring container itself; you're simply
|
||||
interacting with the application context via its
|
||||
<interfacename>ApplicationEventPublisher</interfacename> interface.</para>
|
||||
|
||||
<para>To receive the custom <classname>ApplicationEvent</classname>, create
|
||||
a class that implements <interfacename>ApplicationListener</interfacename>
|
||||
and register it as a Spring bean. The following example demonstrates such
|
||||
a class:</para>
|
||||
|
||||
<programlisting language="java"><![CDATA[public class BlackListNotifier implements ApplicationListener<BlackListEvent> {
|
||||
|
||||
private String notificationAddress;
|
||||
|
||||
public void setNotificationAddress(String notificationAddress) {
|
||||
this.notificationAddress = notificationAddress;
|
||||
}
|
||||
|
||||
public void onApplicationEvent(BlackListEvent event) {
|
||||
]]><lineannotation> // notify appropriate parties via notificationAddress...</lineannotation><![CDATA[
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
<para>Notice that <interfacename>ApplicationListener</interfacename> is
|
||||
generically parameterized with the type of your custom event,
|
||||
<classname>BlackListEvent</classname>. This means that the
|
||||
<methodname>onApplicationEvent()</methodname> method can remain type-safe,
|
||||
avoiding any need for downcasting. You may register as many event
|
||||
listeners as you wish, but note that by default event listeners receive
|
||||
events synchronously. This means the
|
||||
<methodname>publishEvent()</methodname> method blocks until all listeners
|
||||
have finished processing the event. One advantage of this synchronous and
|
||||
single-threaded approach is that when a listener receives an event, it
|
||||
operates inside the transaction context of the publisher if a transaction
|
||||
context is available. If another strategy for event publication becomes
|
||||
necessary, refer to the JavaDoc for Spring's
|
||||
<interfacename>ApplicationEventMulticaster</interfacename>
|
||||
interface.</para>
|
||||
|
||||
<para>The following example demonstrates the bean definitions used to
|
||||
register and configure each of the classes above:</para>
|
||||
<programlisting language="xml"><![CDATA[<bean id="emailService" class="example.EmailService">
|
||||
<property name="blackList">
|
||||
<list>
|
||||
<value>black@list.org</value>
|
||||
<value>white@list.org</value>
|
||||
<value>john@doe.org</value>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="blackListNotifier" class="example.BlackListNotifier">
|
||||
<property name="notificationAddress" value="spam@list.org"/>
|
||||
</bean>]]></programlisting>
|
||||
|
||||
<para>Putting it all together, when the <methodname>sendEmail()</methodname>
|
||||
method of the <literal>emailService</literal> bean is called, if there are
|
||||
any emails that should be blacklisted, a custom event of type
|
||||
<classname>BlackListEvent</classname> is published. The
|
||||
<literal>blackListNotifier</literal> bean is registered as an
|
||||
<interfacename>ApplicationListener</interfacename> and thus receives the
|
||||
<classname>BlackListEvent</classname>, at which point it can notify
|
||||
appropriate parties.</para>
|
||||
|
||||
<note>
|
||||
<para>Spring's eventing mechanism is designed for simple communication
|
||||
between Spring beans within the same application context. However, for
|
||||
more sophisticated enterprise integration needs, the
|
||||
separately-maintained <ulink
|
||||
url="http://springsource.org/spring-integration">Spring
|
||||
Integration</ulink> project provides complete support for building
|
||||
lightweight, <ulink url="http://www.enterpriseintegrationpatterns.com"
|
||||
>pattern-oriented</ulink>, event-driven architectures that build upon
|
||||
the well-known Spring programming model.</para>
|
||||
</note>
|
||||
</section>
|
||||
|
||||
<section id="context-functionality-resources">
|
||||
<title>Convenient access to low-level resources</title>
|
||||
|
||||
<para>For optimal usage and understanding of application contexts, users
|
||||
should generally familiarize themselves with Spring's
|
||||
<interfacename>Resource</interfacename> abstraction, as described in the
|
||||
chapter <xref linkend="resources"/>.</para>
|
||||
|
||||
<para>An application context is a
|
||||
<interfacename>ResourceLoader</interfacename>, which can be used to load
|
||||
<interfacename>Resource</interfacename>s. A
|
||||
<interfacename>Resource</interfacename> is essentially a more feature rich
|
||||
version of the JDK class <literal>java.net.URL</literal>, in fact, the
|
||||
implementations of the <interfacename>Resource</interfacename> wrap an
|
||||
instance of <literal>java.net.URL</literal> where appropriate. A
|
||||
<interfacename>Resource</interfacename> can obtain low-level resources
|
||||
from almost any location in a transparent fashion, including from the
|
||||
classpath, a filesystem location, anywhere describable with a standard
|
||||
URL, and some other variations. If the resource location string is a
|
||||
simple path without any special prefixes, where those resources come from
|
||||
is specific and appropriate to the actual application context type.</para>
|
||||
|
||||
<para>You can configure a bean deployed into the application context to
|
||||
implement the special callback interface,
|
||||
<interfacename>ResourceLoaderAware</interfacename>, to be automatically
|
||||
called back at initialization time with the application context itself
|
||||
passed in as the <interfacename>ResourceLoader</interfacename>. You can
|
||||
also expose properties of type <interfacename>Resource</interfacename>, to
|
||||
be used to access static resources; they will be injected into it like any
|
||||
other properties. You can specify those
|
||||
<interfacename>Resource</interfacename> properties as simple String paths,
|
||||
and rely on a special JavaBean
|
||||
<interfacename>PropertyEditor</interfacename> that is automatically
|
||||
registered by the context, to convert those text strings to actual
|
||||
<interfacename>Resource</interfacename> objects when the bean is
|
||||
deployed.</para>
|
||||
|
||||
<para>The location path or paths supplied to an
|
||||
<interfacename>ApplicationContext</interfacename> constructor are actually
|
||||
resource strings, and in simple form are treated appropriately to the
|
||||
specific context implementation.
|
||||
<classname>ClassPathXmlApplicationContext</classname> treats a simple
|
||||
location path as a classpath location. You can also use location paths
|
||||
(resource strings) with special prefixes to force loading of definitions
|
||||
from the classpath or a URL, regardless of the actual context type.</para>
|
||||
</section>
|
||||
|
||||
<section id="context-create">
|
||||
<title>Convenient <interfacename>ApplicationContext</interfacename>
|
||||
instantiation for web applications</title>
|
||||
|
||||
<para>You can create <interfacename>ApplicationContext</interfacename>
|
||||
instances declaratively by using, for example, a
|
||||
<classname>ContextLoader</classname>. Of course you can also create
|
||||
<interfacename>ApplicationContext</interfacename> instances
|
||||
programmatically by using one of the
|
||||
<interfacename>ApplicationContext</interfacename> implementations.</para>
|
||||
|
||||
<para>The <classname>ContextLoader</classname> mechanism comes in two
|
||||
flavors: the <classname>ContextLoaderListener</classname> and the
|
||||
<classname>ContextLoaderServlet</classname>. They have the same
|
||||
functionality but differ in that the listener version is not reliable in
|
||||
Servlet 2.3 containers. In the Servlet 2.4 specification, Servlet context
|
||||
listeners must execute immediately after the Servlet context for the web
|
||||
application is created and is available to service the first request (and
|
||||
also when the Servlet context is about to be shut down). As such a Servlet
|
||||
context listener is an ideal place to initialize the Spring
|
||||
<interfacename>ApplicationContext</interfacename>. All things being equal,
|
||||
you should probably prefer <classname>ContextLoaderListener</classname>;
|
||||
for more information on compatibility, have a look at the Javadoc for the
|
||||
<classname>ContextLoaderServlet</classname>.</para>
|
||||
|
||||
<para>You can register an <interfacename>ApplicationContext</interfacename>
|
||||
using the <classname>ContextLoaderListener</classname> as follows:</para>
|
||||
|
||||
<programlisting language="xml"><context-param>
|
||||
<param-name>contextConfigLocation</param-name>
|
||||
<param-value>/WEB-INF/daoContext.xml /WEB-INF/applicationContext.xml</param-value>
|
||||
</context-param>
|
||||
|
||||
<listener>
|
||||
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
|
||||
</listener>
|
||||
|
||||
<lineannotation><!-- or use the <classname>ContextLoaderServlet</classname> instead of the above listener</lineannotation><emphasis>
|
||||
<servlet>
|
||||
<servlet-name>context</servlet-name>
|
||||
<servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
</servlet>
|
||||
--</emphasis>></programlisting>
|
||||
|
||||
<para>The listener inspects the <literal>contextConfigLocation</literal>
|
||||
parameter. If the parameter does not exist, the listener uses
|
||||
<literal>/WEB-INF/applicationContext.xml</literal> as a default. When the
|
||||
parameter <emphasis>does</emphasis> exist, the listener separates the
|
||||
String by using predefined delimiters (comma, semicolon and whitespace)
|
||||
and uses the values as locations where application contexts will be
|
||||
searched. Ant-style path patterns are supported as well. Examples are
|
||||
<literal>/WEB-INF/*Context.xml</literal> for all files with names ending
|
||||
with "Context.xml", residing in the "WEB-INF" directory, and
|
||||
<literal>/WEB-INF/**/*Context.xml</literal>, for all such files in any
|
||||
subdirectory of "WEB-INF".</para>
|
||||
|
||||
<para>You can use <classname>ContextLoaderServlet</classname> instead of
|
||||
<classname>ContextLoaderListener</classname>. The Servlet uses the
|
||||
<literal>contextConfigLocation</literal> parameter just as the listener
|
||||
does.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Deploying a Spring ApplicationContext as a J2EE RAR file</title>
|
||||
|
||||
<para>In Spring 2.5 and later, it is possible to deploy a Spring
|
||||
ApplicationContext as a RAR file, encapsulating the context and all of its
|
||||
required bean classes and library JARs in a J2EE RAR deployment unit. This
|
||||
is the equivalent of bootstrapping a standalone ApplicationContext, just
|
||||
hosted in J2EE environment, being able to access the J2EE servers
|
||||
facilities. RAR deployment is a more natural alternative to scenario of
|
||||
deploying a headless WAR file, in effect, a WAR file without any HTTP
|
||||
entry points that is used only for bootstrapping a Spring
|
||||
ApplicationContext in a J2EE environment.</para>
|
||||
|
||||
<para>RAR deployment is ideal for application contexts that do not need HTTP
|
||||
entry points but rather consist only of message endpoints and scheduled
|
||||
jobs. Beans in such a context can use application server resources such as
|
||||
the JTA transaction manager and JNDI-bound JDBC DataSources and JMS
|
||||
ConnectionFactory instances, and may also register with the platform's JMX
|
||||
server - all through Spring's standard transaction management and JNDI and
|
||||
JMX support facilities. Application components can also interact with the
|
||||
application server's JCA WorkManager through Spring's
|
||||
<interfacename>TaskExecutor</interfacename> abstraction.</para>
|
||||
|
||||
<para>Check out the JavaDoc of the <ulink
|
||||
url="http://static.springframework.org/spring/docs/3.0.x/javadoc-api/org/springframework/jca/context/SpringContextResourceAdapter.html"
|
||||
>SpringContextResourceAdapter</ulink> class for the configuration details
|
||||
involved in RAR deployment.</para>
|
||||
|
||||
<para><emphasis>For a simple deployment of a Spring ApplicationContext as a
|
||||
J2EE RAR file:</emphasis> package all application classes into a RAR file,
|
||||
which is a standard JAR file with a different file extension. Add all
|
||||
required library JARs into the root of the RAR archive. Add a
|
||||
"META-INF/ra.xml" deployment descriptor (as shown in
|
||||
<classname>SpringContextResourceAdapter</classname>s JavaDoc) and the
|
||||
corresponding Spring XML bean definition file(s) (typically
|
||||
"META-INF/applicationContext.xml"), and drop the resulting RAR file into
|
||||
your application server's deployment directory.</para>
|
||||
|
||||
<note>
|
||||
<para>Such RAR deployment units are usually self-contained; they do not
|
||||
expose components to the outside world, not even to other modules of the
|
||||
same application. Interaction with a RAR-based ApplicationContext
|
||||
usually occurs through JMS destinations that it shares with other
|
||||
modules. A RAR-based ApplicationContext may also, for example, schedule
|
||||
some jobs, reacting to new files in the file system (or the like). If it
|
||||
needs to allow synchronous access from the outside, it could for example
|
||||
export RMI endpoints, which of course may be used by other application
|
||||
modules on the same machine.</para>
|
||||
</note>
|
||||
</section>
|
||||
</section>
|
||||
|
|
@ -0,0 +1,665 @@
|
|||
<?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-nature">
|
||||
<title>Customizing the nature of a bean</title>
|
||||
|
||||
<section id="beans-factory-lifecycle">
|
||||
<title>Lifecycle callbacks</title>
|
||||
|
||||
<!-- MLP Beverly to review: Old Text: The Spring Framework provides several callback interfaces to
|
||||
change the behavior of your bean in the container; they include -->
|
||||
|
||||
<para>To interact with the container's management of the bean lifecycle, you
|
||||
can implement the Spring <interfacename>InitializingBean</interfacename>
|
||||
and <interfacename>DisposableBean</interfacename> interfaces. The
|
||||
container calls <methodname>afterPropertiesSet()</methodname> for the
|
||||
former and <methodname>destroy()</methodname> for the latter to allow the
|
||||
bean to perform certain actions upon initialization and destruction of
|
||||
your beans. You can also achieve the same integration with the container
|
||||
without coupling your classes to Spring interfaces through the use of
|
||||
init-method and destroy method object definition metadata.</para>
|
||||
|
||||
<para>Internally, the Spring Framework uses
|
||||
<interfacename>BeanPostProcessor</interfacename> implementations to
|
||||
process any callback interfaces it can find and call the appropriate
|
||||
methods. If you need custom features or other lifecycle behavior Spring
|
||||
does not offer out-of-the-box, you can implement a
|
||||
<interfacename>BeanPostProcessor</interfacename> yourself. For more
|
||||
information, see <xref linkend="beans-factory-extension"/>.</para>
|
||||
|
||||
<para>In addition to the initialization and destruction callbacks,
|
||||
Spring-managed objects may also implement the
|
||||
<interfacename>Lifecycle</interfacename> interface so that those objects
|
||||
can participate in the startup and shutdown process as driven by the
|
||||
container's own lifecycle.</para>
|
||||
|
||||
<para>The lifecycle callback interfaces are described in this
|
||||
section.</para>
|
||||
|
||||
<section id="beans-factory-lifecycle-initializingbean">
|
||||
<title>Initialization callbacks</title>
|
||||
|
||||
<para>The
|
||||
<interfacename>org.springframework.beans.factory.InitializingBean</interfacename>
|
||||
interface allows a bean to perform initialization work after all
|
||||
necessary properties on the bean have been set by the container. The
|
||||
<interfacename>InitializingBean</interfacename> interface specifies a
|
||||
single method:</para>
|
||||
|
||||
<programlisting language="java">void afterPropertiesSet() throws Exception;</programlisting>
|
||||
|
||||
<para>It is recommended that you do not use the
|
||||
<interfacename>InitializingBean</interfacename> interface because it
|
||||
unnecessarily couples the code to Spring. Alternatively, specify a POJO
|
||||
initialization method. In the case of XML-based configuration metadata,
|
||||
you use the <literal>init-method</literal> attribute to specify the name
|
||||
of the method that has a void no-argument signature. For example, the
|
||||
following definition:</para>
|
||||
|
||||
<programlisting language="xml"><bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/></programlisting>
|
||||
|
||||
<programlisting language="java">public class ExampleBean {
|
||||
|
||||
public void init() {
|
||||
<lineannotation>// do some initialization work</lineannotation>
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<para>...is exactly the same as...</para>
|
||||
|
||||
<programlisting language="xml"><bean id="exampleInitBean" class="examples.AnotherExampleBean"/></programlisting>
|
||||
|
||||
<programlisting language="java">public class AnotherExampleBean implements InitializingBean {
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
<lineannotation>// do some initialization work</lineannotation>
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<para>... but does not couple the code to Spring.</para>
|
||||
</section>
|
||||
|
||||
<section id="beans-factory-lifecycle-disposablebean">
|
||||
<title>Destruction callbacks</title>
|
||||
|
||||
<para>Implementing the
|
||||
<interfacename>org.springframework.beans.factory.DisposableBean</interfacename>
|
||||
interface allows a bean to get a callback when the container containing
|
||||
it is destroyed. The <interfacename>DisposableBean</interfacename>
|
||||
interface specifies a single method:</para>
|
||||
|
||||
<programlisting language="java">void destroy() throws Exception;</programlisting>
|
||||
|
||||
<para>It is recommended that you do not use the
|
||||
<interfacename>DisposableBean</interfacename> callback interface because
|
||||
it unnecessarily couples the code to Spring. Alternatively, specify a
|
||||
generic method that is supported by bean definitions. With XML-based
|
||||
configuration metadata, you use the <literal>destroy-method</literal>
|
||||
attribute on the <literal><bean/></literal>. For example, the
|
||||
following definition:</para>
|
||||
|
||||
<programlisting language="xml"><bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/></programlisting>
|
||||
|
||||
<programlisting language="java">public class ExampleBean {
|
||||
|
||||
public void cleanup() {
|
||||
<lineannotation>// do some destruction work (like releasing pooled connections)</lineannotation>
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<para>...is exactly the same as...</para>
|
||||
|
||||
<programlisting language="xml"><bean id="exampleInitBean" class="examples.AnotherExampleBean"/></programlisting>
|
||||
|
||||
<programlisting language="java">public class AnotherExampleBean implements DisposableBean {
|
||||
|
||||
public void destroy() {
|
||||
<lineannotation>// do some destruction work (like releasing pooled connections)</lineannotation>
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<para>... but does not couple the code to Spring.</para>
|
||||
</section>
|
||||
|
||||
<section id="beans-factory-lifecycle-default-init-destroy-methods">
|
||||
<title>Default initialization and destroy methods</title>
|
||||
|
||||
<para>When you write initialization and destroy method callbacks that do
|
||||
not use the Spring-specific
|
||||
<interfacename>InitializingBean</interfacename> and
|
||||
<interfacename>DisposableBean</interfacename> callback interfaces, you
|
||||
typically write methods with names such as <literal>init()</literal>,
|
||||
<literal>initialize()</literal>, <literal>dispose()</literal>, and so
|
||||
on. Ideally, the names of such lifecycle callback methods are
|
||||
standardized across a project so that all developers use the same method
|
||||
names and ensure consistency.</para>
|
||||
|
||||
<para>You can configure the Spring container to <literal>look</literal>
|
||||
for named initialization and destroy callback method names on
|
||||
<emphasis>every</emphasis> bean. This means that you, as an application
|
||||
developer, can write your application classes and use an initialization
|
||||
callback called <literal>init()</literal>, without having to configure
|
||||
an <literal>init-method="init"</literal> attribute with each bean
|
||||
definition. The Spring IoC container calls that method when the bean is
|
||||
created (and in accordance with the standard lifecycle callback contract
|
||||
described previously). This feature also enforces a consistent naming
|
||||
convention for initialization and destroy method callbacks.</para>
|
||||
|
||||
<para>Suppose that your initialization callback methods are named
|
||||
<literal>init()</literal> and destroy callback methods are named
|
||||
<literal>destroy()</literal>. Your class will resemble the class in the
|
||||
following example.</para>
|
||||
|
||||
<programlisting language="java">public class DefaultBlogService implements BlogService {
|
||||
|
||||
private BlogDao blogDao;
|
||||
|
||||
public void setBlogDao(BlogDao blogDao) {
|
||||
this.blogDao = blogDao;
|
||||
}
|
||||
|
||||
<lineannotation>// this is (unsurprisingly) the initialization callback method</lineannotation>
|
||||
public void init() {
|
||||
if (this.blogDao == null) {
|
||||
throw new IllegalStateException("The [blogDao] property must be set.");
|
||||
}
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<programlisting language="xml"><beans <emphasis role="bold">default-init-method="init"</emphasis>>
|
||||
|
||||
<bean id="blogService" class="com.foo.DefaultBlogService">
|
||||
<property name="blogDao" ref="blogDao" />
|
||||
</bean>
|
||||
|
||||
</beans></programlisting>
|
||||
|
||||
<para>The presence of the <literal>default-init-method</literal> attribute
|
||||
on the top-level <literal><beans/></literal> element attribute
|
||||
causes the Spring IoC container to recognize a method called
|
||||
<literal>init</literal> on beans as the initialization method callback.
|
||||
When a bean is created and assembled, if the bean class has such a
|
||||
method, it is invoked at the appropriate time.</para>
|
||||
|
||||
<para>You configure destroy method callbacks similarly (in XML, that is)
|
||||
by using the <literal>default-destroy-method</literal> attribute on the
|
||||
top-level <literal><beans/></literal> element.</para>
|
||||
|
||||
<para>Where existing bean classes already have callback methods that are
|
||||
named at variance with the convention, you can override the default by
|
||||
specifying (in XML, that is) the method name using the
|
||||
<literal>init-method</literal> and <literal>destroy-method</literal>
|
||||
attributes of the <bean/> itself.</para>
|
||||
|
||||
<para>The Spring container guarantees that a configured initialization
|
||||
callback is called immediately after a bean is supplied with all
|
||||
dependencies. Thus the initialization callback is called on the raw bean
|
||||
reference, which means that AOP interceptors and so forth are not yet
|
||||
applied to the bean. A target bean is fully created
|
||||
<emphasis>first</emphasis>, <emphasis>then</emphasis> an AOP proxy (for
|
||||
example) with its interceptor chain is applied. If the target bean and
|
||||
the proxy are defined separately, your code can even interact with the
|
||||
raw target bean, bypassing the proxy. Hence, it would be inconsistent to
|
||||
apply the interceptors to the init method, because doing so would couple
|
||||
the lifecycle of the target bean with its proxy/interceptors and leave
|
||||
strange semantics when your code interacts directly to the raw target
|
||||
bean.</para>
|
||||
</section>
|
||||
|
||||
<section id="beans-factory-lifecycle-combined-effects">
|
||||
<title>Combining lifecycle mechanisms</title>
|
||||
|
||||
<para>As of Spring 2.5, you have three options for controlling bean
|
||||
lifecycle behavior: the <link
|
||||
linkend="beans-factory-lifecycle-initializingbean"
|
||||
><interfacename>InitializingBean</interfacename></link> and <link
|
||||
linkend="beans-factory-lifecycle-disposablebean"
|
||||
><interfacename>DisposableBean</interfacename></link> callback
|
||||
interfaces; custom <literal>init()</literal> and
|
||||
<literal>destroy()</literal> methods; and the <link
|
||||
linkend="beans-postconstruct-and-predestroy-annotations"
|
||||
><interfacename>@PostConstruct</interfacename> and
|
||||
<interfacename>@PreDestroy</interfacename> annotations</link>. You can
|
||||
combine these mechanisms to control a given bean.</para>
|
||||
|
||||
<note>
|
||||
<para>If multiple lifecycle mechanisms are configured for a bean, and
|
||||
each mechanism is configured with a different method name, then each
|
||||
configured method is executed in the order listed below. However, if
|
||||
the same method name is configured - for example,
|
||||
<literal>init()</literal> for an initialization method - for more than
|
||||
one of these lifecycle mechanisms, that method is executed once, as
|
||||
explained in the preceding section.</para>
|
||||
</note>
|
||||
|
||||
<para>Multiple lifecycle mechanisms configured for the same bean, with
|
||||
different initialization methods, are called as follows:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Methods annotated with
|
||||
<interfacename>@PostConstruct</interfacename></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>afterPropertiesSet()</literal> as defined by the
|
||||
<interfacename>InitializingBean</interfacename> callback
|
||||
interface</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>A custom configured <literal>init()</literal> method</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>Destroy methods are called in the same order:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Methods annotated with
|
||||
<interfacename>@PreDestroy</interfacename></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>destroy()</literal> as defined by the
|
||||
<interfacename>DisposableBean</interfacename> callback
|
||||
interface</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>A custom configured <literal>destroy()</literal> method</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section id="beans-factory-lifecycle-processor">
|
||||
<title>Startup and shutdown callbacks</title>
|
||||
|
||||
<para>The <interfacename>Lifecycle</interfacename> interface defines the
|
||||
essential methods for any object that has its own lifecycle requirements
|
||||
(e.g. starts and stops some background process):</para>
|
||||
|
||||
<programlisting language="java">public interface Lifecycle {
|
||||
|
||||
void start();
|
||||
|
||||
void stop();
|
||||
|
||||
boolean isRunning();
|
||||
|
||||
}</programlisting>
|
||||
|
||||
<para>Any Spring-managed object may implement that interface. Then, when
|
||||
the ApplicationContext itself starts and stops, it will cascade those
|
||||
calls to all Lifecycle implementations defined within that context. It
|
||||
does this by delegating to a
|
||||
<interfacename>LifecycleProcessor</interfacename>:</para>
|
||||
|
||||
<programlisting language="java">public interface LifecycleProcessor extends Lifecycle {
|
||||
|
||||
void onRefresh();
|
||||
|
||||
void onClose();
|
||||
|
||||
}</programlisting>
|
||||
|
||||
<para>Notice that the <interfacename>LifecycleProcessor</interfacename> is
|
||||
itself an extension of the <interfacename>Lifecycle</interfacename>
|
||||
interface. It also adds two other methods for reacting to the context
|
||||
being refreshed and closed.</para>
|
||||
|
||||
<para>The order of startup and shutdown invocations can be important. If a
|
||||
"depends-on" relationship exists between any two objects, the dependent
|
||||
side will start <emphasis>after</emphasis> its dependency, and it will
|
||||
stop <emphasis>before</emphasis> its dependency. However, at times the
|
||||
direct dependencies are unknown. You may only know that objects of a
|
||||
certain type should start prior to objects of another type. In those
|
||||
cases, the <interfacename>SmartLifecycle</interfacename> interface
|
||||
defines another option, namely the <methodname>getPhase()</methodname>
|
||||
method as defined on its super-interface,
|
||||
<interfacename>Phased</interfacename>.</para>
|
||||
|
||||
<programlisting language="java">public interface Phased {
|
||||
|
||||
int getPhase();
|
||||
|
||||
}
|
||||
|
||||
|
||||
public interface SmartLifecycle extends Lifecycle, Phased {
|
||||
|
||||
boolean isAutoStartup();
|
||||
|
||||
void stop(Runnable callback);
|
||||
|
||||
}</programlisting>
|
||||
|
||||
<para>When starting, the objects with the lowest phase start first, and
|
||||
when stopping, the reverse order is followed. Therefore, an object that
|
||||
implements <interfacename>SmartLifecycle</interfacename> and whose
|
||||
getPhase() method returns <literal>Integer.MIN_VALUE</literal> would be
|
||||
among the first to start and the last to stop. At the other end of the
|
||||
spectrum, a phase value of <literal>Integer.MAX_VALUE</literal> would
|
||||
indicate that the object should be started last and stopped first
|
||||
(likely because it depends on other processes to be running). When
|
||||
considering the phase value, it's also important to know that the
|
||||
default phase for any "normal" <interfacename>Lifecycle</interfacename>
|
||||
object that does not implement
|
||||
<interfacename>SmartLifecycle</interfacename> would be 0. Therefore, any
|
||||
negative phase value would indicate that an object should start before
|
||||
those standard components (and stop after them), and vice versa for any
|
||||
positive phase value.</para>
|
||||
|
||||
<para>As you can see the stop method defined by
|
||||
<interfacename>SmartLifecycle</interfacename> accepts a callback. Any
|
||||
implementation <emphasis>must</emphasis> invoke that callback's run()
|
||||
method after that implementation's shutdown process is complete. That
|
||||
enables asynchronous shutdown where necessary since the default
|
||||
implementation of the <interfacename>LifecycleProcessor</interfacename>
|
||||
interface, <classname>DefaultLifecycleProcessor</classname>, will wait
|
||||
up to its timeout value for the group of objects within each phase to
|
||||
invoke that callback. The default per-phase timeout is 30 seconds. You
|
||||
can override the default lifecycle processor instance by defining a bean
|
||||
named "lifecycleProcessor" within the context. If you only want to
|
||||
modify the timeout, then defining the following would be
|
||||
sufficient:</para>
|
||||
|
||||
<programlisting language="xml"><bean id="lifecycleProcessor" class="org.springframework.context.support.DefaultLifecycleProcessor">
|
||||
<!-- timeout value in milliseconds -->
|
||||
<property name="timeoutPerShutdownPhase" value="10000"/>
|
||||
</bean></programlisting>
|
||||
|
||||
<para>As mentioned, the <interfacename>LifecycleProcessor</interfacename>
|
||||
interface defines callback methods for the refreshing and closing of the
|
||||
context as well. The latter will simply drive the shutdown process as if
|
||||
stop() had been called explicitly, but it will happen when the context
|
||||
is closing. The 'refresh' callback on the other hand enables another
|
||||
feature of <interfacename>SmartLifecycle</interfacename> beans. When the
|
||||
context is refreshed (after all objects have been instantiated and
|
||||
initialized), that callback will be invoked, and at that point the
|
||||
default lifecycle processor will check the boolean value returned by
|
||||
each <interfacename>SmartLifecycle</interfacename> object's
|
||||
<methodname>isAutoStartup()</methodname> method. If "true", then that
|
||||
object will be started at that point rather than waiting for an explicit
|
||||
invocation of the context's or its own start() method (unlike the
|
||||
context refresh, the context start does not happen automatically for a
|
||||
standard context implementation). The "phase" value as well as any
|
||||
"depends-on" relationships will determine the startup order in the same
|
||||
way as described above.</para>
|
||||
</section>
|
||||
|
||||
<section id="beans-factory-shutdown">
|
||||
<title>Shutting down the Spring IoC container gracefully in non-web
|
||||
applications</title>
|
||||
|
||||
<note>
|
||||
<para>This section applies only to non-web applications. Spring's
|
||||
web-based <interfacename>ApplicationContext</interfacename>
|
||||
implementations already have code in place to shut down the Spring IoC
|
||||
container gracefully when the relevant web application is shut
|
||||
down.</para>
|
||||
</note>
|
||||
|
||||
<para>If you are using Spring's IoC container in a non-web application
|
||||
environment; for example, in a rich client desktop environment; you
|
||||
register a shutdown hook with the JVM. Doing so ensures a graceful
|
||||
shutdown and calls the relevant destroy methods on your singleton beans
|
||||
so that all resources are released. Of course, you must still configure
|
||||
and implement these destroy callbacks correctly.</para>
|
||||
|
||||
<para>To register a shutdown hook, you call the
|
||||
<methodname>registerShutdownHook()</methodname> method that is declared
|
||||
on the <classname>AbstractApplicationContext</classname> class:</para>
|
||||
|
||||
<programlisting language="java">import org.springframework.context.support.AbstractApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
|
||||
public final class Boot {
|
||||
|
||||
public static void main(final String[] args) throws Exception {
|
||||
AbstractApplicationContext ctx
|
||||
= new ClassPathXmlApplicationContext(new String []{"beans.xml"});
|
||||
|
||||
<lineannotation>// add a shutdown hook for the above context... </lineannotation>
|
||||
ctx.registerShutdownHook();
|
||||
|
||||
<lineannotation>// app runs here...</lineannotation>
|
||||
|
||||
<lineannotation>// main method exits, hook is called prior to the app shutting down...</lineannotation>
|
||||
}
|
||||
}</programlisting>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="beans-factory-aware">
|
||||
<title><interfacename>ApplicationContextAware</interfacename> and
|
||||
<interfacename>BeanNameAware</interfacename></title>
|
||||
|
||||
<para>When an <interfacename>ApplicationContext</interfacename> creates a
|
||||
class that implements the
|
||||
<interfacename>org.springframework.context.ApplicationContextAware</interfacename>
|
||||
interface, the class is provided with a reference to that
|
||||
<interfacename>ApplicationContext</interfacename>.</para>
|
||||
|
||||
<programlisting language="java">public interface ApplicationContextAware {
|
||||
|
||||
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
|
||||
}</programlisting>
|
||||
|
||||
<para>Thus beans can manipulate programmatically the
|
||||
<interfacename>ApplicationContext</interfacename> that created them,
|
||||
through the <interfacename>ApplicationContext</interfacename> interface,
|
||||
or by casting the reference to a known subclass of this interface, such as
|
||||
<classname>ConfigurableApplicationContext</classname>, which exposes
|
||||
additional functionality. One use would be the programmatic retrieval of
|
||||
other beans. Sometimes this capability is useful; however, in general you
|
||||
should avoid it, because it couples the code to Spring and does not follow
|
||||
the Inversion of Control style, where collaborators are provided to beans
|
||||
as properties. Other methods of the ApplicationContext provide access to
|
||||
file resources, publishing application events, and accessing a
|
||||
MessageSource. These additional features are described in <xref
|
||||
linkend="context-introduction"/></para>
|
||||
|
||||
<para>As of Spring 2.5, autowiring is another alternative to obtain
|
||||
reference to the <interfacename>ApplicationContext</interfacename>. The
|
||||
"traditional" <literal>constructor</literal> and <literal>byType</literal>
|
||||
autowiring modes (as described in <xref linkend="beans-factory-autowire"
|
||||
/>) can provide a dependency of type
|
||||
<interfacename>ApplicationContext</interfacename> for a constructor
|
||||
argument or setter method parameter, respectively. For more flexibility,
|
||||
including the ability to autowire fields and multiple parameter methods,
|
||||
use the new annotation-based autowiring features. If you do, the
|
||||
<interfacename>ApplicationFactory</interfacename> is autowired into a
|
||||
field, constructor argument, or method parameter that is expecting the
|
||||
<interfacename>BeanFactory</interfacename> type if the field, constructor,
|
||||
or method in question carries the
|
||||
<interfacename>@Autowired</interfacename> annotation. For more
|
||||
information, see <xref linkend="beans-autowired-annotation"/>.</para>
|
||||
|
||||
<para>When an ApplicationContext creates a class that implements the
|
||||
<interfacename>org.springframework.beans.factory.BeanNameAware</interfacename>
|
||||
interface, the class is provided with a reference to the name defined in
|
||||
its associated object definition.</para>
|
||||
|
||||
<programlisting language="java">public interface BeanNameAware {
|
||||
|
||||
void setBeanName(string name) throws BeansException;
|
||||
}</programlisting>
|
||||
|
||||
<para>The callback is invoked after population of normal bean properties but
|
||||
before an initialization callback such as
|
||||
<interfacename>InitializingBean</interfacename>s
|
||||
<emphasis>afterPropertiesSet</emphasis> or a custom init-method.</para>
|
||||
</section>
|
||||
|
||||
<section id="aware-list">
|
||||
<title>Other <interfacename>Aware</interfacename> interfaces</title>
|
||||
|
||||
<para>Besides <interfacename>ApplicationContextAware</interfacename> and
|
||||
<interfacename>BeanNameAware</interfacename> discussed above, Spring
|
||||
offers a range of
|
||||
<emphasis><interfacename>Aware</interfacename></emphasis> interfaces that
|
||||
allow beans to indicate to the container that they require a certain
|
||||
<emphasis>infrastructure</emphasis> dependency. The most important
|
||||
<interfacename>Aware</interfacename> interfaces are summarized below - as
|
||||
a general rule, the name is a good indication of the dependency
|
||||
type:</para>
|
||||
|
||||
<table id="beans-factory-nature-aware-list" pgwide="1">
|
||||
<title><interfacename>Aware</interfacename> interfaces</title>
|
||||
|
||||
<tgroup cols="3">
|
||||
<colspec align="left"/>
|
||||
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Name</entry>
|
||||
|
||||
<entry>Injected Dependency</entry>
|
||||
|
||||
<entry>Explained in...</entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><para><classname>ApplicationContextAware</classname></para></entry>
|
||||
|
||||
<entry><para>Declaring
|
||||
<interfacename>ApplicationContext</interfacename></para></entry>
|
||||
|
||||
<entry><para><xref linkend="beans-factory-aware"/></para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><classname>ApplicationEventPublisherAware</classname></para></entry>
|
||||
|
||||
<entry><para>Event publisher of the enclosing
|
||||
<interfacename>ApplicationContext</interfacename></para></entry>
|
||||
|
||||
<entry><para><xref linkend="context-introduction"/></para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><classname>BeanClassLoaderAware</classname></para></entry>
|
||||
|
||||
<entry><para>Class loader used to load the bean
|
||||
classes.</para></entry>
|
||||
|
||||
<entry><para><xref linkend="beans-factory-class"/></para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><classname>BeanFactoryAware</classname></para></entry>
|
||||
|
||||
<entry><para>Declaring
|
||||
<interfacename>BeanFactory</interfacename></para></entry>
|
||||
|
||||
<entry><para><xref linkend="beans-factory-aware"/></para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><classname>BeanNameAware</classname></para></entry>
|
||||
|
||||
<entry><para>Name of the declaring bean</para></entry>
|
||||
|
||||
<entry><para><xref linkend="beans-factory-aware"/></para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><classname>BootstrapContextAware</classname></para></entry>
|
||||
|
||||
<entry><para>Resource adapter
|
||||
<interfacename>BootstrapContext</interfacename> the container runs
|
||||
in. Typically available only in JCA aware
|
||||
<interfacename>ApplicationContext</interfacename>s</para></entry>
|
||||
|
||||
<entry><para><xref linkend="cci"/></para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><classname>LoadTimeWeaverAware</classname></para></entry>
|
||||
|
||||
<entry><para>Defined <emphasis>weaver</emphasis> for processing
|
||||
class definition at load time</para></entry>
|
||||
|
||||
<entry><para><xref linkend="aop-aj-ltw"/></para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><classname>MessageSourceAware</classname></para></entry>
|
||||
|
||||
<entry><para>Configured strategy for resolving messages (with
|
||||
support for parametrization and
|
||||
internationalization)</para></entry>
|
||||
|
||||
<entry><para><xref linkend="context-introduction"/></para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><classname>NotificationPublisherAware</classname></para></entry>
|
||||
|
||||
<entry><para>Spring JMX notification publisher</para></entry>
|
||||
|
||||
<entry><para><xref linkend="jmx-notifications"/></para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><classname>PortletConfigAware</classname></para></entry>
|
||||
|
||||
<entry><para>Current <interfacename>PortletConfig</interfacename>
|
||||
the container runs in. Valid only in a web-aware Spring
|
||||
<interfacename>ApplicationContext</interfacename></para></entry>
|
||||
|
||||
<entry><para><xref linkend="portlet"/></para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><classname>PortletContextAware</classname></para></entry>
|
||||
|
||||
<entry><para>Current <interfacename>PortletContext</interfacename>
|
||||
the container runs in. Valid only in a web-aware Spring
|
||||
<interfacename>ApplicationContext</interfacename></para></entry>
|
||||
|
||||
<entry><para><xref linkend="portlet"/></para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><classname>ResourceLoaderAware</classname></para></entry>
|
||||
|
||||
<entry><para>Configured loader for low-level access to
|
||||
resources</para></entry>
|
||||
|
||||
<entry><para><xref linkend="resources"/></para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><classname>ServletConfigAware</classname></para></entry>
|
||||
|
||||
<entry><para>Current <interfacename>ServletConfig</interfacename>
|
||||
the container runs in. Valid only in a web-aware Spring
|
||||
<interfacename>ApplicationContext</interfacename></para></entry>
|
||||
|
||||
<entry><para><xref linkend="mvc"/></para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><classname>ServletContextAware</classname></para></entry>
|
||||
|
||||
<entry><para>Current <interfacename>ServletContext</interfacename>
|
||||
the container runs in. Valid only in a web-aware Spring
|
||||
<interfacename>ApplicationContext</interfacename></para></entry>
|
||||
|
||||
<entry><para><xref linkend="mvc"/></para></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<para>Note again that usage of these interfaces ties your code to the Spring
|
||||
API and does not follow the Inversion of Control style. As such, they are
|
||||
recommended for infrastructure beans that require programmatic access to
|
||||
the container.</para>
|
||||
</section>
|
||||
</section>
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,519 @@
|
|||
<?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-extension">
|
||||
<title>Container extension points</title>
|
||||
|
||||
<para>Typically, an application developer does not need to subclass any
|
||||
<interfacename>ApplicationContext</interfacename> implementation classes.
|
||||
You can extend The Spring IoC container infinitely by plugging in
|
||||
implementations of special integration interfaces. The next few sections
|
||||
describe these integration interfaces.</para>
|
||||
|
||||
<section id="beans-factory-extension-bpp">
|
||||
<title>Customizing beans using the
|
||||
<interfacename>BeanPostProcessor</interfacename> Interface <literal>
|
||||
</literal></title>
|
||||
|
||||
<para>The <interfacename>BeanPostProcessor</interfacename> interface defines
|
||||
<firstterm>callback methods</firstterm> that you can implement to provide
|
||||
your own (or override the container's default) instantiation logic,
|
||||
dependency-resolution logic, and so forth. If you want to implement some
|
||||
custom logic after the Spring container finishes instantiating,
|
||||
configuring, and otherwise initializing a bean, you can plug in one or
|
||||
more <interfacename>BeanPostProcessor</interfacename>
|
||||
implementations.</para>
|
||||
|
||||
<para>You can configure multiple <literal>BeanPostProcessor</literal>
|
||||
interfaces. You can control the order in which these
|
||||
<literal>BeanPostProcessor</literal> interfaces execute by setting the
|
||||
<literal>order</literal> property. You can set this property only if the
|
||||
<interfacename>BeanPostProcessor</interfacename> implements the
|
||||
<interfacename>Ordered</interfacename> interface; if you write your own
|
||||
<interfacename>BeanPostProcessor</interfacename> you should consider
|
||||
implementing the <interfacename>Ordered</interfacename> interface too. For
|
||||
more details, consult the Javadoc for the
|
||||
<interfacename>BeanPostProcessor</interfacename> and
|
||||
<interfacename>Ordered</interfacename> interfaces.</para>
|
||||
|
||||
<note>
|
||||
<para><literal>BeanPostProcessor</literal>s operate on bean (or object)
|
||||
<emphasis>instances</emphasis>; that is to say, the Spring IoC container
|
||||
instantiates a bean instance and <emphasis>then</emphasis>
|
||||
<literal>BeanPostProcessor</literal> interfaces do their work.</para>
|
||||
|
||||
<para><literal>BeanPostProcessor</literal> interfaces are scoped
|
||||
<emphasis>per-container</emphasis>. This is only relevant if you are
|
||||
using container hierarchies. If you define a
|
||||
<interfacename>BeanPostProcessor</interfacename> in one container, it
|
||||
will <emphasis>only</emphasis> do its work on the beans in that
|
||||
container. Beans that are defined in one container are not
|
||||
post-processed by a <literal>BeanPostProcessor</literal> in another
|
||||
container, even if both containers are part of the same
|
||||
hierarchy.</para>
|
||||
|
||||
<para>To change the actual bean definition (that is, the recipe that
|
||||
defines the bean), you instead need to use a
|
||||
<interfacename>BeanFactoryPostProcessor</interfacename>, described below
|
||||
in <xref linkend="beans-factory-extension-factory-postprocessors"
|
||||
/>.</para>
|
||||
</note>
|
||||
|
||||
<para>The
|
||||
<interfacename>org.springframework.beans.factory.config.BeanPostProcessor</interfacename>
|
||||
interface consists of exactly two callback methods. When such a class is
|
||||
registered as a post-processor with the container, for each bean instance
|
||||
that is created by the container, the post-processor gets a callback from
|
||||
the container both <emphasis>before</emphasis> container initialization
|
||||
methods (such as <emphasis>afterPropertiesSet</emphasis> and any declared
|
||||
init method) are called, and also afterwards. The post-processor can take
|
||||
any action with the bean instance, including ignoring the callback
|
||||
completely. A bean post-processor typically checks for callback
|
||||
interfaces, or may wrap a bean with a proxy. Some Spring AOP
|
||||
infrastructure classes are implemented as bean post-processors and they do
|
||||
this proxy-wrapping logic.</para>
|
||||
|
||||
<para>An <interfacename>ApplicationContext</interfacename>
|
||||
<emphasis>automatically detects</emphasis> any beans that are defined in
|
||||
the configuration metadata it receives that implement the
|
||||
<interfacename>BeanPostProcessor</interfacename> interface. The
|
||||
<interfacename>ApplicationContext</interfacename> registers these beans as
|
||||
post-processors, to be then called appropriately by the container upon
|
||||
bean creation. You can then deploy the post-processors as you would any
|
||||
bean.</para>
|
||||
|
||||
<note>
|
||||
<title><interfacename>BeanPostProcessors</interfacename> and AOP
|
||||
auto-proxying</title>
|
||||
|
||||
<para>Classes that implement the
|
||||
<interfacename>BeanPostProcessor</interfacename> interface are
|
||||
<emphasis>special</emphasis>, and so they are treated differently by the
|
||||
container. All <interfacename>BeanPostProcessors</interfacename>
|
||||
<emphasis>and their directly referenced beans</emphasis> are
|
||||
instantiated on startup, as part of the special startup phase of the
|
||||
<interfacename>ApplicationContext</interfacename>. Next, all those
|
||||
<interfacename>BeanPostProcessors</interfacename> are registered in a
|
||||
sorted fashion - and applied to all further beans. Because AOP
|
||||
auto-proxying is implemented as a
|
||||
<interfacename>BeanPostProcessor</interfacename> itself, no
|
||||
<interfacename>BeanPostProcessors</interfacename> or directly referenced
|
||||
beans are eligible for auto-proxying, and thus do not have aspects woven
|
||||
into them.</para>
|
||||
|
||||
<para>For any such bean, you should see an info log message:
|
||||
<emphasis><quote>Bean foo is not eligible for getting processed by all
|
||||
BeanPostProcessor interfaces (for example: not eligible for
|
||||
auto-proxying)</quote>.</emphasis></para>
|
||||
</note>
|
||||
|
||||
<para>The following examples show how to write, register, and use
|
||||
<literal>BeanPostProcessors</literal> in the context of an
|
||||
<interfacename>ApplicationContext</interfacename>.</para>
|
||||
|
||||
<section id="beans-factory-extension-bpp-examples-hw">
|
||||
<title>Example: Hello World,
|
||||
<interfacename>BeanPostProcessor</interfacename>-style</title>
|
||||
|
||||
<para>This first example illustrates basic usage. The example shows a
|
||||
custom <interfacename>BeanPostProcessor</interfacename> implementation
|
||||
that invokes the <methodname>toString()</methodname> method of each bean
|
||||
as it is created by the container and prints the resulting string to the
|
||||
system console.</para>
|
||||
|
||||
<para>Find below the custom
|
||||
<interfacename>BeanPostProcessor</interfacename> implementation class
|
||||
definition:</para>
|
||||
|
||||
<programlisting language="java">package scripting;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.BeansException;
|
||||
|
||||
public class InstantiationTracingBeanPostProcessor implements BeanPostProcessor {
|
||||
|
||||
<lineannotation>// simply return the instantiated bean as-is</lineannotation>
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
return bean; <lineannotation>// we could potentially return <emphasis>any</emphasis> object reference here...</lineannotation>
|
||||
}
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
System.out.println("Bean '" + beanName + "' created : " + bean.toString());
|
||||
return bean;
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<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:lang="http://www.springframework.org/schema/lang"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/lang
|
||||
http://www.springframework.org/schema/lang/spring-lang-3.0.xsd">
|
||||
|
||||
<lang:groovy id="messenger"
|
||||
script-source="classpath:org/springframework/scripting/groovy/Messenger.groovy">
|
||||
<lang:property name="message" value="Fiona Apple Is Just So Dreamy."/>
|
||||
</lang:groovy>
|
||||
|
||||
<lineannotation><!--
|
||||
when the above bean (messenger) is instantiated, this custom
|
||||
<interfacename>BeanPostProcessor</interfacename> implementation will output the fact to the system console
|
||||
--></lineannotation>
|
||||
<bean class="scripting.InstantiationTracingBeanPostProcessor"/>
|
||||
|
||||
</beans></programlisting>
|
||||
|
||||
<para>Notice how the
|
||||
<classname>InstantiationTracingBeanPostProcessor</classname> is simply
|
||||
defined. It does not even have a name, and because it is a bean it can
|
||||
be dependency-injected just like any other bean. (The preceding
|
||||
configuration also defines a bean that is backed by a Groovy script. The
|
||||
Spring 2.0 dynamic language support is detailed in the chapter entitled
|
||||
<xref linkend="dynamic-language"/>.)</para>
|
||||
|
||||
<para>The following small driver script executes the preceding code and
|
||||
configuration:</para>
|
||||
|
||||
<programlisting language="java">import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.scripting.Messenger;
|
||||
|
||||
public final class Boot {
|
||||
|
||||
public static void main(final String[] args) throws Exception {
|
||||
ApplicationContext ctx = new ClassPathXmlApplicationContext("scripting/beans.xml");
|
||||
Messenger messenger = (Messenger) ctx.getBean("messenger");
|
||||
System.out.println(messenger);
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<para>The output of the preceding execution resembles the
|
||||
following:</para>
|
||||
|
||||
<programlisting>Bean 'messenger' created : org.springframework.scripting.groovy.GroovyMessenger@272961
|
||||
org.springframework.scripting.groovy.GroovyMessenger@272961</programlisting>
|
||||
</section>
|
||||
|
||||
<section id="beans-factory-extension-bpp-examples-rabpp">
|
||||
<title>Example: The
|
||||
<classname>RequiredAnnotationBeanPostProcessor</classname></title>
|
||||
|
||||
<para>Using callback interfaces or annotations in conjunction with a
|
||||
custom <interfacename>BeanPostProcessor</interfacename> implementation
|
||||
is a common means of extending the Spring IoC container. An example is
|
||||
Spring's <classname>RequiredAnnotationBeanPostProcessor</classname> -- a
|
||||
<interfacename>BeanPostProcessor</interfacename> implementation that
|
||||
ships with the Spring distribution which ensures that JavaBean
|
||||
properties on beans that are marked with an (arbitrary) annotation are
|
||||
actually (configured to be) dependency-injected with a value.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="beans-factory-extension-factory-postprocessors">
|
||||
<title>Customizing configuration metadata with
|
||||
<interfacename>BeanFactoryPostProcessor</interfacename> interface</title>
|
||||
|
||||
<para>The next extension point that we will look at is the
|
||||
<interfacename>org.springframework.beans.factory.config.BeanFactoryPostProcessor</interfacename>.
|
||||
The semantics of this interface are similar to the
|
||||
<interfacename>BeanPostProcessor</interfacename>, with one major
|
||||
difference: <literal>BeanFactoryPostProcessor</literal>s operate on the
|
||||
<emphasis>bean configuration metadata</emphasis>; that is, the Spring IoC
|
||||
container allows <literal>BeanFactoryPostProcessors</literal> to read the
|
||||
configuration metadata and potentially change it
|
||||
<emphasis>before</emphasis> the container instantiates any beans other
|
||||
than <literal>BeanFactoryPostProcessors</literal>.</para>
|
||||
|
||||
<para>You can configure multiple
|
||||
<literal>BeanFactoryPostProcessors</literal>. You can control the order in
|
||||
which these <literal>BeanFactoryPostProcessors</literal> execute by
|
||||
setting the <literal>order</literal> property. However, you can only set
|
||||
this property if the
|
||||
<interfacename>BeanFactoryPostProcessor</interfacename> implements the
|
||||
<interfacename>Ordered</interfacename> interface. If you write your own
|
||||
<interfacename>BeanFactoryPostProcessor,</interfacename> you should
|
||||
consider implementing the <interfacename>Ordered</interfacename> interface
|
||||
too; consult the Javadoc for the
|
||||
<interfacename>BeanFactoryPostProcessor</interfacename> and
|
||||
<interfacename>Ordered</interfacename> interfaces for more details.</para>
|
||||
|
||||
<note>
|
||||
<para>If you want to change the actual bean <emphasis>instances</emphasis>
|
||||
(the objects that are created from the configuration metadata), then you
|
||||
instead need to use a <interfacename>BeanPostProcessor</interfacename>
|
||||
(described above in <xref linkend="beans-factory-extension-bpp"/>. While
|
||||
it is technically possible to work with bean instances within a
|
||||
<interfacename>BeanFactoryPostProcessor</interfacename> (e.g. using
|
||||
<methodname>BeanFactory.getBean()</methodname>), doing so causes
|
||||
premature bean instantiation, violating the usual containter lifecycle.
|
||||
This may cause negative side effects such as bypassing bean post
|
||||
processing.</para>
|
||||
|
||||
<para>Also, <literal>BeanFactoryPostProcessors</literal> are scoped
|
||||
<emphasis>per-container</emphasis>. This is only relevant if you are
|
||||
using container hierarchies. If you define a
|
||||
<interfacename>BeanFactoryPostProcessor</interfacename> in one
|
||||
container, it will <emphasis>only</emphasis> do its stuff on the bean
|
||||
definitions in that container. Bean definitions in another container
|
||||
will not be post-processed by
|
||||
<literal>BeanFactoryPostProcessors</literal> in another container, even
|
||||
if both containers are part of the same hierarchy.</para>
|
||||
</note>
|
||||
|
||||
<para>A bean factory post-processor is executed automatically when it is
|
||||
declared inside of an <interfacename>ApplicationContext,</interfacename>
|
||||
in order to apply changes to the configuration metadata that defines a
|
||||
container. Spring includes a number of pre-existing bean factory
|
||||
post-processors, such as <classname>PropertyOverrideConfigurer</classname>
|
||||
and <classname>PropertyPlaceholderConfigurer. </classname>A custom
|
||||
<interfacename>BeanFactoryPostProcessor</interfacename> can also be used,
|
||||
for example, to register custom property editors.</para>
|
||||
|
||||
<anchor id="beans-factory-autodetect-beanfactorypostprocessors"/>
|
||||
|
||||
<para>An <interfacename>ApplicationContext</interfacename> detects any beans
|
||||
that are deployed into it and that implement the
|
||||
<interfacename>BeanFactoryPostProcessor</interfacename> interface. It
|
||||
automatically uses these beans as bean factory post-processors, at the
|
||||
appropriate time. You can then deploy these post-processor beans as you
|
||||
would any other bean.</para>
|
||||
|
||||
<note>
|
||||
<para>As with <literal>BeanPostProcessors</literal>, you typically do not
|
||||
want <literal>BeanFactoryPostProcessors</literal> marked as
|
||||
lazy-initialized. If they are marked as such, the Spring container never
|
||||
instantiates them, and thus they cannot apply their custom logic. If you
|
||||
use the <literal>default-lazy-init</literal> attribute on the
|
||||
declaration of your <literal><beans/></literal> element, be sure
|
||||
to mark your various
|
||||
<interfacename>BeanFactoryPostProcessor</interfacename> bean definitions
|
||||
with <literal>lazy-init="false"</literal>.</para>
|
||||
</note>
|
||||
|
||||
<section id="beans-factory-placeholderconfigurer">
|
||||
<title>Example: the
|
||||
<interfacename>PropertyPlaceholderConfigurer</interfacename></title>
|
||||
|
||||
<para>You use the
|
||||
<interfacename>PropertyPlaceholderConfigurer</interfacename> to
|
||||
externalize property values from a bean definition into another separate
|
||||
file in the standard Java <classname>Properties</classname> format.
|
||||
Doing so enables the person deploying an application to customize
|
||||
environment-specific properties such as database URLs and passwords,
|
||||
without the complexity or risk of modifying the main XML definition file
|
||||
or files for the container.</para>
|
||||
|
||||
<!-- MLP: Beverly to review following 2 paragraphs -->
|
||||
|
||||
<para>Consider the following XML-based configuration metadata fragment,
|
||||
where a <interfacename>DataSource</interfacename> with placeholder
|
||||
values is defined. The example shows properties configured from an
|
||||
external <classname>Properties</classname> file. At runtime, a
|
||||
<classname>PropertyPlaceholderConfigurer</classname> is applied to the
|
||||
metadata that will replace some properties of the DataSource. The values
|
||||
to replace are specified as 'placeholders' of the form ${property-name}
|
||||
which follows the Ant / Log4J / JSP EL style.</para>
|
||||
|
||||
<programlisting language="xml"><bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
|
||||
<property name="locations" value="classpath:com/foo/jdbc.properties"/>
|
||||
</bean>
|
||||
|
||||
<bean id="dataSource" destroy-method="close"
|
||||
class="org.apache.commons.dbcp.BasicDataSource">
|
||||
<property name="driverClassName" value="<emphasis role="bold">${jdbc.driverClassName}</emphasis>"/>
|
||||
<property name="url" value="<emphasis role="bold">${jdbc.url}</emphasis>"/>
|
||||
<property name="username" value="<emphasis role="bold">${jdbc.username}</emphasis>"/>
|
||||
<property name="password" value="<emphasis role="bold">${jdbc.password}</emphasis>"/>
|
||||
</bean></programlisting>
|
||||
|
||||
<para>The actual values come from another file in the standard Java
|
||||
<classname>Properties</classname> format:</para>
|
||||
|
||||
<programlisting language="java">jdbc.driverClassName=org.hsqldb.jdbcDriver
|
||||
jdbc.url=jdbc:hsqldb:hsql://production:9002
|
||||
jdbc.username=sa
|
||||
jdbc.password=root</programlisting>
|
||||
|
||||
<para>Therefore, the string ${jdbc.username} is replaced at runtime with
|
||||
the value 'sa' and similarly for other placeholder values that match to
|
||||
keys in the property file. The PropertyPlaceholderConfigurer checks for
|
||||
placeholders in most locations of a bean definition and the placeholder
|
||||
prefix and suffix can be customized.</para>
|
||||
|
||||
<para>With the <literal>context</literal> namespace introduced in Spring
|
||||
2.5, it is possible to configure property placeholders with a dedicated
|
||||
configuration element. You can provide multiple locations as a
|
||||
comma-separated list in the <literal>location</literal>
|
||||
attribute.</para>
|
||||
|
||||
<programlisting language="xml"><context:property-placeholder location="classpath:com/foo/jdbc.properties"/></programlisting>
|
||||
|
||||
<para>The <classname>PropertyPlaceholderConfigurer</classname> does not
|
||||
look for properties only in the <classname>Properties</classname> file
|
||||
you specify, but also checks against the Java
|
||||
<classname>System</classname> properties if it cannot find a property
|
||||
you are trying to use. You can customize this behavior by setting the
|
||||
<literal>systemPropertiesMode</literal> property of the configurer. It
|
||||
has three values that specify configurer behavior: always override,
|
||||
<emphasis>never</emphasis> override, and override only if the property
|
||||
is not found in the properties file specified.
|
||||
<!--What property is it overriding and what will replace the overridden value?-->
|
||||
<!--MLP: override a value in the Properties with one from the 'systemProperties' -->
|
||||
Consult the Javadoc for the
|
||||
<classname>PropertyPlaceholderConfigurer</classname> for more
|
||||
information.</para>
|
||||
|
||||
<tip>
|
||||
<title>Class name substitution</title>
|
||||
|
||||
<para>You can use the
|
||||
<classname>PropertyPlaceholderConfigurer</classname> to substitute
|
||||
class names, which is sometimes useful when you have to pick a
|
||||
particular implementation class at runtime. For example:</para>
|
||||
|
||||
<programlisting language="xml"><bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
|
||||
<property name="locations">
|
||||
<value>classpath:com/foo/strategy.properties</value>
|
||||
</property>
|
||||
<property name="properties">
|
||||
<value>custom.strategy.class=com.foo.DefaultStrategy</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="serviceStrategy" class="${custom.strategy.class}"/></programlisting>
|
||||
|
||||
<para>If the class cannot be resolved at runtime to a valid class,
|
||||
resolution of the bean fails when it is about to be created, which is
|
||||
during the <methodname>preInstantiateSingletons()</methodname> phase
|
||||
of an <interfacename>ApplicationContext</interfacename> for a
|
||||
non-lazy-init bean.</para>
|
||||
</tip>
|
||||
</section>
|
||||
|
||||
<section id="beans-factory-overrideconfigurer">
|
||||
<title>Example: the
|
||||
<classname>PropertyOverrideConfigurer</classname></title>
|
||||
|
||||
<para>The <classname>PropertyOverrideConfigurer</classname>, another bean
|
||||
factory post-processor, resembles the
|
||||
<interfacename>PropertyPlaceholderConfigurer</interfacename>, but unlike
|
||||
the latter, the original definitions can have default values or no
|
||||
values at all for bean properties. If an overriding
|
||||
<classname>Properties</classname> file does not have an entry for a
|
||||
certain bean property, the default context definition is used.</para>
|
||||
|
||||
<para>Note that the bean definition is <emphasis>not</emphasis> aware of
|
||||
being overridden, so it is not immediately obvious from the XML
|
||||
definition file that the override configurer is used. In case of
|
||||
multiple <classname>PropertyOverrideConfigurer</classname> instances
|
||||
that define different values for the same bean property, the last one
|
||||
wins, due to the overriding mechanism.</para>
|
||||
|
||||
<para>Properties file configuration lines take this format:</para>
|
||||
|
||||
<programlisting language="java">beanName.property=value</programlisting>
|
||||
|
||||
<para>For example:</para>
|
||||
|
||||
<programlisting language="java">dataSource.driverClassName=com.mysql.jdbc.Driver
|
||||
dataSource.url=jdbc:mysql:mydb</programlisting>
|
||||
|
||||
<para>This example file is usable against a container definition that
|
||||
contains a bean called <emphasis>dataSource</emphasis>, which has
|
||||
<emphasis>driver</emphasis> and <emphasis>url</emphasis>
|
||||
properties.</para>
|
||||
|
||||
<para>Compound property names are also supported, as long as every
|
||||
component of the path except the final property being overridden is
|
||||
already non-null (presumably initialized by the constructors). In this
|
||||
example...</para>
|
||||
|
||||
<programlisting language="java">foo.fred.bob.sammy=123</programlisting>
|
||||
|
||||
<para>... the <literal>sammy</literal> property of the
|
||||
<literal>bob</literal> property of the <literal>fred</literal> property
|
||||
of the <literal>foo</literal> bean is set to the scalar value
|
||||
<literal>123</literal>.</para>
|
||||
|
||||
<para><note>
|
||||
<para>Specified override values are always <emphasis>literal</emphasis>
|
||||
values; they are not translated into bean references. This convention
|
||||
also applies when the original value in the XML bean definition
|
||||
specifies a bean reference.</para>
|
||||
</note></para>
|
||||
|
||||
<para>With the <literal>context</literal> namespace introduced in Spring
|
||||
2.5, it is possible to configure property overriding with a dedicated
|
||||
configuration element:</para>
|
||||
|
||||
<programlisting language="xml"><context:property-override location="classpath:override.properties"/></programlisting>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="beans-factory-extension-factorybean">
|
||||
<title>Customizing instantiation logic with the
|
||||
<interfacename>FactoryBean</interfacename> Interface <literal>
|
||||
</literal></title>
|
||||
|
||||
<para>You implement the
|
||||
<interfacename>org.springframework.beans.factory.FactoryBean</interfacename>
|
||||
interface for objects that <emphasis>are themselves
|
||||
factories</emphasis>.</para>
|
||||
|
||||
<para>The <interfacename>FactoryBean</interfacename> interface is a point of
|
||||
pluggability into the Spring IoC container's instantiation logic. If you
|
||||
have complex initialization code that is better expressed in Java as
|
||||
opposed to a (potentially) verbose amount of XML, you can create your own
|
||||
<interfacename>FactoryBean</interfacename>, write the complex
|
||||
initialization inside that class, and then plug your custom
|
||||
<interfacename>FactoryBean</interfacename> into the container.</para>
|
||||
|
||||
<para>The <interfacename>FactoryBean</interfacename> interface provides
|
||||
three methods:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><methodname>Object getObject()</methodname>: returns an instance
|
||||
of the object this factory creates. The instance can possibly be
|
||||
shared, depending on whether this factory returns singletons or
|
||||
prototypes.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><methodname>boolean isSingleton()</methodname>: returns
|
||||
<literal>true</literal> if this
|
||||
<interfacename>FactoryBean</interfacename> returns singletons,
|
||||
<literal>false</literal> otherwise.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><methodname>Class getObjectType()</methodname>: returns the object
|
||||
type returned by the <methodname>getObject()</methodname> method or
|
||||
<literal>null</literal> if the type is not known in advance</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>The <interfacename>FactoryBean</interfacename> concept and interface
|
||||
is used in a number of places within the Spring Framework; more than 50
|
||||
implementations of the <interfacename>FactoryBean</interfacename>
|
||||
interface ship with Spring itself.</para>
|
||||
|
||||
<para>When you need to ask a container for an actual
|
||||
<interfacename>FactoryBean</interfacename> instance itself, not the bean
|
||||
it produces, you preface the bean id with the ampersand symbol
|
||||
<literal>&</literal> (without quotes) when calling the
|
||||
<methodname>getBean()</methodname> method of the
|
||||
<interfacename>ApplicationContext</interfacename>. So for a given
|
||||
<interfacename>FactoryBean</interfacename> with an id of
|
||||
<literal>myBean</literal>, invoking <literal>getBean("myBean")</literal>
|
||||
on the container returns the product of the
|
||||
<interfacename>FactoryBean</interfacename>, and invoking
|
||||
<literal>getBean("&myBean")</literal> returns the
|
||||
<interfacename>FactoryBean</interfacename> instance
|
||||
itself.<!--Moved ApplicationContext section to almost the end of the doc, right before BeanFactory and renamed it Additional Capabilities of.--></para>
|
||||
</section>
|
||||
</section>
|
||||
|
|
@ -0,0 +1,908 @@
|
|||
<?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-java">
|
||||
<title>Java-based container configuration</title>
|
||||
|
||||
<section id="beans-java-basic-concepts">
|
||||
<title>Basic concepts: <literal>@Configuration</literal> and
|
||||
<literal>@Bean</literal></title>
|
||||
|
||||
<para>The central artifact in Spring's new Java-configuration support is the
|
||||
<interfacename>@Configuration</interfacename>-annotated class. These
|
||||
classes consist principally of
|
||||
<interfacename>@Bean</interfacename>-annotated methods that define
|
||||
instantiation, configuration, and initialization logic for objects to be
|
||||
managed by the Spring IoC container.</para>
|
||||
|
||||
<para>Annotating a class with the
|
||||
<interfacename>@Configuration</interfacename> indicates that the class can
|
||||
be used by the Spring IoC container as a source of bean definitions. The
|
||||
simplest possible <interfacename>@Configuration</interfacename> class
|
||||
would read as follows:
|
||||
<programlisting language="java">@Configuration
|
||||
public class AppConfig {
|
||||
@Bean
|
||||
public MyService myService() {
|
||||
return new MyServiceImpl();
|
||||
}
|
||||
}</programlisting></para>
|
||||
|
||||
<para>For those more familiar with Spring <literal><beans/></literal>
|
||||
XML, the <literal>AppConfig</literal> class above would be equivalent to:
|
||||
<programlisting language="xml"><beans>
|
||||
<bean id="myService" class="com.acme.services.MyServiceImpl"/>
|
||||
</beans></programlisting>
|
||||
As you can see, the <literal>@Bean</literal> annotation plays the same
|
||||
role as the <literal><bean/></literal> element. The
|
||||
<literal>@Bean</literal> annotation will be discussed in depth in the
|
||||
sections below. First, however, we'll cover the various ways of creating a
|
||||
spring container using Java-based configuration.</para>
|
||||
</section>
|
||||
|
||||
<section id="beans-java-instantiating-container">
|
||||
<title>Instantiating the Spring container using
|
||||
<literal>AnnotationConfigApplicationContext</literal></title>
|
||||
|
||||
<para>The sections below document Spring's
|
||||
<literal>AnnotationConfigApplicationContext</literal>, new in Spring 3.0.
|
||||
This versatile <literal>ApplicationContext</literal> implementation is
|
||||
capable of accepting not only <literal>@Configuration</literal> classes as
|
||||
input, but also plain <literal>@Component</literal> classes and classes
|
||||
annotated with JSR-330 metadata.</para>
|
||||
|
||||
<para>When <literal>@Configuration</literal> classes are provided as input,
|
||||
the <literal>@Configuration</literal> class itself is registered as a bean
|
||||
definition, and all declared <literal>@Bean</literal> methods within the
|
||||
class are also registered as bean definitions.</para>
|
||||
|
||||
<para>When <literal>@Component</literal> and JSR-330 classes are provided,
|
||||
they are registered as bean definitions, and it is assumed that DI
|
||||
metadata such as <literal>@Autowired</literal> or
|
||||
<literal>@Inject</literal> are used within those classes where
|
||||
necessary.</para>
|
||||
|
||||
<section id="beans-java-instantiating-container-contstructor">
|
||||
<title>Simple construction</title>
|
||||
|
||||
<para>In much the same way that Spring XML files are used as input when
|
||||
instantiating a <literal>ClassPathXmlApplicationContext</literal>,
|
||||
<literal>@Configuration</literal> classes may be used as input when
|
||||
instantiating an <literal>AnnotationConfigApplicationContext</literal>.
|
||||
This allows for completely XML-free usage of the Spring container:
|
||||
<programlisting language="java">public static void main(String[] args) {
|
||||
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
|
||||
MyService myService = ctx.getBean(MyService.class);
|
||||
myService.doStuff();
|
||||
}</programlisting>
|
||||
As mentioned above,
|
||||
<literal>AnnotationConfigApplicationContext</literal> is not limited to
|
||||
working only with <literal>@Configuration</literal> classes. Any
|
||||
<literal>@Component</literal> or JSR-330 annotated class may be supplied
|
||||
as input to the constructor. For example:
|
||||
<programlisting language="java">public static void main(String[] args) {
|
||||
ApplicationContext ctx = new AnnotationConfigApplicationContext(MyServiceImpl.class, Dependency1.class, Dependency2.class);
|
||||
MyService myService = ctx.getBean(MyService.class);
|
||||
myService.doStuff();
|
||||
}</programlisting>
|
||||
The above assumes that <literal>MyServiceImpl</literal>,
|
||||
<literal>Dependency1</literal> and <literal>Dependency2</literal> use
|
||||
Spring dependency injection annotations such as
|
||||
<literal>@Autowired</literal>.</para>
|
||||
</section>
|
||||
|
||||
<section id="beans-java-instantiating-container-register">
|
||||
<title>Building the container programmatically using
|
||||
<literal>register(Class<?>...)</literal></title>
|
||||
|
||||
<para>An <literal>AnnotationConfigApplicationContext</literal> may be
|
||||
instantiated using a no-arg constructor and then configured using the
|
||||
<literal>register()</literal> method. This approach is particularly
|
||||
useful when programmatically building an
|
||||
<literal>AnnotationConfigApplicationContext</literal>.
|
||||
<programlisting language="java">public static void main(String[] args) {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.register(AppConfig.class, OtherConfig.class);
|
||||
ctx.register(AdditionalConfig.class);
|
||||
ctx.refresh();
|
||||
MyService myService = ctx.getBean(MyService.class);
|
||||
myService.doStuff();
|
||||
}</programlisting></para>
|
||||
</section>
|
||||
|
||||
<section id="beans-java-instantiating-container-scan">
|
||||
<title>Enabling component scanning with
|
||||
<literal>scan(String...)</literal></title>
|
||||
|
||||
<para>Experienced Spring users will be familiar with the following
|
||||
commonly-used XML declaration from Spring's <literal>context:</literal>
|
||||
namespace
|
||||
<programlisting language="xml"><beans>
|
||||
<context:component-scan base-package="com.acme"/>
|
||||
</beans></programlisting>
|
||||
In the example above, the <literal>com.acme</literal> package will be
|
||||
scanned, looking for any <literal>@Component</literal>-annotated
|
||||
classes, and those classes will be registered as Spring bean definitions
|
||||
within the container.
|
||||
<literal>AnnotationConfigApplicationContext</literal> exposes the
|
||||
<literal>scan(String...)</literal> method to allow for the same
|
||||
component-scanning
|
||||
functionality:<programlisting language="java">public static void main(String[] args) {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.scan("com.acme");
|
||||
ctx.refresh();
|
||||
MyService myService = ctx.getBean(MyService.class);
|
||||
}</programlisting></para>
|
||||
|
||||
<note>
|
||||
<para>Remember that <literal>@Configuration</literal> classes are
|
||||
meta-annotated with <literal>@Component</literal>, so they are
|
||||
candidates for component-scanning! In the example above, assuming that
|
||||
<literal>AppConfig</literal> is declared within the
|
||||
<literal>com.acme</literal> package (or any package underneath), it
|
||||
will be picked up during the call to <literal>scan()</literal>, and
|
||||
upon <literal>refresh()</literal> all its <literal>@Bean</literal>
|
||||
methods will be processed and registered as bean definitions within
|
||||
the container.</para>
|
||||
</note>
|
||||
</section>
|
||||
|
||||
<section id="beans-java-instantiating-container-web">
|
||||
<title>Support for web applications with
|
||||
<literal>AnnotationConfigWebApplicationContext</literal></title>
|
||||
|
||||
<para>A <literal>WebApplicationContext</literal> variant of
|
||||
<literal>AnnotationConfigApplicationContext</literal> is available with
|
||||
<literal>AnnotationConfigWebApplicationContext</literal>. This
|
||||
implementation may be used when configuring the Spring
|
||||
<literal>ContextLoaderListener</literal> servlet listener, Spring MVC
|
||||
<literal>DispatcherServlet</literal>, etc. What follows is a
|
||||
<literal>web.xml</literal> snippet that configures a typical Spring MVC
|
||||
web application. Note the use of the <literal>contextClass</literal>
|
||||
context-param and init-param:
|
||||
<programlisting language="xml">
|
||||
<web-app>
|
||||
<!-- Configure ContextLoaderListener to use AnnotationConfigWebApplicationContext
|
||||
instead of the default XmlWebApplicationContext -->
|
||||
<context-param>
|
||||
<param-name>contextClass</param-name>
|
||||
<param-value>
|
||||
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
|
||||
</param-value>
|
||||
</context-param>
|
||||
|
||||
<!-- Configuration locations must consist of one or more comma- or space-delimited
|
||||
fully-qualified @Configuration classes. Fully-qualified packages may also be
|
||||
specified for component-scanning -->
|
||||
<context-param>
|
||||
<param-name>contextConfigLocation</param-name>
|
||||
<param-value>com.acme.AppConfig</param-value>
|
||||
</context-param>
|
||||
|
||||
<!-- Bootstrap the root application context as usual using ContextLoaderListener -->
|
||||
<listener>
|
||||
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
|
||||
</listener>
|
||||
|
||||
<!-- Declare a Spring MVC DispatcherServlet as usual -->
|
||||
<servlet>
|
||||
<servlet-name>dispatcher</servlet-name>
|
||||
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
|
||||
<!-- Configure DispatcherServlet to use AnnotationConfigWebApplicationContext
|
||||
instead of the default XmlWebApplicationContext -->
|
||||
<init-param>
|
||||
<param-name>contextClass</param-name>
|
||||
<param-value>
|
||||
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
|
||||
</param-value>
|
||||
</init-param>
|
||||
<!-- Again, config locations must consist of one or more comma- or space-delimited
|
||||
and fully-qualified @Configuration classes -->
|
||||
<init-param>
|
||||
<param-name>contextConfigLocation</param-name>
|
||||
<param-value>com.acme.web.MvcConfig</param-value>
|
||||
</init-param>
|
||||
</servlet>
|
||||
|
||||
<!-- map all requests for /main/* to the dispatcher servlet -->
|
||||
<servlet-mapping>
|
||||
<servlet-name>dispatcher</servlet-name>
|
||||
<url-pattern>/main/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
</web-app></programlisting></para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="beans-java-composing-configuration-classes">
|
||||
<title>Composing Java-based configurations</title>
|
||||
|
||||
<section id="beans-java-using-import">
|
||||
<title>Using the <literal>@Import</literal> annotation</title>
|
||||
|
||||
<para>Much as the <literal><import/></literal> element is used
|
||||
within Spring XML files to aid in modularizing configurations, the
|
||||
<literal>@Import</literal> annotation allows for loading
|
||||
<literal>@Bean</literal> definitions from another configuration
|
||||
class:<programlisting language="java">@Configuration
|
||||
public class ConfigA {
|
||||
public @Bean A a() { return new A(); }
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import(ConfigA.class)
|
||||
public class ConfigB {
|
||||
public @Bean B b() { return new B(); }
|
||||
}</programlisting>
|
||||
Now, rather than needing to specify both
|
||||
<literal>ConfigA.class</literal> and <literal>ConfigB.class</literal>
|
||||
when instantiating the context, only <literal>ConfigB</literal> needs to
|
||||
be supplied
|
||||
explicitly:<programlisting language="java">public static void main(String[] args) {
|
||||
ApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigB.class);
|
||||
|
||||
// now both beans A and B will be available...
|
||||
A a = ctx.getBean(A.class);
|
||||
B b = ctx.getBean(B.class);
|
||||
}</programlisting>
|
||||
This approach simplifies container instantiation, as only one class
|
||||
needs to be dealt with, rather than requiring the developer to remember
|
||||
a potentially large number of <literal>@Configuration</literal> classes
|
||||
during construction.</para>
|
||||
|
||||
<section id="beans-java-injecting-imported-beans">
|
||||
<title>Injecting dependencies on imported <literal>@Bean</literal>
|
||||
definitions</title>
|
||||
|
||||
<para>The example above works, but is simplistic. In most practical
|
||||
scenarios, beans will have dependencies on one another across
|
||||
configuration classes. When using XML, this is not an issue, per se,
|
||||
because there is no compiler involved, and one can simply declare
|
||||
<literal>ref="someBean"</literal> and trust that Spring will work it
|
||||
out during container initialization. Of course, when using
|
||||
<literal>@Configuration</literal> classes, the Java compiler places
|
||||
constraints on the configuration model, in that references to other
|
||||
beans must be valid Java syntax.</para>
|
||||
|
||||
<para>Fortunately, solving this problem is simple. Remember that
|
||||
<literal>@Configuration</literal> classes are ultimately just another
|
||||
bean in the container - this means that they can take advantage of
|
||||
<literal>@Autowired</literal> injection metadata just like any other
|
||||
bean!</para>
|
||||
|
||||
<para>Let's consider a more real-world scenario with several
|
||||
<literal>@Configuration</literal> classes, each depending on beans
|
||||
declared in the
|
||||
others:<programlisting language="java">@Configuration
|
||||
public class ServiceConfig {
|
||||
private @Autowired AccountRepository accountRepository;
|
||||
|
||||
public @Bean TransferService transferService() {
|
||||
return new TransferServiceImpl(accountRepository);
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
public class RepositoryConfig {
|
||||
private @Autowired DataSource dataSource;
|
||||
|
||||
public @Bean AccountRepository accountRepository() {
|
||||
return new JdbcAccountRepository(dataSource);
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import({ServiceConfig.class, RepositoryConfig.class})
|
||||
public class SystemTestConfig {
|
||||
public @Bean DataSource dataSource() { /* return new DataSource */ }
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);
|
||||
// everything wires up across configuration classes...
|
||||
TransferService transferService = ctx.getBean(TransferService.class);
|
||||
transferService.transfer(100.00, "A123", "C456");
|
||||
}</programlisting></para>
|
||||
|
||||
<section id="beans-java-injecting-imported-beans-fq">
|
||||
<title>Fully-qualifying imported beans for ease of navigation</title>
|
||||
|
||||
<para>In the scenario above, using <literal>@Autowired</literal> works
|
||||
well and provides the desired modularity, but determining exactly
|
||||
where the autowired bean definitions are declared is still somewhat
|
||||
ambiguous. For example, as a developer looking at
|
||||
<literal>ServiceConfig</literal>, how do you know exactly where the
|
||||
<literal>@Autowired AccountRepository</literal> bean is declared?
|
||||
It's not explicit in the code, and this may be just fine. Remember
|
||||
that the <ulink url="http://www.springsource.com/products/sts"
|
||||
>SpringSource Tool Suite</ulink> provides tooling that can render
|
||||
graphs showing how everything is wired up - that may be all you
|
||||
need. Also, your Java IDE can easily find all declarations and uses
|
||||
of the <literal>AccountRepository</literal> type, and will quickly
|
||||
show you the location of <literal>@Bean</literal> methods that
|
||||
return that type.</para>
|
||||
|
||||
<para>In cases where this ambiguity is not acceptable and you wish to
|
||||
have direct navigation from within your IDE from one
|
||||
<literal>@Configuration</literal> class to another, consider
|
||||
autowiring the configuration classes themselves:
|
||||
<programlisting language="java">@Configuration
|
||||
public class ServiceConfig {
|
||||
private @Autowired RepositoryConfig repositoryConfig;
|
||||
|
||||
public @Bean TransferService transferService() {
|
||||
// navigate 'through' the config class to the @Bean method!
|
||||
return new TransferServiceImpl(repositoryConfig.accountRepository());
|
||||
}
|
||||
}</programlisting>
|
||||
In the situation above, it is completely explicit where
|
||||
<literal>AccountRepository</literal> is defined. However,
|
||||
<literal>ServiceConfig</literal> is now tightly coupled to
|
||||
<literal>RepositoryConfig</literal>; that's the tradeoff. This tight
|
||||
coupling can be somewhat mitigated by using interface-based or
|
||||
abstract class-based <literal>@Configuration</literal> classes.
|
||||
Consider the following:
|
||||
<programlisting language="java">@Configuration
|
||||
public class ServiceConfig {
|
||||
private @Autowired RepositoryConfig repositoryConfig;
|
||||
|
||||
public @Bean TransferService transferService() {
|
||||
return new TransferServiceImpl(repositoryConfig.accountRepository());
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
public interface RepositoryConfig {
|
||||
@Bean AccountRepository accountRepository();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
public class DefaultRepositoryConfig implements RepositoryConfig {
|
||||
public @Bean AccountRepository accountRepository() {
|
||||
return new JdbcAccountRepository(...);
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import({ServiceConfig.class, DefaultRepositoryConfig.class}) // import the concrete config!
|
||||
public class SystemTestConfig {
|
||||
public @Bean DataSource dataSource() { /* return DataSource */ }
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);
|
||||
TransferService transferService = ctx.getBean(TransferService.class);
|
||||
transferService.transfer(100.00, "A123", "C456");
|
||||
}</programlisting>
|
||||
Now <literal>ServiceConfig</literal> is loosely coupled with respect
|
||||
to the concrete <literal>DefaultRepositoryConfig</literal>, and
|
||||
built-in IDE tooling is still useful: it will be easy for the
|
||||
developer to get a type hierarchy of
|
||||
<literal>RepositoryConfig</literal> implementations. In this way,
|
||||
navigating <literal>@Configuration</literal> classes and their
|
||||
dependencies becomes no different than the usual process of
|
||||
navigating interface-based code.</para>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="beans-java-combining">
|
||||
<title>Combining Java and XML configuration</title>
|
||||
|
||||
<para>Spring's <literal>@Configuration</literal> class support does not
|
||||
aim to be a 100% complete replacement for Spring XML. Some facilities
|
||||
such as Spring XML namespaces remain an ideal way to configure the
|
||||
container. In cases where XML is convenient or necessary, you have a
|
||||
choice: either instantiate the container in an "XML-centric" way using,
|
||||
for example, <literal>ClassPathXmlApplicationContext</literal>, or in a
|
||||
"Java-centric" fashion using
|
||||
<literal>AnnotationConfigApplicationContext</literal> and the
|
||||
<literal>@ImportResource</literal> annotation to import XML as
|
||||
needed.</para>
|
||||
|
||||
<section id="beans-java-combining-xml-centric">
|
||||
<title>XML-centric use of <literal>@Configuration</literal>
|
||||
classes</title>
|
||||
|
||||
<para>It may be preferable to bootstrap the Spring container from XML
|
||||
and include <literal>@Configuration</literal> classes in an ad-hoc
|
||||
fashion. For example, in a large existing codebase that uses Spring
|
||||
XML, it will be easier to create <literal>@Configuration</literal>
|
||||
classes on an as-needed basis and include them from the existing XML
|
||||
files. Below you'll find the options for using
|
||||
<literal>@Configuration</literal> classes in this kind of
|
||||
"XML-centric" situation.</para>
|
||||
|
||||
<section id="beans-java-combining-xml-centric-declare-as-bean">
|
||||
<title>Declaring <literal>@Configuration</literal> classes as plain
|
||||
Spring <literal><bean/></literal> elements</title>
|
||||
|
||||
<para>Remember that <literal>@Configuration</literal> classes are
|
||||
ultimately just bean definitions in the container. In this example,
|
||||
we create a <literal>@Configuration</literal> class named
|
||||
<literal>AppConfig</literal> and include it within
|
||||
<literal>system-test-config.xml</literal> as a
|
||||
<literal><bean/></literal>definition. Because
|
||||
<literal><context:annotation-config/></literal> is switched
|
||||
on, the container will recognize the
|
||||
<literal>@Configuration</literal> annotation, and process the
|
||||
<literal>@Bean</literal> methods declared in
|
||||
<literal>AppConfig</literal>
|
||||
properly.<programlisting language="java">@Configuration
|
||||
public class AppConfig {
|
||||
private @Autowired DataSource dataSource;
|
||||
|
||||
public @Bean AccountRepository accountRepository() {
|
||||
return new JdbcAccountRepository(dataSource);
|
||||
}
|
||||
|
||||
public @Bean TransferService transferService() {
|
||||
return new TransferService(accountRepository());
|
||||
}
|
||||
}</programlisting>
|
||||
<programlisting language="xml"><lineannotation role="listingtitle">system-test-config.xml</lineannotation>
|
||||
<beans>
|
||||
<!-- enable processing of annotations such as @Autowired and @Configuration -->
|
||||
<context:annotation-config/>
|
||||
<context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>
|
||||
|
||||
<bean class="com.acme.AppConfig"/>
|
||||
|
||||
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
|
||||
<property name="url" value="${jdbc.url}"/>
|
||||
<property name="username" value="${jdbc.username}"/>
|
||||
<property name="password" value="${jdbc.password}"/>
|
||||
</bean>
|
||||
</beans></programlisting>
|
||||
<programlisting><lineannotation role="listingtitle">jdbc.properties</lineannotation>
|
||||
jdbc.url=jdbc:hsqldb:hsql://localhost/xdb
|
||||
jdbc.username=sa
|
||||
jdbc.password=</programlisting>
|
||||
<programlisting language="java">public static void main(String[] args) {
|
||||
ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:/com/acme/system-test-config.xml");
|
||||
TransferService transferService = ctx.getBean(TransferService.class);
|
||||
// ...
|
||||
}</programlisting></para>
|
||||
|
||||
<note>
|
||||
<para>In <literal>system-test-config.xml</literal> above, the
|
||||
<literal>AppConfig<bean/></literal> does not declare an
|
||||
<literal>id</literal> element. While it would be acceptable to do
|
||||
so, it is unnecessary given that no other bean will ever refer to
|
||||
it, and it is unlikely that it will be explicitly fetched from the
|
||||
container by name. Likewise with the <literal>DataSource</literal>
|
||||
bean - it is only ever autowired by type, so an explicit bean id
|
||||
is not strictly required.</para>
|
||||
</note>
|
||||
</section>
|
||||
|
||||
<section id="beans-java-combining-xml-centric-component-scan">
|
||||
<title>Using <literal><context:component-scan/></literal> to
|
||||
pick up <literal>@Configuration</literal> classes</title>
|
||||
|
||||
<para>Because <literal>@Configuration</literal> is meta-annotated with
|
||||
<literal>@Component</literal>,
|
||||
<literal>@Configuration</literal>-annotated classes are
|
||||
automatically candidates for component scanning. Using the same
|
||||
scenario as above, we can redefine
|
||||
<literal>system-test-config.xml</literal> to take advantage of
|
||||
component-scanning. Note that in this case, we don't need to
|
||||
explicitly declare
|
||||
<literal><context:annotation-config/></literal>, because
|
||||
<literal><context:component-scan/></literal> enables all the
|
||||
same
|
||||
functionality.<programlisting language="xml"><lineannotation role="listingtitle">system-test-config.xml</lineannotation>
|
||||
<beans>
|
||||
<!-- picks up and registers AppConfig as a bean definition -->
|
||||
<context:component-scan base-package="com.acme"/>
|
||||
<context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>
|
||||
|
||||
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
|
||||
<property name="url" value="${jdbc.url}"/>
|
||||
<property name="username" value="${jdbc.username}"/>
|
||||
<property name="password" value="${jdbc.password}"/>
|
||||
</bean>
|
||||
</beans></programlisting></para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="beans-java-combining-java-centric">
|
||||
<title><literal>@Configuration</literal> class-centric use of XML with
|
||||
<literal>@ImportResource</literal></title>
|
||||
|
||||
<para>In applications where <literal>@Configuration</literal> classes
|
||||
are the primary mechanism for configuring the container, it will still
|
||||
likely be necessary to use at least some XML. In these scenarios,
|
||||
simply use <literal>@ImportResource</literal> and define only as much
|
||||
XML as is needed. Doing so achieves a "Java-centric" approach to
|
||||
configuring the container and keeps XML to a bare minimum.
|
||||
<programlisting language="java">@Configuration
|
||||
@ImportResource("classpath:/com/acme/properties-config.xml")
|
||||
public class AppConfig {
|
||||
private @Value("${jdbc.url}") String url;
|
||||
private @Value("${jdbc.username}") String username;
|
||||
private @Value("${jdbc.password}") String password;
|
||||
|
||||
public @Bean DataSource dataSource() {
|
||||
return new DriverManagerDataSource(url, username, password);
|
||||
}
|
||||
}</programlisting>
|
||||
<programlisting language="xml"><lineannotation role="listingtitle">properties-config.xml</lineannotation>
|
||||
<beans>
|
||||
<context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>
|
||||
</beans></programlisting>
|
||||
<programlisting><lineannotation role="listingtitle">jdbc.properties</lineannotation>
|
||||
jdbc.url=jdbc:hsqldb:hsql://localhost/xdb
|
||||
jdbc.username=sa
|
||||
jdbc.password=</programlisting>
|
||||
<programlisting language="java">public static void main(String[] args) {
|
||||
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
|
||||
TransferService transferService = ctx.getBean(TransferService.class);
|
||||
// ...
|
||||
}</programlisting></para>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="beans-java-bean-annotation">
|
||||
<title>Using the <interfacename>@Bean</interfacename> annotation</title>
|
||||
|
||||
<para><interfacename>@Bean</interfacename> is a method-level annotation and
|
||||
a direct analog of the XML <code><bean/></code> element. The
|
||||
annotation supports some of the attributes offered by
|
||||
<code><bean/></code>, such as: <code><link
|
||||
linkend="beans-factory-lifecycle-initializingbean"
|
||||
>init-method</link></code>, <code><link
|
||||
linkend="beans-factory-lifecycle-disposablebean"
|
||||
>destroy-method</link></code>, <code><link
|
||||
linkend="beans-factory-autowire">autowiring</link></code> and
|
||||
<code>name</code>.</para>
|
||||
|
||||
<para>You can use the <interfacename>@Bean</interfacename> annotation in a
|
||||
<interfacename>@Configuration</interfacename>-annotated or in a
|
||||
<interfacename>@Component</interfacename>-annotated class.</para>
|
||||
|
||||
<section id="beans-java-declaring-a-bean">
|
||||
<title>Declaring a bean</title>
|
||||
|
||||
<para>To declare a bean, simply annotate a method with the
|
||||
<interfacename>@Bean</interfacename> annotation. You use this method to
|
||||
register a bean definition within an <code>ApplicationContext</code> of
|
||||
the type specified as the method's return value. By default, the bean
|
||||
name will be the same as the method name. The following is a simple
|
||||
example of a <interfacename>@Bean</interfacename> method declaration:
|
||||
<programlisting language="java">@Configuration
|
||||
public class AppConfig {
|
||||
|
||||
@Bean
|
||||
public TransferService transferService() {
|
||||
return new TransferServiceImpl();
|
||||
}
|
||||
|
||||
}</programlisting></para>
|
||||
|
||||
<para>The preceding configuration is exactly equivalent to the following
|
||||
Spring XML:
|
||||
<programlisting language="xml"><beans>
|
||||
<bean id="transferService" class="com.acme.TransferServiceImpl"/>
|
||||
</beans> </programlisting></para>
|
||||
|
||||
<para>Both declarations make a bean named <code>transferService</code>
|
||||
available in the <code>ApplicationContext</code>, bound to an object
|
||||
instance of type <code>TransferServiceImpl</code>:
|
||||
<programlisting>
|
||||
transferService -> com.acme.TransferServiceImpl
|
||||
</programlisting></para>
|
||||
</section>
|
||||
|
||||
<section id="beans-java-injecting-dependencies">
|
||||
<title>Injecting dependencies</title>
|
||||
|
||||
<para>When <interfacename>@Bean</interfacename>s have dependencies on one
|
||||
another, expressing that dependency is as simple as having one bean
|
||||
method call another:
|
||||
<programlisting language="java">@Configuration
|
||||
public class AppConfig {
|
||||
|
||||
@Bean
|
||||
public Foo foo() {
|
||||
return new Foo(bar());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Bar bar() {
|
||||
return new Bar();
|
||||
}
|
||||
|
||||
} </programlisting></para>
|
||||
|
||||
<para>In the example above, the <code>foo</code> bean receives a reference
|
||||
to <code> bar</code> via constructor injection.</para>
|
||||
</section>
|
||||
|
||||
<section id="beans-java-lifecycle-callbacks">
|
||||
<title>Receiving lifecycle callbacks</title>
|
||||
|
||||
<para>Beans declared in a
|
||||
<interfacename>@Configuration</interfacename>-annotated class support
|
||||
the regular lifecycle callbacks. Any classes defined with the
|
||||
<literal>@Bean</literal> annotation can use the
|
||||
<literal>@PostConstruct</literal> and <literal>@PreDestroy</literal>
|
||||
annotations from JSR-250, see <link
|
||||
linkend="beans-postconstruct-and-predestroy-annotations">JSR-250
|
||||
annotations</link> for further details.</para>
|
||||
|
||||
<para>The regular Spring <link linkend="beans-factory-nature"
|
||||
>lifecycle</link> callbacks are fully supported as well. If a bean
|
||||
implements <code>InitializingBean</code>, <code>DisposableBean</code>,
|
||||
or <code>Lifecycle</code>, their respective methods are called by the
|
||||
container.</para>
|
||||
|
||||
<para>The standard set of <code>*Aware</code> interfaces such as
|
||||
<code><link linkend="beans-beanfactory">BeanFactoryAware</link></code>,
|
||||
<code><link linkend="beans-factory-aware">BeanNameAware</link></code>,
|
||||
<code><link linkend="context-functionality-messagesource"
|
||||
>MessageSourceAware</link></code>, <code><link
|
||||
linkend="beans-factory-aware">ApplicationContextAware</link></code>, and
|
||||
so on are also fully supported.</para>
|
||||
|
||||
<para>The <interfacename>@Bean</interfacename> annotation supports
|
||||
specifying arbitrary initialization and destruction callback methods,
|
||||
much like Spring XML's <code>init-method</code> and
|
||||
<code>destroy-method</code> attributes on the <code>bean</code> element:
|
||||
<programlisting language="java">public class Foo {
|
||||
public void init() {
|
||||
// initialization logic
|
||||
}
|
||||
}
|
||||
|
||||
public class Bar {
|
||||
public void cleanup() {
|
||||
// destruction logic
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
public class AppConfig {
|
||||
@Bean(initMethod = "init")
|
||||
public Foo foo() {
|
||||
return new Foo();
|
||||
}
|
||||
@Bean(destroyMethod = "cleanup")
|
||||
public Bar bar() {
|
||||
return new Bar();
|
||||
}
|
||||
}
|
||||
</programlisting></para>
|
||||
|
||||
<para>Of course, in the case of <code>Foo</code> above, it would be
|
||||
equally as valid to call the <code>init()</code> method directly during
|
||||
construction:
|
||||
<programlisting language="java">@Configuration
|
||||
public class AppConfig {
|
||||
@Bean
|
||||
public Foo foo() {
|
||||
Foo foo = new Foo();
|
||||
foo.init();
|
||||
return foo;
|
||||
}
|
||||
|
||||
// ...
|
||||
} </programlisting></para>
|
||||
|
||||
<tip>
|
||||
<para>When you work directly in Java, you can do anything you like with
|
||||
your objects and do not always need to rely on the container
|
||||
lifecycle!</para>
|
||||
</tip>
|
||||
</section>
|
||||
|
||||
<section id="beans-java-specifying-bean-scope">
|
||||
<title>Specifying bean scope</title>
|
||||
|
||||
<section id="beans-java-available-scopes">
|
||||
<title>Using the <interfacename>@Scope</interfacename>
|
||||
annotation</title>
|
||||
|
||||
<!-- MLP: Beverly, did not apply your edit as it changed meaning -->
|
||||
|
||||
<para>You can specify that your beans defined with the
|
||||
<interfacename>@Bean</interfacename> annotation should have a specific
|
||||
scope. You can use any of the standard scopes specified in the <link
|
||||
linkend="beans-factory-scopes">Bean Scopes</link> section.</para>
|
||||
|
||||
<para>The default scope is <literal>singleton</literal>, but you can
|
||||
override this with the <interfacename>@Scope</interfacename>
|
||||
annotation:
|
||||
<programlisting language="java">@Configuration
|
||||
public class MyConfiguration {
|
||||
@Bean
|
||||
<emphasis role="bold">@Scope("prototype")</emphasis>
|
||||
public Encryptor encryptor() {
|
||||
// ...
|
||||
}
|
||||
}</programlisting></para>
|
||||
</section>
|
||||
|
||||
<section id="beans-java-scoped-proxy">
|
||||
<title><code>@Scope and scoped-proxy</code></title>
|
||||
|
||||
<para>Spring offers a convenient way of working with scoped dependencies
|
||||
through <link linkend="beans-factory-scopes-other-injection">scoped
|
||||
proxies</link>. The easiest way to create such a proxy when using the
|
||||
XML configuration is the <code><aop:scoped-proxy/></code>
|
||||
element. Configuring your beans in Java with a @Scope annotation
|
||||
offers equivalent support with the proxyMode attribute. The default is
|
||||
no proxy (<varname>ScopedProxyMode.NO</varname>), but you can specify
|
||||
<classname>ScopedProxyMode.TARGET_CLASS</classname> or
|
||||
<classname>ScopedProxyMode.INTERFACES</classname>.</para>
|
||||
|
||||
<para>If you port the scoped proxy example from the XML reference
|
||||
documentation (see preceding link) to our
|
||||
<interfacename>@Bean</interfacename> using Java, it would look like
|
||||
the following:
|
||||
<programlisting language="java">// an HTTP Session-scoped bean exposed as a proxy
|
||||
@Bean
|
||||
<emphasis role="bold">@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)</emphasis>
|
||||
public UserPreferences userPreferences() {
|
||||
return new UserPreferences();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Service userService() {
|
||||
UserService service = new SimpleUserService();
|
||||
// a reference to the proxied userPreferences bean
|
||||
service.setUserPreferences(userPreferences());
|
||||
return service;
|
||||
} </programlisting></para>
|
||||
</section>
|
||||
|
||||
<section id="beans-java-method-injection">
|
||||
<title>Lookup method injection</title>
|
||||
|
||||
<para>As noted earlier, <link linkend="beans-factory-method-injection"
|
||||
>lookup method injection</link> is an advanced feature that you should
|
||||
use rarely. It is useful in cases where a singleton-scoped bean has a
|
||||
dependency on a prototype-scoped bean. Using Java for this type of
|
||||
configuration provides a natural means for implementing this pattern.
|
||||
<programlisting language="java">public abstract class CommandManager {
|
||||
public Object process(Object commandState) {
|
||||
// grab a new instance of the appropriate Command interface
|
||||
Command command = createCommand();
|
||||
|
||||
// set the state on the (hopefully brand new) Command instance
|
||||
command.setState(commandState);
|
||||
return command.execute();
|
||||
}
|
||||
|
||||
// okay... but where is the implementation of this method?
|
||||
protected abstract Command createCommand();
|
||||
} </programlisting></para>
|
||||
|
||||
<para>Using Java-configuration support , you can create a subclass of
|
||||
<code>CommandManager</code> where the abstract
|
||||
<code>createCommand()</code> method is overridden in such a way that
|
||||
it looks up a new (prototype) command object:
|
||||
<programlisting language="java">@Bean
|
||||
@Scope("prototype")
|
||||
public AsyncCommand asyncCommand() {
|
||||
AsyncCommand command = new AsyncCommand();
|
||||
// inject dependencies here as required
|
||||
return command;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CommandManager commandManager() {
|
||||
// return new anonymous implementation of CommandManager with command() overridden
|
||||
// to return a new prototype Command object
|
||||
return new CommandManager() {
|
||||
protected Command createCommand() {
|
||||
return asyncCommand();
|
||||
}
|
||||
}
|
||||
} </programlisting></para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="beans-java-customizing-bean-naming">
|
||||
<title>Customizing bean naming</title>
|
||||
|
||||
<para>By default, configuration classes use a
|
||||
<interfacename>@Bean</interfacename> method's name as the name of the
|
||||
resulting bean. This functionality can be overridden, however, with the
|
||||
<code>name</code> attribute.
|
||||
<programlisting language="java">@Configuration
|
||||
public class AppConfig {
|
||||
|
||||
@Bean(name = "myFoo")
|
||||
public Foo foo() {
|
||||
return new Foo();
|
||||
}
|
||||
|
||||
} </programlisting></para>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
<section id="beans-java-bean-aliasing">
|
||||
<title>Bean aliasing</title>
|
||||
|
||||
<para>As discussed in <xref linkend="beans-beanname"/>, it is sometimes
|
||||
desirable to give a single bean multiple names, otherwise known as
|
||||
<emphasis>bean aliasing</emphasis>. The <literal>name</literal>
|
||||
attribute of the <literal>@Bean</literal> annotation accepts a String
|
||||
array for this purpose.
|
||||
<programlisting language="java">@Configuration
|
||||
public class AppConfig {
|
||||
|
||||
@Bean(name = { "dataSource", "subsystemA-dataSource", "subsystemB-dataSource" })
|
||||
public DataSource dataSource() {
|
||||
// instantiate, configure and return DataSource bean...
|
||||
}
|
||||
|
||||
} </programlisting></para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="beans-java-further-information-java-config">
|
||||
<title>Further information about how Java-based configuration works
|
||||
internally</title>
|
||||
|
||||
<para>The following example shows a <literal>@Bean</literal> annotated
|
||||
method being called twice:</para>
|
||||
|
||||
<programlisting language="java">
|
||||
@Configuration
|
||||
public class AppConfig {
|
||||
|
||||
@Bean
|
||||
public ClientService clientService1() {
|
||||
ClientServiceImpl clientService = new ClientServiceImpl();
|
||||
clientService.setClientDao(clientDao());
|
||||
return clientService;
|
||||
}
|
||||
@Bean
|
||||
public ClientService clientService2() {
|
||||
ClientServiceImpl clientService = new ClientServiceImpl();
|
||||
clientService.setClientDao(clientDao());
|
||||
return clientService;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ClientDao clientDao() {
|
||||
return new ClientDaoImpl();
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
<para> <methodname>clientDao()</methodname> has been called once in
|
||||
<methodname>clientService1()</methodname> and once in
|
||||
<methodname>clientService2()</methodname>. Since this method creates a new
|
||||
instance of <classname>ClientDaoImpl</classname> and returns it, you would
|
||||
normally expect having 2 instances (one for each service). That definitely
|
||||
would be problematic: in Spring, instantiated beans have a
|
||||
<literal>singleton</literal> scope by default. This is where the magic
|
||||
comes in: All <literal>@Configuration</literal> classes are subclassed at
|
||||
startup-time with <literal>CGLIB</literal>. In the subclass, the child
|
||||
method checks the container first for any cached (scoped) beans before it
|
||||
calls the parent method and creates a new instance. </para>
|
||||
<note>
|
||||
<para> The behavior could be different according to the scope of your
|
||||
bean. We are talking about singletons here. </para>
|
||||
</note>
|
||||
<note>
|
||||
<para> Beware that, in order for JavaConfig to work, you must include the
|
||||
CGLIB jar in your list of dependencies. </para>
|
||||
</note>
|
||||
<note>
|
||||
<para> There are a few restrictions due to the fact that CGLIB dynamically
|
||||
adds features at startup-time: <itemizedlist>
|
||||
<listitem>
|
||||
<para>Configuration classes should not be final</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>They should have a constructor with no arguments</para>
|
||||
</listitem>
|
||||
</itemizedlist> </para>
|
||||
</note>
|
||||
</section>
|
||||
</section>
|
||||
|
|
@ -0,0 +1,686 @@
|
|||
<?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><!-- this next element effects the proxying of 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>
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue