Move reference docs => src/reference
This change eliminates the spring-framework-reference subproject, moving these sources into the root project's own src directory. This makes sense because the reference docs span all submodules, and also because api Javadoc is created at the root project level as well. This means that both api and reference documentation output will now reside in the root project's 'build' directory. This is more consistent and easy to discover.
1969
src/reference/docbook/aop-api.xml
Normal file
3865
src/reference/docbook/aop.xml
Normal file
801
src/reference/docbook/beans-annotation-config.xml
Normal file
@@ -0,0 +1,801 @@
|
||||
<?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. Spring 2.5 made it 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 added support for JSR-250 annotations
|
||||
such as <interfacename>@PostConstruct</interfacename>, and
|
||||
<interfacename>@PreDestroy</interfacename>. Spring 3.0 added support for
|
||||
JSR-330 (Dependency Injection for Java) annotations contained in the
|
||||
javax.inject package such as <classname>@Inject</classname> and
|
||||
<literal> @Named</literal>. Details about those annotations can be found in the <link linkend="beans-standard-annotations"
|
||||
>relevant section</link>. <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</interfacename></title>
|
||||
|
||||
<para>As expected, you can apply the
|
||||
<interfacename>@Autowired</interfacename> annotation to "traditional"
|
||||
setter methods:</para>
|
||||
|
||||
|
||||
|
||||
<programlisting language="java">public class SimpleMovieLister {
|
||||
|
||||
private MovieFinder movieFinder;
|
||||
|
||||
@Autowired
|
||||
public void setMovieFinder(MovieFinder movieFinder) {
|
||||
this.movieFinder = movieFinder;
|
||||
}
|
||||
|
||||
<lineannotation>// ...</lineannotation>
|
||||
}</programlisting>
|
||||
|
||||
<note>
|
||||
<para>JSR 330's @Inject annotation can be used in place of Spring's
|
||||
<interfacename>@Autowired</interfacename> annotation in the examples below. See <link linkend="beans-standard-annotations"
|
||||
>here</link> for more details</para>
|
||||
</note>
|
||||
|
||||
|
||||
<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>Environment</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>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
<interfacename>@Autowired</interfacename>,
|
||||
<interfacename>@Inject</interfacename>,
|
||||
<interfacename>@Resource</interfacename>, and
|
||||
<interfacename>@Value</interfacename> annotations are handled by a
|
||||
Spring <interfacename>BeanPostProcessor</interfacename> implementations
|
||||
which in turn means that you <emphasis>cannot</emphasis>
|
||||
apply these annotations within your own
|
||||
<classname>BeanPostProcessor</classname> or
|
||||
<classname>BeanFactoryPostProcessor</classname> types (if any). These
|
||||
types must be 'wired up' explicitly via XML or using a Spring
|
||||
<interfacename>@Bean</interfacename> method.</para>
|
||||
</note>
|
||||
</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>
|
||||
|
||||
<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>
|
||||
|
||||
|
||||
<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>
|
||||
502
src/reference/docbook/beans-classpath-scanning.xml
Normal file
@@ -0,0 +1,502 @@
|
||||
<?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>
|
||||
|
||||
<para>Most examples 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
|
||||
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>
|
||||
|
||||
<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>
|
||||
663
src/reference/docbook/beans-context-additional.xml
Normal file
@@ -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 shows 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>known.spammer@example.org</value>
|
||||
<value>known.hacker@example.org</value>
|
||||
<value>john.doe@example.org</value>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="blackListNotifier" class="example.BlackListNotifier">
|
||||
<property name="notificationAddress" value="blacklist@example.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>
|
||||
665
src/reference/docbook/beans-customizing.xml
Normal file
@@ -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>
|
||||
1648
src/reference/docbook/beans-dependencies.xml
Normal file
557
src/reference/docbook/beans-extension-points.xml
Normal file
@@ -0,0 +1,557 @@
|
||||
<?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
|
||||
<interfacename>ApplicationContext</interfacename> implementation classes.
|
||||
Instead, the Spring IoC container can be extended 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 a
|
||||
<interfacename>BeanPostProcessor</interfacename></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 initializing a bean, you can plug in one or
|
||||
more <interfacename>BeanPostProcessor</interfacename>
|
||||
implementations.</para>
|
||||
|
||||
<para>You can configure multiple <literal>BeanPostProcessor</literal>
|
||||
instances, and you can control the order in which these
|
||||
<literal>BeanPostProcessor</literal>s 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
|
||||
further details, consult the Javadoc for the
|
||||
<interfacename>BeanPostProcessor</interfacename> and
|
||||
<interfacename>Ordered</interfacename> interfaces. See also the note below on
|
||||
<link linkend="beans-factory-programmatically-registering-beanpostprocessors">
|
||||
programmatic registration of <interfacename>BeanPostProcessors</interfacename>
|
||||
</link></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>s do their work.</para>
|
||||
|
||||
<para><literal>BeanPostProcessor</literal>s 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> post-process the beans in that
|
||||
container. In other words, beans that are defined in one container are not
|
||||
post-processed by a <literal>BeanPostProcessor</literal> defined in another
|
||||
container, even if both containers are part of the same hierarchy.</para>
|
||||
|
||||
<para>To change the actual bean definition (i.e., the
|
||||
<emphasis>blueprint</emphasis> that defines the bean), you instead need to use a
|
||||
<interfacename>BeanFactoryPostProcessor</interfacename> as described
|
||||
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 InitializingBean's <emphasis>afterPropertiesSet()</emphasis>
|
||||
and any declared init method) are called as well as <emphasis>after</emphasis>
|
||||
any bean initialization callbacks. 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 in order
|
||||
to provide proxy-wrapping logic.</para>
|
||||
|
||||
<para>An <interfacename>ApplicationContext</interfacename>
|
||||
<emphasis>automatically detects</emphasis> any beans that are defined in
|
||||
the configuration metadata which implement the
|
||||
<interfacename>BeanPostProcessor</interfacename> interface. The
|
||||
<interfacename>ApplicationContext</interfacename> registers these beans as
|
||||
post-processors so that they can be called later upon bean creation.
|
||||
Bean post-processors can be deployed in the container just like any other
|
||||
beans.</para>
|
||||
|
||||
<anchor id="beans-factory-programmatically-registering-beanpostprocessors"/>
|
||||
<note>
|
||||
<title>Programmatically registering <interfacename>BeanPostProcessors
|
||||
</interfacename></title>
|
||||
<para>
|
||||
While the recommended approach for <interfacename>BeanPostProcessor
|
||||
</interfacename> registration is through <interfacename>ApplicationContext
|
||||
</interfacename> auto-detection (as described above), it is also
|
||||
possible to register them <emphasis>programmatically</emphasis>
|
||||
against an <interfacename>ApplicationContext</interfacename> using the
|
||||
<methodname>addBeanPostProcessor</methodname> method. This can be useful
|
||||
when needing to evaluate conditional logic before registration, or even
|
||||
for copying bean post processors across contexts in a hierarchy. Note
|
||||
however that <interfacename>BeanPostProcessors</interfacename> added
|
||||
programmatically <emphasis>do not respect the <interfacename>Ordered
|
||||
</interfacename> interface</emphasis>. Here it is the <emphasis>order of
|
||||
registration</emphasis> that dictates the order of execution. Note also
|
||||
that <interfacename>BeanPostProcessors</interfacename> registered
|
||||
programmatically are always processed before those registered through
|
||||
auto-detection, regardless of any explicit ordering.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
<note>
|
||||
<title><interfacename>BeanPostProcessors</interfacename> and AOP
|
||||
auto-proxying</title>
|
||||
|
||||
<para>Classes that implement the
|
||||
<interfacename>BeanPostProcessor</interfacename> interface are
|
||||
<emphasis>special</emphasis> and are treated differently by the
|
||||
container. All <interfacename>BeanPostProcessors</interfacename>
|
||||
<emphasis>and beans that they reference directly</emphasis> are
|
||||
instantiated on startup, as part of the special startup phase of the
|
||||
<interfacename>ApplicationContext</interfacename>. Next, all
|
||||
<interfacename>BeanPostProcessors</interfacename> are registered in a
|
||||
sorted fashion and applied to all further beans in the container.
|
||||
Because AOP auto-proxying is implemented as a
|
||||
<interfacename>BeanPostProcessor</interfacename> itself, neither
|
||||
<interfacename>BeanPostProcessors</interfacename> nor the beans they reference
|
||||
directly are eligible for auto-proxying, and thus do not have aspects woven
|
||||
into them.</para>
|
||||
|
||||
<para>For any such bean, you should see an informational log message:
|
||||
<quote><emphasis>Bean foo is not eligible for getting processed by all
|
||||
BeanPostProcessor interfaces (for example: not eligible for
|
||||
auto-proxying)</emphasis></quote>.</para>
|
||||
</note>
|
||||
|
||||
<para>The following examples show how to write, register, and use
|
||||
<literal>BeanPostProcessors</literal> in 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 simple Java application 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 application 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 a
|
||||
<interfacename>BeanFactoryPostProcessor</interfacename></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 those of 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>, and 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>
|
||||
(i.e., 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 standard container 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> be applied to the bean
|
||||
definitions in that container. Bean definitions in one 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 an <interfacename>ApplicationContext</interfacename>,
|
||||
in order to apply changes to the configuration metadata that define the
|
||||
container. Spring includes a number of predefined 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> automatically
|
||||
detects any beans that are deployed into it that implement the
|
||||
<interfacename>BeanFactoryPostProcessor</interfacename> interface. It
|
||||
uses these beans as bean factory post-processors, at the
|
||||
appropriate time. You can deploy these post-processor beans as you
|
||||
would any other bean.</para>
|
||||
|
||||
<note>
|
||||
<para>As with <interfacename>BeanPostProcessor</interfacename>s, you typically
|
||||
do not want to configure <interfacename>BeanFactoryPostProcessor</interfacename>s
|
||||
for lazy initialization. If no other bean references a
|
||||
<interfacename>Bean(Factory)PostProcessor</interfacename>,
|
||||
that post-processor will not get instantiated at all. Thus, marking it for
|
||||
lazy initialization will be ignored, and the
|
||||
<interfacename>Bean(Factory)PostProcessor</interfacename> will be
|
||||
instantiated eagerly even if you set the <literal>default-lazy-init</literal>
|
||||
attribute to <literal>true</literal> on the declaration of your
|
||||
<code><beans /></code> element.</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 in a separate
|
||||
file using 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 <emphasis>placeholders</emphasis> 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>jdbc.driverClassName=org.hsqldb.jdbcDriver
|
||||
jdbc.url=jdbc:hsqldb:hsql://production:9002
|
||||
jdbc.username=sa
|
||||
jdbc.password=root</programlisting>
|
||||
|
||||
<para>Therefore, the string <literal>${jdbc.username}</literal> is replaced
|
||||
at runtime with the value 'sa', and the same applies for other placeholder
|
||||
values that match keys in the properties file. The
|
||||
<classname>PropertyPlaceholderConfigurer</classname> checks for
|
||||
placeholders in most properties and attributes of a bean definition.
|
||||
Furthermore, 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. One or more locations can be provided 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> not only
|
||||
looks for properties in the <classname>Properties</classname> file
|
||||
you specify. By default it also checks against the Java
|
||||
<classname>System</classname> properties if it cannot find a property
|
||||
in the specified properties files. You can customize this behavior by setting the
|
||||
<literal>systemPropertiesMode</literal> property of the configurer with
|
||||
one of the following three supported integer values:
|
||||
<!--What property is it overriding and what will replace the overridden value?-->
|
||||
<!--MLP: override a value in the Properties with one from the 'systemProperties' -->
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><emphasis>never</emphasis> (0): Never check system properties</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><emphasis>fallback</emphasis> (1): Check system properties if not resolvable in the specified properties files. This is the default.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><emphasis>override</emphasis> (2): Check system properties first, before trying the specified properties files. This allows system properties to override any other property source.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
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 being 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 can be used with 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>
|
||||
|
||||
<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>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 a
|
||||
<interfacename>FactoryBean</interfacename></title>
|
||||
|
||||
<para>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 instead of the bean
|
||||
it produces, preface the bean's id with the ampersand symbol
|
||||
(<literal>&</literal>) 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>; whereas, 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>
|
||||
908
src/reference/docbook/beans-java.xml
Normal file
@@ -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 /app/* to the dispatcher servlet -->
|
||||
<servlet-mapping>
|
||||
<servlet-name>dispatcher</servlet-name>
|
||||
<url-pattern>/app/*</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>
|
||||
686
src/reference/docbook/beans-scopes.xml
Normal file
@@ -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><!-- instructs the container to proxy the surrounding bean --></lineannotation>
|
||||
<emphasis role="bold"><aop:scoped-proxy/></emphasis>
|
||||
</bean>
|
||||
|
||||
<lineannotation><!-- a singleton-scoped bean <emphasis role="bold">injected with a proxy to the above bean</emphasis> --></lineannotation>
|
||||
<bean id="userService" class="com.foo.SimpleUserService">
|
||||
|
||||
<lineannotation><!-- a reference to the <emphasis role="bold">proxied</emphasis> <literal>userPreferences</literal> bean --></lineannotation>
|
||||
<property name="userPreferences" ref="userPreferences"/>
|
||||
|
||||
</bean>
|
||||
</beans>
|
||||
</programlisting>
|
||||
|
||||
<para>To create such a proxy, you insert a child
|
||||
<literal><aop:scoped-proxy/></literal> element into a scoped bean
|
||||
definition.
|
||||
<!--To create what such proxy? Is the proxy created above? Also, below added an x-ref that seems relevant.-->(If
|
||||
you choose class-based proxying, you also need the CGLIB library in your
|
||||
classpath. See <xref
|
||||
linkend="beans-factory-scopes-other-injection-proxies"/> and <xref
|
||||
linkend="xsd-config"/>.) Why do definitions of beans scoped at the
|
||||
<literal>request</literal>, <literal>session</literal>,
|
||||
<literal>globalSession</literal> and custom-scope levels require the
|
||||
<literal><aop:scoped-proxy/></literal> element ? Let's examine the
|
||||
following singleton bean definition and contrast it with what you need
|
||||
to define for the aforementioned scopes. (The following
|
||||
<literal>userPreferences</literal> bean definition as it stands is
|
||||
<emphasis>incomplete.)</emphasis></para>
|
||||
|
||||
<programlisting language="xml"><bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>
|
||||
|
||||
<bean id="userManager" class="com.foo.UserManager">
|
||||
<property name="userPreferences" ref="userPreferences"/>
|
||||
</bean></programlisting>
|
||||
|
||||
<para>In the preceding example, the singleton bean
|
||||
<literal>userManager</literal> is injected with a reference to the HTTP
|
||||
<interfacename>Session</interfacename>-scoped bean
|
||||
<literal>userPreferences</literal>. The salient point here is that the
|
||||
<literal>userManager</literal> bean is a singleton: it will be
|
||||
instantiated <emphasis>exactly once</emphasis> per container, and its
|
||||
dependencies (in this case only one, the
|
||||
<literal>userPreferences</literal> bean) are also injected only once.
|
||||
This means that the <literal>userManager</literal> bean will only
|
||||
operate on the exact same <literal>userPreferences</literal> object,
|
||||
that is, the one that it was originally injected with.</para>
|
||||
|
||||
<!-- MLP: Beverly to review paragraph -->
|
||||
|
||||
<para>This is <emphasis>not</emphasis> the behavior you want when
|
||||
injecting a shorter-lived scoped bean into a longer-lived scoped bean,
|
||||
for example injecting an HTTP
|
||||
<interfacename>Session</interfacename>-scoped collaborating bean as a
|
||||
dependency into singleton bean. Rather, you need a single
|
||||
<literal>userManager</literal> object, and for the lifetime of an HTTP
|
||||
<interfacename>Session</interfacename>, you need a
|
||||
<literal>userPreferences</literal> object that is specific to said HTTP
|
||||
<interfacename>Session</interfacename>. Thus the container creates an
|
||||
object that exposes the exact same public interface as the
|
||||
<classname>UserPreferences</classname> class (ideally an object that
|
||||
<emphasis>is a</emphasis> <classname>UserPreferences</classname>
|
||||
instance) which can fetch the real
|
||||
<classname>UserPreferences</classname> object from the scoping mechanism
|
||||
(HTTP request, <interfacename>Session</interfacename>, etc.). The
|
||||
container injects this proxy object into the
|
||||
<literal>userManager</literal> bean, which is unaware that this
|
||||
<classname>UserPreferences</classname> reference is a proxy. In this
|
||||
example, when a <interfacename>UserManager</interfacename> instance
|
||||
invokes a method on the dependency-injected
|
||||
<classname>UserPreferences</classname> object, it actually is invoking a
|
||||
method on the proxy. The proxy then fetches the real
|
||||
<classname>UserPreferences</classname> object from (in this case) the
|
||||
HTTP <interfacename>Session</interfacename>, and delegates the method
|
||||
invocation onto the retrieved real
|
||||
<classname>UserPreferences</classname> object.</para>
|
||||
|
||||
<para>Thus you need the following, correct and complete, configuration
|
||||
when injecting <literal>request-</literal>, <literal>session-</literal>,
|
||||
and <literal>globalSession-scoped</literal> beans into collaborating
|
||||
objects:</para>
|
||||
|
||||
<programlisting language="xml"><bean id="userPreferences" class="com.foo.UserPreferences" scope="session">
|
||||
<emphasis role="bold"><literal><aop:scoped-proxy/></literal></emphasis>
|
||||
</bean>
|
||||
|
||||
<bean id="userManager" class="com.foo.UserManager">
|
||||
<property name="userPreferences" ref="userPreferences"/>
|
||||
</bean></programlisting>
|
||||
|
||||
<section id="beans-factory-scopes-other-injection-proxies">
|
||||
<title>Choosing the type of proxy to create</title>
|
||||
|
||||
<para>By default, when the Spring container creates a proxy for a bean
|
||||
that is marked up with the
|
||||
<literal><aop:scoped-proxy/></literal> element, <emphasis>a
|
||||
CGLIB-based class proxy is created</emphasis>. This means that you
|
||||
need to have the CGLIB library in the classpath of your
|
||||
application.</para>
|
||||
|
||||
<para><emphasis>Note: CGLIB proxies only intercept public method
|
||||
calls!</emphasis> Do not call non-public methods on such a proxy; they
|
||||
will not be delegated to the scoped target object.</para>
|
||||
|
||||
<para>Alternatively, you can configure the Spring container to create
|
||||
standard JDK interface-based proxies for such scoped beans, by
|
||||
specifying <literal>false</literal> for the value of the
|
||||
<literal>proxy-target-class</literal> attribute of the
|
||||
<literal><aop:scoped-proxy/></literal> element. Using JDK
|
||||
interface-based proxies means that you do not need additional
|
||||
libraries in your application classpath to effect such proxying.
|
||||
However, it also means that the class of the scoped bean must
|
||||
implement at least one interface, and <emphasis>that all</emphasis>
|
||||
collaborators into which the scoped bean is injected must reference
|
||||
the bean through one of its interfaces.</para>
|
||||
|
||||
<programlisting language="xml"><lineannotation><!-- <classname>DefaultUserPreferences</classname> implements the <interfacename>UserPreferences</interfacename> interface --></lineannotation>
|
||||
<bean id="userPreferences" class="com.foo.DefaultUserPreferences" scope="session">
|
||||
<aop:scoped-proxy <emphasis role="bold">proxy-target-class="false"<literal/></emphasis>/>
|
||||
</bean>
|
||||
|
||||
<bean id="userManager" class="com.foo.UserManager">
|
||||
<property name="userPreferences" ref="userPreferences"/>
|
||||
</bean></programlisting>
|
||||
|
||||
<para>For more detailed information about choosing class-based or
|
||||
interface-based proxying, see <xref linkend="aop-proxying"/>.</para>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="beans-factory-scopes-custom">
|
||||
<title>Custom scopes</title>
|
||||
|
||||
<para>As of Spring 2.0, the bean scoping mechanism is extensible. You can
|
||||
define your own scopes, or even redefine existing scopes, although the
|
||||
latter is considered bad practice and you <emphasis>cannot</emphasis>
|
||||
override the built-in <literal>singleton</literal> and
|
||||
<literal>prototype</literal> scopes.</para>
|
||||
|
||||
<section id="beans-factory-scopes-custom-creating">
|
||||
<title>Creating a custom scope</title>
|
||||
|
||||
<para>To integrate your custom scope(s) into the Spring container, you
|
||||
need to implement the
|
||||
<interfacename>org.springframework.beans.factory.config.Scope</interfacename>
|
||||
interface, which is described in this section. For an idea of how to
|
||||
implement your own scopes, see the <interfacename>Scope</interfacename>
|
||||
implementations that are supplied with the Spring Framework itself and
|
||||
the <ulink
|
||||
url="http://static.springframework.org/spring/docs/3.0.x/javadoc-api/org/springframework/beans/factory/config/Scope.html"
|
||||
>Scope Javadoc</ulink>, which explains the methods you need to implement
|
||||
in more detail.</para>
|
||||
|
||||
<para>The <literal>Scope</literal> interface has four methods to get
|
||||
objects from the scope, remove them from the scope, and allow them to be
|
||||
destroyed.</para>
|
||||
|
||||
<para>The following method returns the object from the underlying scope.
|
||||
The session scope implementation, for example, returns the
|
||||
session-scoped bean (and if it does not exist, the method returns a new
|
||||
instance of the bean, after having bound it to the session for future
|
||||
reference).<!--How can it return a a new instance of a bean that doesn't exist? Revise to clarify.--></para>
|
||||
|
||||
<programlisting language="java">Object get(String name, ObjectFactory objectFactory)</programlisting>
|
||||
|
||||
<para>The following method removes the object from the underlying scope.
|
||||
The session scope implementation for example, removes the session-scoped
|
||||
bean from the underlying session. The object should be returned, but you
|
||||
can return null if the object with the specified name is not
|
||||
found.</para>
|
||||
|
||||
<programlisting language="java">Object remove(String name)</programlisting>
|
||||
|
||||
<para>The following method registers the callbacks the scope should
|
||||
execute when it is destroyed or when the specified object in the scope
|
||||
is destroyed. Refer to the Javadoc or a Spring scope implementation for
|
||||
more information on destruction callbacks.</para>
|
||||
|
||||
<programlisting language="java">void registerDestructionCallback(String name, Runnable destructionCallback)</programlisting>
|
||||
|
||||
<para>The following method obtains the conversation identifier for the
|
||||
underlying scope. This identifier is different for each scope. For a
|
||||
session scoped implementation, this identifier can be the session
|
||||
identifier.</para>
|
||||
|
||||
<programlisting language="java">String getConversationId()</programlisting>
|
||||
</section>
|
||||
|
||||
<section id="beans-factory-scopes-custom-using">
|
||||
<title>Using a custom scope</title>
|
||||
|
||||
<para>After you write and test one or more custom
|
||||
<interfacename>Scope</interfacename> implementations, you need to make
|
||||
the Spring container aware of your new scope(s). The following method is
|
||||
the central method to register a new
|
||||
<interfacename>Scope</interfacename> with the Spring container:</para>
|
||||
|
||||
<programlisting language="java">void registerScope(String scopeName, Scope scope);</programlisting>
|
||||
|
||||
<para>This method is declared on the
|
||||
<interfacename>ConfigurableBeanFactory</interfacename> interface, which
|
||||
is available on most of the concrete
|
||||
<interfacename>ApplicationContext</interfacename> implementations that
|
||||
ship with Spring via the BeanFactory property.</para>
|
||||
|
||||
<para>The first argument to the <methodname>registerScope(..)</methodname>
|
||||
method is the unique name associated with a scope; examples of such
|
||||
names in the Spring container itself are <literal>singleton</literal>
|
||||
and <literal>prototype</literal>. The second argument to the
|
||||
<methodname>registerScope(..)</methodname> method is an actual instance
|
||||
of the custom <interfacename>Scope</interfacename> implementation that
|
||||
you wish to register and use.</para>
|
||||
|
||||
<para>Suppose that you write your custom
|
||||
<interfacename>Scope</interfacename> implementation, and then register
|
||||
it as below.</para>
|
||||
|
||||
<note>
|
||||
<para>The example below uses <literal>SimpleThreadScope</literal> which
|
||||
is included with Spring, but not registered by default. The
|
||||
instructions would be the same for your own custom
|
||||
<literal>Scope</literal> implementations.</para>
|
||||
</note>
|
||||
|
||||
<programlisting language="java">
|
||||
Scope threadScope = new SimpleThreadScope();
|
||||
beanFactory.registerScope("<emphasis role="bold">thread</emphasis>", threadScope);</programlisting>
|
||||
|
||||
<para>You then create bean definitions that adhere to the scoping rules of
|
||||
your custom <interfacename>Scope</interfacename>:</para>
|
||||
|
||||
<programlisting language="xml"><bean id="..." class="..." scope="thread"></programlisting>
|
||||
|
||||
<para>With a custom <interfacename>Scope</interfacename> implementation,
|
||||
you are not limited to programmatic registration of the scope. You can
|
||||
also do the <interfacename>Scope</interfacename> registration
|
||||
declaratively, using the <classname>CustomScopeConfigurer</classname>
|
||||
class:</para>
|
||||
|
||||
<programlisting language="xml"><?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/aop
|
||||
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
|
||||
|
||||
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
|
||||
<property name="scopes">
|
||||
<map><emphasis role="bold">
|
||||
<entry key="thread">
|
||||
<bean class="org.springframework.context.support.SimpleThreadScope"/>
|
||||
</entry></emphasis>
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="bar" class="x.y.Bar" scope="thread">
|
||||
<property name="name" value="Rick"/>
|
||||
<aop:scoped-proxy/>
|
||||
</bean>
|
||||
|
||||
<bean id="foo" class="x.y.Foo">
|
||||
<property name="bar" ref="bar"/>
|
||||
</bean>
|
||||
|
||||
</beans></programlisting>
|
||||
|
||||
<note>
|
||||
<para>When you place <aop:scoped-proxy/> in a
|
||||
<interfacename>FactoryBean</interfacename> implementation, it is the
|
||||
factory bean itself that is scoped, not the object returned from
|
||||
<methodname>getObject()</methodname>.</para>
|
||||
</note>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
200
src/reference/docbook/beans-standard-annotations.xml
Normal file
@@ -0,0 +1,200 @@
|
||||
<?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-standard-annotations">
|
||||
<title>Using JSR 330 Standard Annotations</title>
|
||||
|
||||
<para>Starting with Spring 3.0, Spring offers support for JSR-330 standard annotations (Dependency Injection).
|
||||
Those annotations are scanned in the same way as the Spring annotations. You just need to have the relevant jars in your classpath.
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
If you are using Maven, the <interfacename>javax.inject</interfacename> artifact is available
|
||||
in the standard Maven repository
|
||||
(<ulink url="http://repo1.maven.org/maven2/javax/inject/javax.inject/1/">http://repo1.maven.org/maven2/javax/inject/javax.inject/1/</ulink>).
|
||||
You can add the following dependency to your file pom.xml:
|
||||
</para>
|
||||
<programlisting language="xml">
|
||||
<dependency>
|
||||
<groupId>javax.inject</groupId>
|
||||
<artifactId>javax.inject</artifactId>
|
||||
<version>1</version>
|
||||
</dependency></programlisting>
|
||||
</note>
|
||||
|
||||
<section id="beans-inject-named">
|
||||
<title>Dependency Injection with <interfacename>@Inject</interfacename> and <interfacename>@Named</interfacename></title>
|
||||
|
||||
<para>Instead of <interfacename>@Autowired</interfacename>,
|
||||
<interfacename>@javax.inject.Inject</interfacename> may be used as follows:
|
||||
|
||||
<programlisting language="java">import javax.inject.Inject;
|
||||
|
||||
public class SimpleMovieLister {
|
||||
|
||||
private MovieFinder movieFinder;
|
||||
|
||||
@Inject
|
||||
public void setMovieFinder(MovieFinder movieFinder) {
|
||||
this.movieFinder = movieFinder;
|
||||
}
|
||||
<lineannotation>// ...</lineannotation>
|
||||
}</programlisting>
|
||||
</para>
|
||||
|
||||
<para>As with <interfacename>@Autowired</interfacename>, it is possible to use <interfacename>@Inject</interfacename>
|
||||
at the class-level, field-level, method-level and constructor-argument level.
|
||||
|
||||
If you would like to use a qualified name for the dependency that should be injected,
|
||||
you should use the <interfacename>@Named</interfacename> annotation as follows:
|
||||
|
||||
<programlisting language="java">import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
public class SimpleMovieLister {
|
||||
|
||||
private MovieFinder movieFinder;
|
||||
|
||||
@Inject
|
||||
public void setMovieFinder(@Named("main") MovieFinder movieFinder) {
|
||||
this.movieFinder = movieFinder;
|
||||
}
|
||||
<lineannotation>// ...</lineannotation>
|
||||
}</programlisting>
|
||||
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="beans-named">
|
||||
<title><interfacename>@Named</interfacename>: a standard equivalent to the <interfacename>@Component</interfacename> annotation</title>
|
||||
<para>
|
||||
Instead of <interfacename>@Component</interfacename>, <interfacename>@javax.inject.Named</interfacename> may be used as follows:
|
||||
<programlisting language="java">import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
@Named("movieListener")
|
||||
public class SimpleMovieLister {
|
||||
|
||||
private MovieFinder movieFinder;
|
||||
|
||||
@Inject
|
||||
public void setMovieFinder(MovieFinder movieFinder) {
|
||||
this.movieFinder = movieFinder;
|
||||
}
|
||||
<lineannotation>// ...</lineannotation>
|
||||
}</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
It is very common to use <interfacename>@Component</interfacename> without
|
||||
specifying a name for the component. <interfacename>@Named</interfacename>
|
||||
can be used in a similar fashion:
|
||||
|
||||
<programlisting language="java">import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
@Named
|
||||
public class SimpleMovieLister {
|
||||
|
||||
private MovieFinder movieFinder;
|
||||
|
||||
@Inject
|
||||
public void setMovieFinder(MovieFinder movieFinder) {
|
||||
this.movieFinder = movieFinder;
|
||||
}
|
||||
<lineannotation>// ...</lineannotation>
|
||||
}</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
When using <interfacename>@Named</interfacename>, it is possible to use
|
||||
component-scanning in the exact same way as when using Spring annotations:
|
||||
|
||||
<programlisting language="xml"><beans>
|
||||
<context:component-scan base-package="org.example"/>
|
||||
</beans></programlisting>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="beans-standard-annotations-limitations">
|
||||
<title>Limitations of the standard approach</title>
|
||||
|
||||
<para>When working with standard annotations, it is important to know that
|
||||
some significant features are not available as shown in the table below:</para>
|
||||
|
||||
<para><table id="annotations-comparison">
|
||||
<title>Spring annotations vs. standard annotations</title>
|
||||
|
||||
<tgroup cols="3">
|
||||
|
||||
<colspec colnum="1" colwidth="0.7*" />
|
||||
<colspec colnum="2" colwidth="0.6*" />
|
||||
<colspec colnum="3" colwidth="1.5*" />
|
||||
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Spring</entry>
|
||||
<entry>javax.inject.*</entry>
|
||||
<entry>javax.inject restrictions / comments</entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>@Autowired</entry>
|
||||
<entry>@Inject</entry>
|
||||
<entry>@Inject has no 'required' attribute</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>@Component</entry>
|
||||
<entry>@Named</entry>
|
||||
<entry>—</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>@Scope("singleton")</entry>
|
||||
<entry>@Singleton</entry>
|
||||
<entry>
|
||||
<para>
|
||||
The JSR-330 default scope is like Spring's <interfacename>prototype</interfacename>.
|
||||
However, in order to keep it consistent with Spring's general defaults,
|
||||
a JSR-330 bean declared in the Spring container is a
|
||||
<interfacename>singleton</interfacename> by default. In order to use a
|
||||
scope other than <interfacename>singleton</interfacename>, you should use Spring's
|
||||
<interfacename>@Scope</interfacename> annotation.
|
||||
</para>
|
||||
<para>
|
||||
<interfacename>javax.inject</interfacename> also provides a
|
||||
<ulink url="http://download.oracle.com/javaee/6/api/javax/inject/Scope.html">@Scope</ulink> annotation.
|
||||
Nevertheless, this one is only intended to be used for creating your own annotations.
|
||||
</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>@Qualifier</entry>
|
||||
<entry>@Named</entry>
|
||||
<entry>—</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>@Value</entry>
|
||||
<entry>—</entry>
|
||||
<entry>no equivalent</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>@Required</entry>
|
||||
<entry>—</entry>
|
||||
<entry>no equivalent</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>@Lazy</entry>
|
||||
<entry>—</entry>
|
||||
<entry>no equivalent</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
</section>
|
||||
1179
src/reference/docbook/beans.xml
Normal file
584
src/reference/docbook/cache.xml
Normal file
@@ -0,0 +1,584 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
|
||||
<chapter id="cache">
|
||||
<title>Cache Abstraction</title>
|
||||
|
||||
<section id="cache-introduction">
|
||||
<title>Introduction</title>
|
||||
|
||||
<para>Since version 3.1, Spring Framework provides support for transparently
|
||||
adding caching into an existing Spring application. Similar to the <link linkend="transaction">transaction</link>
|
||||
support, the caching abstraction allows consistent use of various caching
|
||||
solutions with minimal impact on the code.</para>
|
||||
</section>
|
||||
|
||||
<section id="cache-strategies">
|
||||
<title>Understanding the cache abstraction</title>
|
||||
|
||||
<sidebar>
|
||||
<title>Cache vs Buffer</title>
|
||||
<para>The terms "buffer" and "cache" tend to be used interchangeably; note however they represent different things.
|
||||
A buffer is used traditionally as an intermediate temporary store for data between a fast and a slow entity. As one
|
||||
party would have to <emphasis>wait</emphasis> for the other affecting performance, the buffer alleviates this by
|
||||
allowing entire blocks of data to move at once rather then in small chunks. The data is written and read only once from
|
||||
the buffer. Furthermore, the buffers are <emphasis>visible</emphasis> to at least one party which is aware of it.</para>
|
||||
<para>A cache on the other hand by definition is hidden and neither party is aware that caching occurs.It as well improves
|
||||
performance but does that by allowing the same data to be read multiple times in a fast fashion.</para>
|
||||
|
||||
<para>A further explanation of the differences between two can be found
|
||||
<ulink url="http://en.wikipedia.org/wiki/Cache#The_difference_between_buffer_and_cache">here</ulink>.</para>
|
||||
</sidebar>
|
||||
|
||||
<para>At its core, the abstraction applies caching to Java methods, reducing thus the number of executions based on the
|
||||
information available in the cache. That is, each time a <emphasis>targeted</emphasis> method is invoked, the abstraction
|
||||
will apply a caching behaviour checking whether the method has been already executed for the given arguments. If it has,
|
||||
then the cached result is returned without having to execute the actual method; if it has not, then method is executed, the
|
||||
result cached and returned to the user so that, the next time the method is invoked, the cached result is returned.
|
||||
This way, expensive methods (whether CPU or IO bound) can be executed only once for a given set of parameters and the result
|
||||
reused without having to actually execute the method again. The caching logic is applied transparently without any interference
|
||||
to the invoker.</para>
|
||||
|
||||
<important>Obviously this approach works only for methods that are guaranteed to return the same output (result) for a given input
|
||||
(or arguments) no matter how many times it is being executed.</important>
|
||||
|
||||
<para>To use the cache abstraction, the developer needs to take care of two aspects:
|
||||
<itemizedlist>
|
||||
<listitem>caching declaration - identify the methods that need to be cached and their policy</listitem>
|
||||
<listitem>cache configuration - the backing cache where the data is stored and read from</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>Note that just like other services in Spring Framework, the caching service is an abstraction (not a cache implementation) and requires
|
||||
the use of an actual storage to store the cache data - that is, the abstraction frees the developer from having to write the caching
|
||||
logic but does not provide the actual stores. There are two integrations available out of the box, for JDK <literal>java.util.concurrent.ConcurrentMap</literal>
|
||||
and <ulink url="http://ehcache.org/">Ehcache</ulink> - see <xref linkend="cache-plug"/> for more information on plugging in other cache stores/providers.</para>
|
||||
</section>
|
||||
|
||||
<section id="cache-annotations">
|
||||
<title>Declarative annotation-based caching</title>
|
||||
|
||||
<para>For caching declaration, the abstraction provides two Java annotations: <literal>@Cacheable</literal> and <literal>@CacheEvict</literal> which allow methods
|
||||
to trigger cache population or cache eviction. Let us take a closer look at each annotation:</para>
|
||||
|
||||
<section id="cache-annotations-cacheable">
|
||||
<title><literal>@Cacheable</literal> annotation</title>
|
||||
|
||||
<para>As the name implies, <literal>@Cacheable</literal> is used to demarcate methods that are cacheable - that is, methods for whom the result is stored into the cache
|
||||
so on subsequent invocations (with the same arguments), the value in the cache is returned without having to actually execute the method. In its simplest form,
|
||||
the annotation declaration requires the name of the cache associated with the annotated method:</para>
|
||||
|
||||
<programlisting language="java"><![CDATA[@Cacheable("books")
|
||||
public Book findBook(ISBN isbn) {...}]]></programlisting>
|
||||
|
||||
<para>In the snippet above, the method <literal>findBook</literal> is associated with the cache named <literal>books</literal>. Each time the method is called, the cache
|
||||
is checked to see whether the invocation has been already executed and does not have to be repeated. While in most cases, only one cache is declared, the annotation allows multiple
|
||||
names to be specified so that more then one cache are being used. In this case, each of the caches will be checked before executing the method - if at least one cache is hit,
|
||||
then the associated value will be returned:</para>
|
||||
<note>All the other caches that do not contain the method will be updated as well even though the cached method was not actually
|
||||
executed.</note>
|
||||
|
||||
<programlisting language="java"><![CDATA[@Cacheable({ "books", "isbns" })
|
||||
public Book findBook(ISBN isbn) {...}]]></programlisting>
|
||||
|
||||
<section id="cache-annotations-cacheable-default-key">
|
||||
<title>Default Key Generation</title>
|
||||
|
||||
<para>Since caches are essentially key-value stores, each invocation of a cached method needs to be translated into a suitable key for cache access.
|
||||
Out of the box, the caching abstraction uses a simple <interfacename>KeyGenerator</interfacename> based on the following algorithm:</para>
|
||||
<itemizedlist>
|
||||
<listitem>If no params are given, return 0.</listitem>
|
||||
<listitem>If only one param is given, return that instance.</listitem>
|
||||
<listitem>If more the one param is given, return a key computed from the hashes of all parameters.</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
This approach works well for objects with <emphasis>natural keys</emphasis> as long as the <literal>hashCode()</literal> reflects that. If that is not the case then
|
||||
for distributed or persistent environments, the strategy needs to be changed as the objects hashCode is not preserved.
|
||||
In fact, depending on the JVM implementation or running conditions, the same hashCode can be reused for different objects, in the same VM instance.</para>
|
||||
|
||||
<para>To provide a different <emphasis>default</emphasis> key generator, one needs to implement the <interfacename>org.springframework.cache.KeyGenerator</interfacename> interface.
|
||||
Once configured, the generator will be used for each declaration that doesn not specify its own key generation strategy (see below).
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="cache-annotations-cacheable-key">
|
||||
<title>Custom Key Generation Declaration</title>
|
||||
|
||||
<para>Since caching is generic, it is quite likely the target methods have various signatures that cannot be simply mapped on top of the cache structure. This tends to become
|
||||
obvious when the target method has multiple arguments out of which only some are suitable for caching (while the rest are used only by the method logic). For example:</para>
|
||||
|
||||
<programlisting language="java"><![CDATA[@Cacheable("books")
|
||||
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed]]></programlisting>
|
||||
|
||||
<para>At first glance, while the two <literal>boolean</literal> arguments influence the way the book is found, they are no use for the cache. Further more what if only one of the two
|
||||
is important while the other is not?</para>
|
||||
|
||||
<para>For such cases, the <literal>@Cacheable</literal> annotation allows the user to specify how the key is generated through its <literal>key</literal> attribute.
|
||||
The developer can use <link linkend="expressions">SpEL</link> to pick the arguments of interest (or their nested properties), perform operations or even invoke arbitrary methods without
|
||||
having to write any code or implement any interface. This is the recommended approach over the <link linkend="cache-annotations-cacheable-default-key">default</link> generator since
|
||||
methods tend to be quite different in signatures as the code base grows; while the default strategy might work for some methods, it rarely does for all methods.</para>
|
||||
|
||||
<para>
|
||||
Below are some examples of various SpEL declarations - if you are not familiar with it, do yourself a favour and read <xref linkend="expressions"/>:
|
||||
</para>
|
||||
|
||||
<programlisting language="java"><!-- select 'isbn' argument -->
|
||||
@Cacheable(value="books", <emphasis role="bold">key="#isbn"</emphasis>
|
||||
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
|
||||
|
||||
<!-- select nested property of a certain argument -->
|
||||
@Cacheable(value="books", <emphasis role="bold">key="#isbn.rawNumber"</emphasis>)
|
||||
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
|
||||
|
||||
<!-- invoke arbitrary method using certain arguments -->
|
||||
@Cacheable(value="books", <emphasis role="bold">key="T(someType).hash(#isbn)"</emphasis>)
|
||||
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)</programlisting>
|
||||
|
||||
<para>The snippets above, show how easy it is to select a certain argument, one of its properties or even an arbitrary (static) method.</para>
|
||||
</section>
|
||||
|
||||
<section id="cache-annotations-cacheable-condition">
|
||||
<title>Conditional caching</title>
|
||||
|
||||
<para>Sometimes, a method might not be suitable for caching all the time (for example, it might depend on the given arguments). The cache annotations support such functionality
|
||||
through the <literal>conditional</literal> parameter which takes a <literal>SpEL</literal> expression that is evaluated to either <literal>true</literal> or <literal>false</literal>.
|
||||
If <literal>true</literal>, the method is cached - if not, it behaves as if the method is not cached, that is executed every since time no matter what values are in the cache or what
|
||||
arguments are used. A quick example - the following method will be cached, only if the argument <literal>name</literal> has a length shorter then 32:</para>
|
||||
|
||||
<programlisting language="java"><![CDATA[@Cacheable(value="book", condition="#name.length < 32")
|
||||
public Book findBook(String name)]]></programlisting>
|
||||
</section>
|
||||
|
||||
<section id="cache-spel-context">
|
||||
<title>Available caching <literal>SpEL</literal> evaluation context</title>
|
||||
|
||||
<para>Each <literal>SpEL</literal> expression evaluates again a dedicated <literal><link linkend="expressions-language-ref">context</link></literal>. In addition
|
||||
to the build in parameters, the framework provides dedicated caching related metadata such as the argument names. The next table lists the items made available to the context
|
||||
so one can use them for key and conditional(see next section) computations:</para>
|
||||
|
||||
<table id="cache-spel-context-tbl" pgwide="1">
|
||||
<title>Cache SpEL available metadata</title>
|
||||
<tgroup cols="4">
|
||||
<colspec align="center" />
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Name</entry>
|
||||
<entry>Location</entry>
|
||||
<entry>Description</entry>
|
||||
<entry>Example</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>methodName</entry>
|
||||
<entry>root object</entry>
|
||||
<entry>The name of the method being invoked</entry>
|
||||
<entry><screen>#root.methodName</screen></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>method</entry>
|
||||
<entry>root object</entry>
|
||||
<entry>The method being invoked</entry>
|
||||
<entry><screen>#root.method.name</screen></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>target</entry>
|
||||
<entry>root object</entry>
|
||||
<entry>The target object being invoked</entry>
|
||||
<entry><screen>#root.target</screen></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>targetClass</entry>
|
||||
<entry>root object</entry>
|
||||
<entry>The class of the target being invoked</entry>
|
||||
<entry><screen>#root.targetClass</screen></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>args</entry>
|
||||
<entry>root object</entry>
|
||||
<entry>The arguments (as array) used for invoking the target</entry>
|
||||
<entry><screen>#root.args[0]</screen></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>caches</entry>
|
||||
<entry>root object</entry>
|
||||
<entry>Collection of caches against which the current method is executed</entry>
|
||||
<entry><screen>#root.caches[0].name</screen></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><emphasis>argument name</emphasis></entry>
|
||||
<entry>evaluation context</entry>
|
||||
<entry>Name of any of the method argument. If for some reason the names are not available (ex: no debug information),
|
||||
the argument names are also available under the <literal><![CDATA[a<#arg>]]></literal> where
|
||||
<emphasis><![CDATA[#arg]]></emphasis> stands for the argument index (starting from 0).</entry>
|
||||
<entry><screen>iban</screen> or <screen>a0</screen> (one can also use <screen>p0</screen> or <literal><![CDATA[p<#arg>]]></literal> notation as an alias).</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="cache-annotations-put">
|
||||
<title><literal>@CachePut</literal> annotation</title>
|
||||
|
||||
<para>For cases where the cache needs to be updated without interferring with the method execution, one can use the <literal>@CachePut</literal> annotation. That is, the method will always
|
||||
be executed and its result placed into the cache (according to the <literal>@CachePut</literal> options). It supports the same options as <literal>@Cacheable</literal> and should be used
|
||||
for cache population rather then method flow optimization.</para>
|
||||
|
||||
<para>Note that using <literal>@CachePut</literal> and <literal>@Cacheable</literal> annotations on the same method is generaly discouraged because they have different behaviours. While the latter
|
||||
causes the method execution to be skipped by using the cache, the former forces the execution in order to execute a cache update. This leads to unexpected behaviour and with the exception of specific
|
||||
corner-cases (such as annotations having conditions that exclude them from each other), such declarations should be avoided.</para>
|
||||
</section>
|
||||
|
||||
<section id="cache-annotations-evict">
|
||||
<title><literal>@CacheEvict</literal> annotation</title>
|
||||
|
||||
<para>The cache abstraction allows not just population of a cache store but also eviction. This process is useful for removing stale or unused data from the cache. Opposed to
|
||||
<literal>@Cacheable</literal>, annotation <literal>@CacheEvict</literal> demarcates methods that perform cache <emphasis>eviction</emphasis>, that is methods that act as triggers
|
||||
for removing data from the cache. Just like its sibling, <literal>@CacheEvict</literal> requires one to specify one (or multiple) caches that are affected by the action, allows a
|
||||
key or a condition to be specified but in addition, features an extra parameter <literal>allEntries</literal> which indicates whether a cache-wide eviction needs to be performed
|
||||
rather then just an entry one (based on the key):</para>
|
||||
|
||||
<programlisting language="java"><![CDATA[@CacheEvict(value = "books", allEntries=true)
|
||||
public void loadBooks(InputStream batch)]]></programlisting>
|
||||
|
||||
<para>This option comes in handy when an entire cache region needs to be cleared out - rather then evicting each entry (which would take a long time since it is inefficient),
|
||||
all the entires are removed in one operation as shown above. Note that the framework will ignore any key specified in this scenario as it does not apply (the entire cache is evicted not just
|
||||
one entry).</para>
|
||||
|
||||
<para>One can also indicate whether the eviction should occur after (the default) or before the method executes through the <literal>beforeInvocation</literal> attribute.
|
||||
The former provides the same semantics as the rest of the annotations - once the method completes successfully, an action (in this case eviction) on the cache is executed. If the method does not
|
||||
execute (as it might be cached) or an exception is thrown, the eviction does not occur. The latter (<literal>beforeInvocation=true</literal>) causes the eviction to occur always, before the method
|
||||
is invoked - this is useful in cases where the eviction does not need to be tied to the method outcome.</para>
|
||||
|
||||
<para>It is important to note that void methods can be used with <literal>@CacheEvict</literal> - as the methods act as triggers, the return values are ignored (as they don't interact with
|
||||
the cache) - this is not the case with <literal>@Cacheable</literal> which adds/update data into the cache and thus requires a result.</para>
|
||||
</section>
|
||||
|
||||
<section id="cache-annotations-caching">
|
||||
<title><literal>@Caching</literal> annotation</title>
|
||||
|
||||
<para>There are cases when multiple annotations of the same type, such as <literal>@CacheEvict</literal> or <literal>@CachePut</literal> need to be specified, for example because the condition or the key
|
||||
expression is different between different caches. Unfortunately Java does not support such declarations however there is a workaround - using a <emphasis>enclosing</emphasis> annotation, in this case,
|
||||
<literal>@Caching</literal>. <literal>@Caching</literal> allows multiple nested <literal>@Cacheable</literal>, <literal>@CachePut</literal> and <literal>@CacheEvict</literal> to be used on the same method:</para>
|
||||
|
||||
<programlisting language="java"><![CDATA[@Caching(evict = { @CacheEvict("primary"), @CacheEvict(value = "secondary", key = "#p0") })
|
||||
public Book importBooks(String deposit, Date date)]]></programlisting>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="cache-annotation-enable">
|
||||
<title>Enable caching annotations</title>
|
||||
|
||||
<para>It is important to note that even though declaring the cache annotations does not automatically triggers their actions - like many things in Spring, the feature has to be declaratively
|
||||
enabled (which means if you ever suspect caching is to blame, you can disable it by removing only one configuration line rather then all the annotations in your code). In practice, this
|
||||
translates to one line that informs Spring that it should process the cache annotations, namely:</para>
|
||||
|
||||
<programlisting language="xml"><![CDATA[<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"]]>
|
||||
<emphasis role="bold">xmlns:cache="http://www.springframework.org/schema/cache"</emphasis><![CDATA[
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd]]>
|
||||
<emphasis role="bold">http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd</emphasis><![CDATA[">]]>
|
||||
<emphasis role="bold"><![CDATA[<cache:annotation-driven />]]></emphasis>
|
||||
<![CDATA[</beans>]]></programlisting>
|
||||
|
||||
<para>The namespace allows various options to be specified that influence the way the caching behaviour is added to the application through AOP. The configuration is similar (on purpose)
|
||||
with that of <literal><ulink url="tx-annotation-driven-settings">tx:annotation-driven</ulink></literal>:
|
||||
</para>
|
||||
|
||||
<para><table id="cache-annotation-driven-settings">
|
||||
<title><literal><cache:annotation-driven/></literal>
|
||||
settings</title>
|
||||
|
||||
<tgroup cols="3">
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Attribute</entry>
|
||||
|
||||
<entry>Default</entry>
|
||||
|
||||
<entry>Description</entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><literal>cache-manager</literal></entry>
|
||||
|
||||
<entry>cacheManager</entry>
|
||||
|
||||
<entry><para>Name of cache manager to use. Only required
|
||||
if the name of the cache manager is not
|
||||
<literal>cacheManager</literal>, as in the example
|
||||
above.</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><literal>mode</literal></entry>
|
||||
|
||||
<entry>proxy</entry>
|
||||
|
||||
<entry><para>The default mode "proxy" processes annotated
|
||||
beans to be proxied using Spring's AOP framework (following
|
||||
proxy semantics, as discussed above, applying to method calls
|
||||
coming in through the proxy only). The alternative mode
|
||||
"aspectj" instead weaves the affected classes with Spring's
|
||||
AspectJ caching aspect, modifying the target class byte
|
||||
code to apply to any kind of method call. AspectJ weaving
|
||||
requires spring-aspects.jar in the classpath as well as
|
||||
load-time weaving (or compile-time weaving) enabled. (See
|
||||
<xref linkend="aop-aj-ltw-spring" /> for details on how to set
|
||||
up load-time weaving.)</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><literal>proxy-target-class</literal></entry>
|
||||
|
||||
<entry>false</entry>
|
||||
|
||||
<entry><para>Applies to proxy mode only. Controls what type of
|
||||
caching proxies are created for classes annotated with
|
||||
the <interfacename>@Cacheable</interfacename> or <interfacename>@CacheEvict</interfacename> annotations.
|
||||
If the <literal>proxy-target-class</literal> attribute is set
|
||||
to <literal>true</literal>, then class-based proxies are
|
||||
created. If <literal>proxy-target-class</literal> is
|
||||
<literal>false</literal> or if the attribute is omitted, then
|
||||
standard JDK interface-based proxies are created. (See <xref
|
||||
linkend="aop-proxying" /> for a detailed examination of the
|
||||
different proxy types.)</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><literal>order</literal></entry>
|
||||
|
||||
<entry>Ordered.LOWEST_PRECEDENCE</entry>
|
||||
|
||||
<entry><para>Defines the order of the cache advice that
|
||||
is applied to beans annotated with
|
||||
<interfacename>@Cacheable</interfacename> or <interfacename>@CacheEvict</interfacename>.
|
||||
(For more
|
||||
information about the rules related to ordering of AOP advice,
|
||||
see <xref linkend="aop-ataspectj-advice-ordering" />.) No
|
||||
specified ordering means that the AOP subsystem determines the
|
||||
order of the advice.</para></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table></para>
|
||||
|
||||
<note>
|
||||
<para><literal><cache:annotation-driven/></literal> only looks for
|
||||
<interfacename>@Cacheable/@CacheEvict</interfacename> on beans in the same
|
||||
application context it is defined in. This means that, if you put
|
||||
<literal><cache:annotation-driven/></literal> in a
|
||||
<interfacename>WebApplicationContext</interfacename> for a
|
||||
<classname>DispatcherServlet</classname>, it only checks for
|
||||
<interfacename>@Cacheable/@CacheEvict</interfacename> beans in your
|
||||
controllers, and not your services. See <xref
|
||||
linkend="mvc-servlet" /> for more information.</para>
|
||||
</note>
|
||||
|
||||
<sidebar>
|
||||
<title>Method visibility and
|
||||
<interfacename>@Cacheable/@CachePut/@CacheEvict</interfacename></title>
|
||||
|
||||
<para>When using proxies, you should apply the
|
||||
<interfacename>@Cache*</interfacename> annotations only to
|
||||
methods with <emphasis>public</emphasis> visibility. If you do
|
||||
annotate protected, private or package-visible methods with these annotations,
|
||||
no error is raised, but the annotated method does not exhibit the configured
|
||||
caching settings. Consider the use of AspectJ (see below) if you
|
||||
need to annotate non-public methods as it changes the bytecode itself.</para>
|
||||
</sidebar>
|
||||
|
||||
<para><tip>
|
||||
<para>Spring recommends that you only annotate concrete classes (and
|
||||
methods of concrete classes) with the
|
||||
<interfacename>@Cache*</interfacename> annotation, as opposed
|
||||
to annotating interfaces. You certainly can place the
|
||||
<interfacename>@Cache*</interfacename> annotation on an
|
||||
interface (or an interface method), but this works only as you would
|
||||
expect it to if you are using interface-based proxies. The fact that
|
||||
Java annotations are <emphasis>not inherited from interfaces</emphasis>
|
||||
means that if you are using class-based proxies
|
||||
(<literal>proxy-target-class="true"</literal>) or the weaving-based
|
||||
aspect (<literal>mode="aspectj"</literal>), then the caching
|
||||
settings are not recognized by the proxying and weaving
|
||||
infrastructure, and the object will not be wrapped in a
|
||||
caching proxy, which would be decidedly
|
||||
<emphasis>bad</emphasis>.</para>
|
||||
</tip></para>
|
||||
|
||||
<note>
|
||||
<para>In proxy mode (which is the default), only external method calls
|
||||
coming in through the proxy are intercepted. This means that
|
||||
self-invocation, in effect, a method within the target object calling
|
||||
another method of the target object, will not lead to an actual
|
||||
caching at runtime even if the invoked method is marked with
|
||||
<interfacename>@Cacheable</interfacename> - considering using the aspectj mode in this case.</para>
|
||||
</note>
|
||||
</section>
|
||||
|
||||
<section id="cache-annotation-stereotype">
|
||||
<title>Using custom annotations</title>
|
||||
|
||||
<para>The caching abstraction allows one to use her own annotations to identify what method trigger cache population or eviction. This is quite handy as a template mechanism as it eliminates
|
||||
the need to duplicate cache annotation declarations (especially useful if the key or condition are specified) or if the foreign imports (<literal>org.springframework</literal>) are not allowed
|
||||
in your code base. Similar to the rest of the <link linkend="beans-stereotype-annotations">stereotype</link> annotations, both <literal>@Cacheable</literal> and <literal>@CacheEvict</literal>
|
||||
can be used as meta-annotations, that is annotations that can annotate other annotations. To wit, let us replace a common <literal>@Cacheable</literal> declaration with our own, custom
|
||||
annotation:
|
||||
</para>
|
||||
|
||||
<programlisting language="java"><![CDATA[@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.METHOD})
|
||||
@Cacheable(value=“books”, key="#isbn")
|
||||
public @interface SlowService {
|
||||
}]]></programlisting>
|
||||
|
||||
<para>Above, we have defined our own <literal>SlowService</literal> annotation which itself is annotated with <literal>@Cacheable</literal> - now we can replace the following code:</para>
|
||||
|
||||
<programlisting language="java"><![CDATA[@Cacheable(value="books", key="#isbn")
|
||||
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)]]></programlisting>
|
||||
|
||||
<para>with:</para>
|
||||
|
||||
<programlisting language="java"><![CDATA[@SlowService
|
||||
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)]]></programlisting>
|
||||
|
||||
<para>Even though <literal>@SlowService</literal> is not a Spring annotation, the container automatically picks up its declaration at runtime and understands its meaning. Note that as
|
||||
mentined <link linkend="cache-annotation-enable">above</link>, the annotation-driven behaviour needs to be enabled.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="cache-declarative-xml">
|
||||
<title>Declarative XML-based caching</title>
|
||||
|
||||
<para>If annotations are not an option (no access to the sources or no external code), one can use XML for declarative caching. So instead of annotating the methods for caching, one specifies
|
||||
the target method and the caching directives externally (similar to the declarative transaction management <link linkend="transaction-declarative-first-example">advice</link>). The previous example
|
||||
can be translated into:</para>
|
||||
|
||||
<programlisting language="xml"><![CDATA[<!-- the service we want to make cacheable -->
|
||||
<bean id="bookService" class="x.y.service.DefaultBookService"/>
|
||||
|
||||
<!-- cache definitions -->
|
||||
<cache:advice id="cacheAdvice" cache-manager="cacheManager">
|
||||
<cache:caching cache="books">
|
||||
<cache:cacheable method="findBook" key="#isbn"/>
|
||||
<cache:cache-evict method="loadBooks" all-entries="true"/>
|
||||
</cache:caching>
|
||||
</cache:advice>
|
||||
|
||||
<!-- apply the cacheable behaviour to all BookService interfaces -->
|
||||
<aop:config>
|
||||
<aop:advisor advice-ref="cacheAdvice" pointcut="execution(* x.y.BookService.*(..))"/>
|
||||
</aop:config>
|
||||
...
|
||||
// cache manager definition omitted
|
||||
]]>
|
||||
</programlisting>
|
||||
|
||||
<para>In the configuration above, the <literal>bookService</literal> is made cacheable. The caching semantics to apply are encapsulated in the <literal>cache:advice</literal> definition which
|
||||
instructs method <literal>findBooks</literal> to be used for putting data into the cache while method <literal>loadBooks</literal> for evicting data. Both definitions are working against the
|
||||
<literal>books</literal> cache.</para>
|
||||
|
||||
<para>The <literal>aop:config</literal> definition applies the cache advice to the appropriate points in the program by using the AspectJ pointcut expression (more information is available
|
||||
in <xref linkend="aop" />). In the example above, all methods from the <interfacename>BookService</interfacename> are considered and the cache advice applied to them.</para>
|
||||
|
||||
<para>The declarative XML caching supports all of the annotation-based model so moving between the two should be fairly easy - further more both can be used inside the same application.
|
||||
The XML based approach does not touch the target code however it is inherently more verbose; when dealing with classes with overloaded methods that are targeted for caching, identifying the
|
||||
proper methods does take an extra effort since the <literal>method</literal> argument is not a good discriminator - in these cases, the AspectJ pointcut can be used to cherry pick the target
|
||||
methods and apply the appropriate caching functionality. Howeve through XML, it is easier to apply a package/group/interface-wide caching (again due to the AspectJ poincut) and to create
|
||||
template-like definitions (as we did in the example above by defining the target cache through the <literal>cache:definitions </literal><literal>cache</literal> attribute).
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="cache-store-configuration">
|
||||
<title>Configuring the cache storage</title>
|
||||
|
||||
<para>Out of the box, the cache abstraction provides integration with two storages - one on top of the JDK <interfacename>ConcurrentMap</interfacename> and one
|
||||
for <ulink url="ehcache.org">ehcache</ulink> library. To use them, one needs to simply declare an appropriate <interfacename>CacheManager</interfacename> - an entity that controls and manages
|
||||
<interfacename>Cache</interfacename>s and can be used to retrieve these for storage.</para>
|
||||
|
||||
<section id="cache-store-configuration-jdk">
|
||||
<title>JDK <interfacename>ConcurrentMap</interfacename>-based <interfacename>Cache</interfacename></title>
|
||||
|
||||
<para>The JDK-based <interfacename>Cache</interfacename> implementation resides under <literal>org.springframework.cache.concurrent</literal> package. It allows one to use <classname>
|
||||
ConcurrentHashMap</classname> as a backing <interfacename>Cache</interfacename> store.</para>
|
||||
|
||||
<programlisting language="xml"><![CDATA[<!-- generic cache manager -->
|
||||
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
|
||||
<property name="caches">
|
||||
<set>
|
||||
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="default"/>
|
||||
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="books"/>
|
||||
</set>
|
||||
</property>
|
||||
</bean>]]></programlisting>
|
||||
|
||||
<para>The snippet above uses the <classname>SimpleCacheManager</classname> to create a <interfacename>CacheManager</interfacename> for the two, nested <interfacename>Concurrent</interfacename>
|
||||
<interfacename>Cache</interfacename> implementations named <emphasis>default</emphasis> and <emphasis>books</emphasis>.
|
||||
Note that the names are configured directly for each cache.</para>
|
||||
|
||||
<para>As the cache is created by the application, it is bound to its lifecycle, making it suitable for basic use cases, tests or simple applications. The cache scales well and is very fast
|
||||
but it does not provide any management or persistence capabilities nor eviction contracts.</para>
|
||||
</section>
|
||||
|
||||
<section id="cache-store-configuration-ehcache">
|
||||
<title>Ehcache-based <interfacename>Cache</interfacename></title>
|
||||
|
||||
<para>The Ehcache implementation is located under <literal>org.springframework.cache.ehcache</literal> package. Again, to use it, one simply needs to declare the appropriate
|
||||
<interfacename>CacheManager</interfacename>:</para>
|
||||
|
||||
<programlisting language="xml"><![CDATA[<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cache-manager-ref="ehcache"/>
|
||||
|
||||
<!-- Ehcache library setup -->
|
||||
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:config-location="ehcache.xml"/>]]></programlisting>
|
||||
|
||||
<para>This setup bootstraps ehcache library inside Spring IoC (through bean <literal>ehcache</literal>) which is then wired into the dedicated <interfacename>CacheManager</interfacename>
|
||||
implementation. Note the entire ehcache-specific configuration is read from the resource <literal>ehcache.xml</literal>.</para>
|
||||
</section>
|
||||
|
||||
<section id="cache-store-configuration-noop">
|
||||
<title>Dealing with caches without a backing store</title>
|
||||
|
||||
<para>Sometimes when switching environments or doing testing, one might have cache declarations without an actual backing cache configured. As this is an invalid configuration, at runtime an
|
||||
exception will be through since the caching infrastructure is unable to find a suitable store. In situations like this, rather then removing the cache declarations (which can prove tedious),
|
||||
one can wire in a simple, dummy cache that performs no caching - that is, forces the cached methods to be executed every time:</para>
|
||||
|
||||
<programlisting language="xml"><![CDATA[<bean id="cacheManager" class="org.springframework.cache.support.CompositeCacheManager">
|
||||
<property name="cacheManagers"><list>
|
||||
<ref bean="jdkCache"/>
|
||||
<ref bean="gemfireCache"/>
|
||||
</list></property>
|
||||
<property name="addNoOpCache" value="true"/>
|
||||
</bean>]]></programlisting>
|
||||
|
||||
<para>The <literal>CompositeCacheManager</literal> above chains multiple <literal>CacheManager</literal>s and aditionally, through the <literal>addNoOpManager</literal> flag, adds a
|
||||
<emphasis>no op</emphasis> cache that for all the definitions not handled by the configured cache managers. That is, every cache definition not found in either <literal>jdkCache</literal>
|
||||
or <literal>gemfireCache</literal> (configured above) will be handled by the no op cache, which will not store any information causing the target method to be executed every time.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="cache-plug">
|
||||
<title>Plugging-in different back-end caches</title>
|
||||
|
||||
<para>Clearly there are plenty of caching products out there that can be used as a backing store. To plug them in, one needs to provide a <interfacename>CacheManager</interfacename> and
|
||||
<interfacename>Cache</interfacename> implementation since unfortunately there is no available standard that we can use instead. This may sound harder then it is since in practice,
|
||||
the classes tend to be simple <ulink url="http://en.wikipedia.org/wiki/Adapter_pattern">adapter</ulink>s that map the caching abstraction framework on top of the storage API as the <literal>ehcache</literal> classes can show.
|
||||
Most <interfacename>CacheManager</interfacename> classes can use the classes in <literal>org.springframework.cache.support</literal> package, such as <classname>AbstractCacheManager</classname>
|
||||
which takes care of the boiler-plate code leaving only the actual <emphasis>mapping</emphasis> to be completed. We hope that in time, the libraries that provide integration with Spring
|
||||
can fill in this small configuration gap.</para>
|
||||
</section>
|
||||
|
||||
<section id="cache-specific-config">
|
||||
<title>How can I set the TTL/TTI/Eviction policy/XXX feature?</title>
|
||||
|
||||
<para>Directly through your cache provider. The cache abstraction is... well, an abstraction not a cache implementation. The solution you are using might support various data policies and different
|
||||
topologies which other solutions do not (take for example the JDK <literal>ConcurrentHashMap</literal>) - exposing that in the cache abstraction would be useless simply because there would
|
||||
no backing support. Such functionality should be controlled directly through the backing cache, when configuring it or through its native API.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
1190
src/reference/docbook/cci.xml
Normal file
1950
src/reference/docbook/classic-aop-spring.xml
Normal file
453
src/reference/docbook/classic-spring.xml
Normal file
@@ -0,0 +1,453 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE appendix PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
<appendix id="classic-spring">
|
||||
<title>Classic Spring Usage</title>
|
||||
|
||||
<para>This appendix discusses some classic Spring usage patterns as a
|
||||
reference for developers maintaining legacy Spring applications. These usage
|
||||
patterns no longer reflect the recommended way of using these features and
|
||||
the current recommended usage is covered in the respective sections of the
|
||||
reference manual.</para>
|
||||
|
||||
<section id="classic-spring-orm">
|
||||
<title>Classic ORM usage</title>
|
||||
|
||||
<para>This section documents the classic usage patterns that you might
|
||||
encounter in a legacy Spring application. For the currently recommended
|
||||
usage patterns, please refer to the <xref linkend="orm" /> chapter.</para>
|
||||
|
||||
<section id="classic-spring-hibernate">
|
||||
<title>Hibernate</title>
|
||||
|
||||
<para>For the currently recommended usage patterns for Hibernate see
|
||||
<xref linkend="orm-hibernate" /></para>
|
||||
|
||||
<section id="orm-hibernate-template">
|
||||
<title>The <classname>HibernateTemplate</classname></title>
|
||||
|
||||
<para>The basic programming model for templating looks as follows, for
|
||||
methods that can be part of any custom data access object or business
|
||||
service. There are no restrictions on the implementation of the
|
||||
surrounding object at all, it just needs to provide a Hibernate
|
||||
<interfacename>SessionFactory</interfacename>. It can get the latter
|
||||
from anywhere, but preferably as bean reference from a Spring IoC
|
||||
container - via a simple
|
||||
<methodname>setSessionFactory(..)</methodname> bean property setter.
|
||||
The following snippets show a DAO definition in a Spring container,
|
||||
referencing the above defined
|
||||
<interfacename>SessionFactory</interfacename>, and an example for a
|
||||
DAO method implementation.</para>
|
||||
|
||||
<programlisting language="xml"><beans>
|
||||
|
||||
<bean id="myProductDao" class="product.ProductDaoImpl">
|
||||
<property name="sessionFactory" ref="mySessionFactory"/>
|
||||
</bean>
|
||||
|
||||
</beans></programlisting>
|
||||
|
||||
<programlisting language="java">public class ProductDaoImpl implements ProductDao {
|
||||
|
||||
private HibernateTemplate hibernateTemplate;
|
||||
|
||||
public void setSessionFactory(SessionFactory sessionFactory) {
|
||||
this.hibernateTemplate = new HibernateTemplate(sessionFactory);
|
||||
}
|
||||
|
||||
public Collection loadProductsByCategory(String category) throws DataAccessException {
|
||||
return this.hibernateTemplate.find("from test.Product product where product.category=?", category);
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<para>The <classname>HibernateTemplate</classname> class provides many
|
||||
methods that mirror the methods exposed on the Hibernate
|
||||
<interfacename>Session</interfacename> interface, in addition to a
|
||||
number of convenience methods such as the one shown above. If you need
|
||||
access to the <interfacename>Session</interfacename> to invoke methods
|
||||
that are not exposed on the <classname>HibernateTemplate</classname>,
|
||||
you can always drop down to a callback-based approach like so.</para>
|
||||
|
||||
<programlisting language="java">public class ProductDaoImpl implements ProductDao {
|
||||
|
||||
private HibernateTemplate hibernateTemplate;
|
||||
|
||||
public void setSessionFactory(SessionFactory sessionFactory) {
|
||||
this.hibernateTemplate = new HibernateTemplate(sessionFactory);
|
||||
}
|
||||
|
||||
public Collection loadProductsByCategory(final String category) throws DataAccessException {
|
||||
return this.hibernateTemplate.execute(new HibernateCallback() {
|
||||
|
||||
public Object doInHibernate(Session session) {
|
||||
Criteria criteria = session.createCriteria(Product.class);
|
||||
criteria.add(Expression.eq("category", category));
|
||||
criteria.setMaxResults(6);
|
||||
return criteria.list();
|
||||
}
|
||||
};
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<para>A callback implementation effectively can be used for any
|
||||
Hibernate data access. <classname>HibernateTemplate</classname> will
|
||||
ensure that <interfacename>Session</interfacename> instances are
|
||||
properly opened and closed, and automatically participate in
|
||||
transactions. The template instances are thread-safe and reusable,
|
||||
they can thus be kept as instance variables of the surrounding class.
|
||||
For simple single step actions like a single find, load, saveOrUpdate,
|
||||
or delete call, <classname>HibernateTemplate</classname> offers
|
||||
alternative convenience methods that can replace such one line
|
||||
callback implementations. Furthermore, Spring provides a convenient
|
||||
<classname>HibernateDaoSupport</classname> base class that provides a
|
||||
<methodname>setSessionFactory(..)</methodname> method for receiving a
|
||||
<interfacename>SessionFactory</interfacename>, and
|
||||
<methodname>getSessionFactory()</methodname> and
|
||||
<methodname>getHibernateTemplate()</methodname>for use by subclasses.
|
||||
In combination, this allows for very simple DAO implementations for
|
||||
typical requirements:</para>
|
||||
|
||||
<programlisting language="java">public class ProductDaoImpl extends HibernateDaoSupport implements ProductDao {
|
||||
|
||||
public Collection loadProductsByCategory(String category) throws DataAccessException {
|
||||
return this.getHibernateTemplate().find(
|
||||
"from test.Product product where product.category=?", category);
|
||||
}
|
||||
}</programlisting>
|
||||
</section>
|
||||
|
||||
<section id="orm-hibernate-daos">
|
||||
<title>Implementing Spring-based DAOs without callbacks</title>
|
||||
|
||||
<para>As alternative to using Spring's
|
||||
<classname>HibernateTemplate</classname> to implement DAOs, data
|
||||
access code can also be written in a more traditional fashion, without
|
||||
wrapping the Hibernate access code in a callback, while still
|
||||
respecting and participating in Spring's generic
|
||||
<classname>DataAccessException</classname> hierarchy. The
|
||||
<classname>HibernateDaoSupport</classname> base class offers methods
|
||||
to access the current transactional
|
||||
<interfacename>Session</interfacename> and to convert exceptions in
|
||||
such a scenario; similar methods are also available as static helpers
|
||||
on the <classname>SessionFactoryUtils</classname> class. Note that
|
||||
such code will usually pass '<literal>false</literal>' as the value of
|
||||
the <methodname>getSession(..)</methodname> methods
|
||||
'<literal>allowCreate</literal>' argument, to enforce running within a
|
||||
transaction (which avoids the need to close the returned
|
||||
<interfacename>Session</interfacename>, as its lifecycle is managed by
|
||||
the transaction).</para>
|
||||
|
||||
<programlisting language="java">public class HibernateProductDao extends HibernateDaoSupport implements ProductDao {
|
||||
|
||||
public Collection loadProductsByCategory(String category) throws DataAccessException, MyException {
|
||||
Session session = getSession(false);
|
||||
try {
|
||||
Query query = session.createQuery("from test.Product product where product.category=?");
|
||||
query.setString(0, category);
|
||||
List result = query.list();
|
||||
if (result == null) {
|
||||
throw new MyException("No search results.");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (HibernateException ex) {
|
||||
throw convertHibernateAccessException(ex);
|
||||
}
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<para>The advantage of such direct Hibernate access code is that it
|
||||
allows <emphasis>any</emphasis> checked application exception to be
|
||||
thrown within the data access code; contrast this to the
|
||||
<classname>HibernateTemplate</classname> class which is restricted to
|
||||
throwing only unchecked exceptions within the callback. Note that you
|
||||
can often defer the corresponding checks and the throwing of
|
||||
application exceptions to after the callback, which still allows
|
||||
working with <classname>HibernateTemplate</classname>. In general, the
|
||||
<classname>HibernateTemplate</classname> class' convenience methods
|
||||
are simpler and more convenient for many scenarios.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="classic-spring-jdo">
|
||||
<title>JDO</title>
|
||||
|
||||
<para>For the currently recommended usage patterns for JDO see <xref
|
||||
linkend="orm-jdo" /></para>
|
||||
|
||||
<section id="orm-jdo-template">
|
||||
<title><classname>JdoTemplate</classname> and
|
||||
<classname>JdoDaoSupport</classname></title>
|
||||
|
||||
<para>Each JDO-based DAO will then receive the
|
||||
<interfacename>PersistenceManagerFactory</interfacename> through
|
||||
dependency injection. Such a DAO could be coded against plain JDO API,
|
||||
working with the given
|
||||
<interfacename>PersistenceManagerFactory</interfacename>, but will
|
||||
usually rather be used with the Spring Framework's
|
||||
<classname>JdoTemplate</classname>:</para>
|
||||
|
||||
<programlisting language="xml"><beans>
|
||||
|
||||
<bean id="myProductDao" class="product.ProductDaoImpl">
|
||||
<property name="persistenceManagerFactory" ref="myPmf"/>
|
||||
</bean>
|
||||
|
||||
</beans></programlisting>
|
||||
|
||||
<programlisting language="java">public class ProductDaoImpl implements ProductDao {
|
||||
|
||||
private JdoTemplate jdoTemplate;
|
||||
|
||||
public void setPersistenceManagerFactory(PersistenceManagerFactory pmf) {
|
||||
this.jdoTemplate = new JdoTemplate(pmf);
|
||||
}
|
||||
|
||||
public Collection loadProductsByCategory(final String category) throws DataAccessException {
|
||||
return (Collection) this.jdoTemplate.execute(new JdoCallback() {
|
||||
public Object doInJdo(PersistenceManager pm) throws JDOException {
|
||||
Query query = pm.newQuery(Product.class, "category = pCategory");
|
||||
query.declareParameters("String pCategory");
|
||||
List result = query.execute(category);
|
||||
<lineannotation>// do some further stuff with the result list</lineannotation>
|
||||
return result;
|
||||
}
|
||||
});
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<para>A callback implementation can effectively be used for any JDO
|
||||
data access. <classname>JdoTemplate</classname> will ensure that
|
||||
<classname>PersistenceManager</classname>s are properly opened and
|
||||
closed, and automatically participate in transactions. The template
|
||||
instances are thread-safe and reusable, they can thus be kept as
|
||||
instance variables of the surrounding class. For simple single-step
|
||||
actions such as a single <literal>find</literal>,
|
||||
<literal>load</literal>, <literal>makePersistent</literal>, or
|
||||
<literal>delete</literal> call, <classname>JdoTemplate</classname>
|
||||
offers alternative convenience methods that can replace such one line
|
||||
callback implementations. Furthermore, Spring provides a convenient
|
||||
<classname>JdoDaoSupport</classname> base class that provides a
|
||||
<literal>setPersistenceManagerFactory(..)</literal> method for
|
||||
receiving a <classname>PersistenceManagerFactory</classname>, and
|
||||
<methodname>getPersistenceManagerFactory()</methodname> and
|
||||
<methodname>getJdoTemplate()</methodname> for use by subclasses. In
|
||||
combination, this allows for very simple DAO implementations for
|
||||
typical requirements:</para>
|
||||
|
||||
<programlisting language="java">public class ProductDaoImpl extends JdoDaoSupport implements ProductDao {
|
||||
|
||||
public Collection loadProductsByCategory(String category) throws DataAccessException {
|
||||
return getJdoTemplate().find(
|
||||
Product.class, "category = pCategory", "String category", new Object[] {category});
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<para>As alternative to working with Spring's
|
||||
<classname>JdoTemplate</classname>, you can also code Spring-based
|
||||
DAOs at the JDO API level, explicitly opening and closing a
|
||||
<interfacename>PersistenceManager</interfacename>. As elaborated in
|
||||
the corresponding Hibernate section, the main advantage of this
|
||||
approach is that your data access code is able to throw checked
|
||||
exceptions. <classname>JdoDaoSupport</classname> offers a variety of
|
||||
support methods for this scenario, for fetching and releasing a
|
||||
transactional <interfacename>PersistenceManager</interfacename> as
|
||||
well as for converting exceptions.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="classic-spring-jpa">
|
||||
<title>JPA</title>
|
||||
|
||||
<para>For the currently recommended usage patterns for JPA see <xref
|
||||
linkend="orm-jpa" /></para>
|
||||
|
||||
<section id="orm-jpa-template">
|
||||
<title><classname>JpaTemplate</classname> and
|
||||
<classname>JpaDaoSupport</classname></title>
|
||||
|
||||
<para>Each JPA-based DAO will then receive a
|
||||
<interfacename>EntityManagerFactory</interfacename> via dependency
|
||||
injection. Such a DAO can be coded against plain JPA and work with the
|
||||
given <interfacename>EntityManagerFactory</interfacename> or through
|
||||
Spring's <classname>JpaTemplate</classname>:</para>
|
||||
|
||||
<programlisting language="xml"><beans>
|
||||
|
||||
<bean id="myProductDao" class="product.ProductDaoImpl">
|
||||
<property name="entityManagerFactory" ref="myEmf"/>
|
||||
</bean>
|
||||
|
||||
</beans></programlisting>
|
||||
|
||||
<programlisting language="java">public class JpaProductDao implements ProductDao {
|
||||
|
||||
private JpaTemplate jpaTemplate;
|
||||
|
||||
public void setEntityManagerFactory(EntityManagerFactory emf) {
|
||||
this.jpaTemplate = new JpaTemplate(emf);
|
||||
}
|
||||
|
||||
public Collection loadProductsByCategory(final String category) throws DataAccessException {
|
||||
return (Collection) this.jpaTemplate.execute(new JpaCallback() {
|
||||
public Object doInJpa(EntityManager em) throws PersistenceException {
|
||||
Query query = em.createQuery("from Product as p where p.category = :category");
|
||||
query.setParameter("category", category);
|
||||
List result = query.getResultList();
|
||||
<lineannotation>// do some further processing with the result list</lineannotation>
|
||||
return result;
|
||||
}
|
||||
});
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<para>The <interfacename>JpaCallback</interfacename> implementation
|
||||
allows any type of JPA data access. The
|
||||
<classname>JpaTemplate</classname> will ensure that
|
||||
<interfacename>EntityManager</interfacename>s are properly opened and
|
||||
closed and automatically participate in transactions. Moreover, the
|
||||
<classname>JpaTemplate</classname> properly handles exceptions, making
|
||||
sure resources are cleaned up and the appropriate transactions rolled
|
||||
back. The template instances are thread-safe and reusable and they can
|
||||
be kept as instance variable of the enclosing class. Note that
|
||||
<classname>JpaTemplate</classname> offers single-step actions such as
|
||||
find, load, merge, etc along with alternative convenience methods that
|
||||
can replace one line callback implementations.</para>
|
||||
|
||||
<para>Furthermore, Spring provides a convenient
|
||||
<classname>JpaDaoSupport</classname> base class that provides the
|
||||
<literal>get/setEntityManagerFactory</literal> and
|
||||
<methodname>getJpaTemplate()</methodname> to be used by
|
||||
subclasses:</para>
|
||||
|
||||
<programlisting language="java">public class ProductDaoImpl extends JpaDaoSupport implements ProductDao {
|
||||
|
||||
public Collection loadProductsByCategory(String category) throws DataAccessException {
|
||||
Map<String, String> params = new HashMap<String, String>();
|
||||
params.put("category", category);
|
||||
return getJpaTemplate().findByNamedParams("from Product as p where p.category = :category", params);
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<para>Besides working with Spring's
|
||||
<classname>JpaTemplate</classname>, one can also code Spring-based
|
||||
DAOs against the JPA, doing one's own explicit
|
||||
<interfacename>EntityManager</interfacename> handling. As also
|
||||
elaborated in the corresponding Hibernate section, the main advantage
|
||||
of this approach is that your data access code is able to throw
|
||||
checked exceptions. <classname>JpaDaoSupport</classname> offers a
|
||||
variety of support methods for this scenario, for retrieving and
|
||||
releasing a transaction <interfacename>EntityManager</interfacename>,
|
||||
as well as for converting exceptions.</para>
|
||||
|
||||
<para><emphasis>JpaTemplate mainly exists as a sibling of JdoTemplate
|
||||
and HibernateTemplate, offering the same style for people used to
|
||||
it.</emphasis></para>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="clasic-spring-mvc">
|
||||
<title>Classic Spring MVC</title>
|
||||
|
||||
<para>...</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>JMS Usage</title>
|
||||
|
||||
<para>One of the benefits of Spring's JMS support is to shield the user
|
||||
from differences between the JMS 1.0.2 and 1.1 APIs. (For a description of
|
||||
the differences between the two APIs see sidebar on Domain Unification).
|
||||
Since it is now common to encounter only the JMS 1.1 API the use of
|
||||
classes that are based on the JMS 1.0.2 API has been deprecated in Spring
|
||||
3.0. This section describes Spring JMS support for the JMS 1.0.2
|
||||
deprecated classes. </para>
|
||||
|
||||
<sidebar>
|
||||
<title>Domain Unification</title>
|
||||
|
||||
<para>There are two major releases of the JMS specification, 1.0.2 and
|
||||
1.1.</para>
|
||||
|
||||
<para>JMS 1.0.2 defined two types of messaging domains, point-to-point
|
||||
(Queues) and publish/subscribe (Topics). The 1.0.2 API reflected these
|
||||
two messaging domains by providing a parallel class hierarchy for each
|
||||
domain. As a result, a client application became domain specific in its
|
||||
use of the JMS API. JMS 1.1 introduced the concept of domain unification
|
||||
that minimized both the functional differences and client API
|
||||
differences between the two domains. As an example of a functional
|
||||
difference that was removed, if you use a JMS 1.1 provider you can
|
||||
transactionally consume a message from one domain and produce a message
|
||||
on the other using the same
|
||||
<interfacename>Session</interfacename>.</para>
|
||||
|
||||
<note>
|
||||
<para>The JMS 1.1 specification was released in April 2002 and
|
||||
incorporated as part of J2EE 1.4 in November 2003. As a result, common
|
||||
J2EE 1.3 application servers which are still in widespread use (such
|
||||
as BEA WebLogic 8.1 and IBM WebSphere 5.1) are based on JMS
|
||||
1.0.2.</para>
|
||||
</note>
|
||||
</sidebar>
|
||||
|
||||
<section>
|
||||
<title>JmsTemplate</title>
|
||||
|
||||
<para>Located in the package
|
||||
<literal>org.springframework.jms.core</literal> the class
|
||||
<classname>JmsTemplate102</classname> provides all of the features of
|
||||
the <classname>JmsTemplate</classname> described the JMS chapter, but is
|
||||
based on the JMS 1.0.2 API instead of the JMS 1.1 API. As a consequence,
|
||||
if you are using JmsTemplate102 you need to set the boolean property
|
||||
<property>pubSubDomain</property> to configure the
|
||||
<classname>JmsTemplate</classname> with knowledge of what JMS domain is
|
||||
being used. By default the value of this property is false, indicating
|
||||
that the point-to-point domain, Queues, will be used.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Asynchronous Message Reception </title>
|
||||
|
||||
<para><link
|
||||
linkend="jms-receiving-async-message-listener-adapter">MessageListenerAdapter's</link>
|
||||
are used in conjunction with Spring's <link linkend="jms-mdp">message
|
||||
listener containers</link> to support asynchronous message reception by
|
||||
exposing almost any class as a Message-driven POJO. If you are using the
|
||||
JMS 1.0.2 API, you will want to use the 1.0.2 specific classes such as
|
||||
<classname>MessageListenerAdapter102</classname>,
|
||||
<classname>SimpleMessageListenerContainer102</classname>, and
|
||||
<classname>DefaultMessageListenerContainer102</classname>. These classes
|
||||
provide the same functionality as the JMS 1.1 based counterparts but
|
||||
rely only on the JMS 1.0.2 API. </para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Connections</title>
|
||||
|
||||
<para>The <classname>ConnectionFactory</classname> interface is part of
|
||||
the JMS specification and serves as the entry point for working with
|
||||
JMS. Spring provides an implementation of the
|
||||
<classname>ConnectionFactory</classname> interface,
|
||||
<classname>SingleConnectionFactory102</classname>, based on the JMS
|
||||
1.0.2 API that will return the same <classname>Connection</classname> on
|
||||
all <methodname>createConnection()</methodname> calls and ignore calls to
|
||||
<methodname>close()</methodname>. You will need to set the boolean
|
||||
property <property>pubSubDomain</property> to indicate which messaging
|
||||
domain is used as <classname>SingleConnectionFactory102</classname> will
|
||||
always explicitly differentiate between a
|
||||
<classname>javax.jms.QueueConnection</classname> and a
|
||||
<classname>javax.jmsTopicConnection</classname>.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Transaction Management</title>
|
||||
|
||||
<para>In a JMS 1.0.2 environment the class
|
||||
<classname>JmsTransactionManager102</classname> provides support for
|
||||
managing JMS transactions for a single Connection Factory. Please refer
|
||||
to the reference documentation on <link linkend="jms-tx">JMS Transaction
|
||||
Management</link> for more information on this functionality.</para>
|
||||
</section>
|
||||
</section>
|
||||
</appendix>
|
||||
151
src/reference/docbook/dao.xml
Normal file
@@ -0,0 +1,151 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
<chapter id="dao">
|
||||
<title>DAO support</title>
|
||||
|
||||
<section id="dao-introduction">
|
||||
<title>Introduction</title>
|
||||
|
||||
<para>The Data Access Object (DAO) support in Spring is aimed at making it
|
||||
easy to work with data access technologies like JDBC, Hibernate, JPA or
|
||||
JDO in a consistent way. This allows one to switch between the
|
||||
aforementioned persistence technologies fairly easily and it also allows
|
||||
one to code without worrying about catching exceptions that are specific
|
||||
to each technology.</para>
|
||||
</section>
|
||||
|
||||
<section id="dao-exceptions">
|
||||
<title>Consistent exception hierarchy</title>
|
||||
|
||||
<para>Spring provides a convenient translation from technology-specific
|
||||
exceptions like <classname>SQLException</classname> to its own exception
|
||||
class hierarchy with the <classname>DataAccessException</classname> as the
|
||||
root exception. These exceptions wrap the original exception so there is
|
||||
never any risk that one might lose any information as to what might have
|
||||
gone wrong.</para>
|
||||
|
||||
<para>In addition to JDBC exceptions, Spring can also wrap
|
||||
Hibernate-specific exceptions, converting them from proprietary, checked
|
||||
exceptions (in the case of versions of Hibernate prior to Hibernate 3.0),
|
||||
to a set of focused runtime exceptions (the same is true for JDO and JPA
|
||||
exceptions). This allows one to handle most persistence exceptions, which
|
||||
are non-recoverable, only in the appropriate layers, without having
|
||||
annoying boilerplate catch-and-throw blocks and exception declarations in
|
||||
one's DAOs. (One can still trap and handle exceptions anywhere one needs
|
||||
to though.) As mentioned above, JDBC exceptions (including
|
||||
database-specific dialects) are also converted to the same hierarchy,
|
||||
meaning that one can perform some operations with JDBC within a consistent
|
||||
programming model.</para>
|
||||
|
||||
<para>The above holds true for the various template classes in Springs
|
||||
support for various ORM frameworks. If one uses the interceptor-based
|
||||
classes then the application must care about handling
|
||||
<classname>HibernateExceptions</classname> and
|
||||
<classname>JDOExceptions</classname> itself, preferably via delegating to
|
||||
<classname>SessionFactoryUtils</classname>'
|
||||
<methodname>convertHibernateAccessException(..)</methodname> or
|
||||
<methodname>convertJdoAccessException()</methodname> methods respectively.
|
||||
These methods convert the exceptions to ones that are compatible with the
|
||||
exceptions in the <literal>org.springframework.dao</literal> exception
|
||||
hierarchy. As <classname>JDOExceptions</classname> are unchecked, they can
|
||||
simply get thrown too, sacrificing generic DAO abstraction in terms of
|
||||
exceptions though.</para>
|
||||
|
||||
<para>The exception hierarchy that Spring provides can be seen below.
|
||||
(Please note that the class hierarchy detailed in the image shows only a
|
||||
subset of the entire <classname>DataAccessException</classname>
|
||||
hierarchy.)</para>
|
||||
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata align="center" fileref="images/DataAccessException.gif" />
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
</section>
|
||||
|
||||
<section id="dao-annotations">
|
||||
<title>Annotations used for configuring DAO or Repository classes</title>
|
||||
|
||||
<para>The best way to guarantee that your Data Access Objects (DAOs) or
|
||||
repositories provide exception translation is to use the
|
||||
<interfacename>@Repository</interfacename> annotation. This annotation
|
||||
also allows the component scanning support to find and configure your DAOs
|
||||
and repositories without having to provide XML configuration entries for
|
||||
them.</para>
|
||||
|
||||
<programlisting language="java"><emphasis role="bold">@Repository</emphasis>
|
||||
public class SomeMovieFinder implements MovieFinder {
|
||||
|
||||
// ...
|
||||
|
||||
}</programlisting>
|
||||
|
||||
<para>Any DAO or repository implementation will need to access to a
|
||||
persistence resource, depending on the persistence technology used; for
|
||||
example, a JDBC-based repository will need access to a JDBC
|
||||
<interfacename>DataSource</interfacename>; a JPA-based repository will need
|
||||
access to an <interfacename>EntityManager</interfacename>. The easiest way
|
||||
to accomplish this is to have this resource dependency injected using one of
|
||||
the <interfacename>@Autowired,</interfacename>, <interfacename>@Inject</interfacename>,
|
||||
<interfacename>@Resource</interfacename> or
|
||||
<interfacename>@PersistenceContext</interfacename> annotations. Here is an
|
||||
example for a JPA repository:</para>
|
||||
|
||||
<programlisting language="java">@Repository
|
||||
public class JpaMovieFinder implements MovieFinder {
|
||||
|
||||
@PersistenceContext
|
||||
private EntityManager entityManager;
|
||||
|
||||
// ...
|
||||
|
||||
}</programlisting>
|
||||
|
||||
<para>If you are using the classic Hibernate APIs than you can inject the
|
||||
SessionFactory:</para>
|
||||
|
||||
<programlisting language="java">@Repository
|
||||
public class HibernateMovieFinder implements MovieFinder {
|
||||
|
||||
private SessionFactory sessionFactory;
|
||||
|
||||
@Autowired
|
||||
public void setSessionFactory(SessionFactory sessionFactory) {
|
||||
this.sessionFactory = sessionFactory;
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
}</programlisting>
|
||||
|
||||
<para>Last example we will show here is for typical JDBC support. You
|
||||
would have the <classname>DataSource</classname> injected into an
|
||||
initialization method where you would create a
|
||||
<classname>JdbcTemplate</classname> and other data access support classes
|
||||
like <classname>SimpleJdbcCall</classname> etc using this
|
||||
<classname>DataSource</classname>.</para>
|
||||
|
||||
<programlisting language="java">@Repository
|
||||
public class JdbcMovieFinder implements MovieFinder {
|
||||
|
||||
private JdbcTemplate jdbcTemplate;
|
||||
|
||||
@Autowired
|
||||
public void init(DataSource dataSource) {
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
}</programlisting>
|
||||
|
||||
<note>
|
||||
<para>Please see the specific coverage of each persistence technology
|
||||
for details on how to configure the application context to take
|
||||
advantage of these annotations.</para>
|
||||
</note>
|
||||
|
||||
<para></para>
|
||||
</section>
|
||||
</chapter>
|
||||
684
src/reference/docbook/dtd.xml
Normal file
@@ -0,0 +1,684 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE appendix PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
|
||||
<appendix id="springbeansdtd">
|
||||
<title><literal>spring-beans-2.0.dtd</literal></title>
|
||||
|
||||
<para><programlisting language="xml"><!--
|
||||
Spring XML Beans DTD, version 2.0
|
||||
Authors: Rod Johnson, Juergen Hoeller, Alef Arendsen, Colin Sampaleanu, Rob Harrop
|
||||
|
||||
This defines a simple and consistent way of creating a namespace
|
||||
of JavaBeans objects, managed by a Spring BeanFactory, read by
|
||||
XmlBeanDefinitionReader (with DefaultBeanDefinitionDocumentReader).
|
||||
|
||||
This document type is used by most Spring functionality, including
|
||||
web application contexts, which are based on bean factories.
|
||||
|
||||
Each "bean" element in this document defines a JavaBean.
|
||||
Typically the bean class is specified, along with JavaBean properties
|
||||
and/or constructor arguments.
|
||||
|
||||
A bean instance can be a "singleton" (shared instance) or a "prototype"
|
||||
(independent instance). Further scopes can be provided by extended
|
||||
bean factories, for example in a web environment.
|
||||
|
||||
References among beans are supported, that is, setting a JavaBean property
|
||||
or a constructor argument to refer to another bean in the same factory
|
||||
(or an ancestor factory).
|
||||
|
||||
As alternative to bean references, "inner bean definitions" can be used.
|
||||
Singleton flags of such inner bean definitions are effectively ignored:
|
||||
Inner beans are typically anonymous prototypes.
|
||||
|
||||
There is also support for lists, sets, maps, and java.util.Properties
|
||||
as bean property types or constructor argument types.
|
||||
|
||||
For simple purposes, this DTD is sufficient. As of Spring 2.0,
|
||||
XSD-based bean definitions are supported as more powerful alternative.
|
||||
|
||||
XML documents that conform to this DTD should declare the following doctype:
|
||||
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
|
||||
"http://www.springframework.org/dtd/spring-beans-2.0.dtd">
|
||||
-->
|
||||
|
||||
|
||||
<!--
|
||||
The document root. A document can contain bean definitions only,
|
||||
imports only, or a mixture of both (typically with imports first).
|
||||
-->
|
||||
<!ELEMENT beans (
|
||||
description?,
|
||||
(import | alias | bean)*
|
||||
)>
|
||||
|
||||
<!--
|
||||
Default values for all bean definitions. Can be overridden at
|
||||
the "bean" level. See those attribute definitions for details.
|
||||
-->
|
||||
<!ATTLIST beans default-lazy-init (true | false) "false">
|
||||
<!ATTLIST beans default-autowire (no | byName | byType | constructor | autodetect) "no">
|
||||
<!ATTLIST beans default-dependency-check (none | objects | simple | all) "none">
|
||||
<!ATTLIST beans default-init-method CDATA #IMPLIED>
|
||||
<!ATTLIST beans default-destroy-method CDATA #IMPLIED>
|
||||
<!ATTLIST beans default-merge (true | false) "false">
|
||||
|
||||
<!--
|
||||
Element containing informative text describing the purpose of the enclosing
|
||||
element. Always optional.
|
||||
Used primarily for user documentation of XML bean definition documents.
|
||||
-->
|
||||
<!ELEMENT description (#PCDATA)>
|
||||
|
||||
|
||||
<!--
|
||||
Specifies an XML bean definition resource to import.
|
||||
-->
|
||||
<!ELEMENT import EMPTY>
|
||||
|
||||
<!--
|
||||
The relative resource location of the XML bean definition file to import,
|
||||
for example "myImport.xml" or "includes/myImport.xml" or "../myImport.xml".
|
||||
-->
|
||||
<!ATTLIST import resource CDATA #REQUIRED>
|
||||
|
||||
|
||||
<!--
|
||||
Defines an alias for a bean, which can reside in a different definition file.
|
||||
-->
|
||||
<!ELEMENT alias EMPTY>
|
||||
|
||||
<!--
|
||||
The name of the bean to define an alias for.
|
||||
-->
|
||||
<!ATTLIST alias name CDATA #REQUIRED>
|
||||
|
||||
<!--
|
||||
The alias name to define for the bean.
|
||||
-->
|
||||
<!ATTLIST alias alias CDATA #REQUIRED>
|
||||
|
||||
<!--
|
||||
Allows for arbitrary metadata to be attached to a bean definition.
|
||||
-->
|
||||
<!ELEMENT meta EMPTY>
|
||||
|
||||
<!--
|
||||
Specifies the key name of the metadata parameter being defined.
|
||||
-->
|
||||
<!ATTLIST meta key CDATA #REQUIRED>
|
||||
|
||||
<!--
|
||||
Specifies the value of the metadata parameter being defined as a String.
|
||||
-->
|
||||
<!ATTLIST meta value CDATA #REQUIRED>
|
||||
|
||||
<!--
|
||||
Defines a single (usually named) bean.
|
||||
|
||||
A bean definition may contain nested tags for constructor arguments,
|
||||
property values, lookup methods, and replaced methods. Mixing constructor
|
||||
injection and setter injection on the same bean is explicitly supported.
|
||||
-->
|
||||
<!ELEMENT bean (
|
||||
description?,
|
||||
(meta | constructor-arg | property | lookup-method | replaced-method)*
|
||||
)>
|
||||
|
||||
<!--
|
||||
Beans can be identified by an id, to enable reference checking.
|
||||
|
||||
There are constraints on a valid XML id: if you want to reference your bean
|
||||
in Java code using a name that's illegal as an XML id, use the optional
|
||||
"name" attribute. If neither is given, the bean class name is used as id
|
||||
(with an appended counter like "#2" if there is already a bean with that name).
|
||||
-->
|
||||
<!ATTLIST bean id ID #IMPLIED>
|
||||
|
||||
<!--
|
||||
Optional. Can be used to create one or more aliases illegal in an id.
|
||||
Multiple aliases can be separated by any number of spaces, commas, or
|
||||
semi-colons (or indeed any mixture of the three).
|
||||
-->
|
||||
<!ATTLIST bean name CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Each bean definition must specify the fully qualified name of the class,
|
||||
except if it pure serves as parent for child bean definitions.
|
||||
-->
|
||||
<!ATTLIST bean class CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Optionally specify a parent bean definition.
|
||||
|
||||
Will use the bean class of the parent if none specified, but can
|
||||
also override it. In the latter case, the child bean class must be
|
||||
compatible with the parent, i.e. accept the parent's property values
|
||||
and constructor argument values, if any.
|
||||
|
||||
A child bean definition will inherit constructor argument values,
|
||||
property values and method overrides from the parent, with the option
|
||||
to add new values. If init method, destroy method, factory bean and/or factory
|
||||
method are specified, they will override the corresponding parent settings.
|
||||
|
||||
The remaining settings will always be taken from the child definition:
|
||||
depends on, autowire mode, dependency check, scope, lazy init.
|
||||
-->
|
||||
<!ATTLIST bean parent CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
The scope of this bean: typically "singleton" (one shared instance,
|
||||
which will be returned by all calls to getBean() with the id),
|
||||
or "prototype" (independent instance resulting from each call to
|
||||
getBean(). Default is "singleton".
|
||||
|
||||
Singletons are most commonly used, and are ideal for multi-threaded
|
||||
service objects. Further scopes, such as "request" or "session",
|
||||
might be supported by extended bean factories (for example, in a
|
||||
web environment).
|
||||
|
||||
Note: This attribute will not be inherited by child bean definitions.
|
||||
Hence, it needs to be specified per concrete bean definition.
|
||||
|
||||
Inner bean definitions inherit the singleton status of their containing
|
||||
bean definition, unless explicitly specified: The inner bean will be a
|
||||
singleton if the containing bean is a singleton, and a prototype if
|
||||
the containing bean has any other scope.
|
||||
-->
|
||||
<!ATTLIST bean scope CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Is this bean "abstract", i.e. not meant to be instantiated itself but
|
||||
rather just serving as parent for concrete child bean definitions.
|
||||
Default is "false". Specify "true" to tell the bean factory to not try to
|
||||
instantiate that particular bean in any case.
|
||||
|
||||
Note: This attribute will not be inherited by child bean definitions.
|
||||
Hence, it needs to be specified per abstract bean definition.
|
||||
-->
|
||||
<!ATTLIST bean abstract (true | false) #IMPLIED>
|
||||
|
||||
<!--
|
||||
If this bean should be lazily initialized.
|
||||
If false, it will get instantiated on startup by bean factories
|
||||
that perform eager initialization of singletons.
|
||||
|
||||
Note: This attribute will not be inherited by child bean definitions.
|
||||
Hence, it needs to be specified per concrete bean definition.
|
||||
-->
|
||||
<!ATTLIST bean lazy-init (true | false | default) "default">
|
||||
|
||||
<!--
|
||||
Indicates whether or not this bean should be considered when looking
|
||||
for candidates to satisfy another beans autowiring requirements.
|
||||
-->
|
||||
<!ATTLIST bean autowire-candidate (true | false) #IMPLIED>
|
||||
|
||||
<!--
|
||||
Optional attribute controlling whether to "autowire" bean properties.
|
||||
This is an automagical process in which bean references don't need to be coded
|
||||
explicitly in the XML bean definition file, but Spring works out dependencies.
|
||||
|
||||
There are 5 modes:
|
||||
|
||||
1. "no"
|
||||
The traditional Spring default. No automagical wiring. Bean references
|
||||
must be defined in the XML file via the <ref> element. We recommend this
|
||||
in most cases as it makes documentation more explicit.
|
||||
|
||||
2. "byName"
|
||||
Autowiring by property name. If a bean of class Cat exposes a dog property,
|
||||
Spring will try to set this to the value of the bean "dog" in the current factory.
|
||||
If there is no matching bean by name, nothing special happens;
|
||||
use dependency-check="objects" to raise an error in that case.
|
||||
|
||||
3. "byType"
|
||||
Autowiring if there is exactly one bean of the property type in the bean factory.
|
||||
If there is more than one, a fatal error is raised, and you can't use byType
|
||||
autowiring for that bean. If there is none, nothing special happens;
|
||||
use dependency-check="objects" to raise an error in that case.
|
||||
|
||||
4. "constructor"
|
||||
Analogous to "byType" for constructor arguments. If there isn't exactly one bean
|
||||
of the constructor argument type in the bean factory, a fatal error is raised.
|
||||
|
||||
5. "autodetect"
|
||||
Chooses "constructor" or "byType" through introspection of the bean class.
|
||||
If a default no-arg constructor is found, "byType" gets applied.
|
||||
|
||||
The latter two are similar to PicoContainer and make bean factories simple to
|
||||
configure for small namespaces, but doesn't work as well as standard Spring
|
||||
behaviour for bigger applications.
|
||||
|
||||
Note that explicit dependencies, i.e. "property" and "constructor-arg" elements,
|
||||
always override autowiring. Autowire behavior can be combined with dependency
|
||||
checking, which will be performed after all autowiring has been completed.
|
||||
|
||||
Note: This attribute will not be inherited by child bean definitions.
|
||||
Hence, it needs to be specified per concrete bean definition.
|
||||
-->
|
||||
<!ATTLIST bean autowire (no | byName | byType | constructor | autodetect | default) "default">
|
||||
|
||||
<!--
|
||||
Optional attribute controlling whether to check whether all this
|
||||
beans dependencies, expressed in its properties, are satisfied.
|
||||
Default is no dependency checking.
|
||||
|
||||
"simple" type dependency checking includes primitives and String;
|
||||
"objects" includes collaborators (other beans in the factory);
|
||||
"all" includes both types of dependency checking.
|
||||
|
||||
Note: This attribute will not be inherited by child bean definitions.
|
||||
Hence, it needs to be specified per concrete bean definition.
|
||||
-->
|
||||
<!ATTLIST bean dependency-check (none | objects | simple | all | default) "default">
|
||||
|
||||
<!--
|
||||
The names of the beans that this bean depends on being initialized.
|
||||
The bean factory will guarantee that these beans get initialized before.
|
||||
|
||||
Note that dependencies are normally expressed through bean properties or
|
||||
constructor arguments. This property should just be necessary for other kinds
|
||||
of dependencies like statics (*ugh*) or database preparation on startup.
|
||||
|
||||
Note: This attribute will not be inherited by child bean definitions.
|
||||
Hence, it needs to be specified per concrete bean definition.
|
||||
-->
|
||||
<!ATTLIST bean depends-on CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Optional attribute for the name of the custom initialization method
|
||||
to invoke after setting bean properties. The method must have no arguments,
|
||||
but may throw any exception.
|
||||
-->
|
||||
<!ATTLIST bean init-method CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Optional attribute for the name of the custom destroy method to invoke
|
||||
on bean factory shutdown. The method must have no arguments,
|
||||
but may throw any exception.
|
||||
|
||||
Note: Only invoked on beans whose lifecycle is under full control
|
||||
of the factory - which is always the case for singletons, but not
|
||||
guaranteed for any other scope.
|
||||
-->
|
||||
<!ATTLIST bean destroy-method CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Optional attribute specifying the name of a factory method to use to
|
||||
create this object. Use constructor-arg elements to specify arguments
|
||||
to the factory method, if it takes arguments. Autowiring does not apply
|
||||
to factory methods.
|
||||
|
||||
If the "class" attribute is present, the factory method will be a static
|
||||
method on the class specified by the "class" attribute on this bean
|
||||
definition. Often this will be the same class as that of the constructed
|
||||
object - for example, when the factory method is used as an alternative
|
||||
to a constructor. However, it may be on a different class. In that case,
|
||||
the created object will *not* be of the class specified in the "class"
|
||||
attribute. This is analogous to FactoryBean behavior.
|
||||
|
||||
If the "factory-bean" attribute is present, the "class" attribute is not
|
||||
used, and the factory method will be an instance method on the object
|
||||
returned from a getBean call with the specified bean name. The factory
|
||||
bean may be defined as a singleton or a prototype.
|
||||
|
||||
The factory method can have any number of arguments. Autowiring is not
|
||||
supported. Use indexed constructor-arg elements in conjunction with the
|
||||
factory-method attribute.
|
||||
|
||||
Setter Injection can be used in conjunction with a factory method.
|
||||
Method Injection cannot, as the factory method returns an instance,
|
||||
which will be used when the container creates the bean.
|
||||
-->
|
||||
<!ATTLIST bean factory-method CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Alternative to class attribute for factory-method usage.
|
||||
If this is specified, no class attribute should be used.
|
||||
This should be set to the name of a bean in the current or
|
||||
ancestor factories that contains the relevant factory method.
|
||||
This allows the factory itself to be configured using Dependency
|
||||
Injection, and an instance (rather than static) method to be used.
|
||||
-->
|
||||
<!ATTLIST bean factory-bean CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Bean definitions can specify zero or more constructor arguments.
|
||||
This is an alternative to "autowire constructor".
|
||||
Arguments correspond to either a specific index of the constructor argument
|
||||
list or are supposed to be matched generically by type.
|
||||
|
||||
Note: A single generic argument value will just be used once, rather than
|
||||
potentially matched multiple times (as of Spring 1.1).
|
||||
|
||||
constructor-arg elements are also used in conjunction with the factory-method
|
||||
element to construct beans using static or instance factory methods.
|
||||
-->
|
||||
<!ELEMENT constructor-arg (
|
||||
description?,
|
||||
(bean | ref | idref | value | null | list | set | map | props)?
|
||||
)>
|
||||
|
||||
<!--
|
||||
The constructor-arg tag can have an optional index attribute,
|
||||
to specify the exact index in the constructor argument list. Only needed
|
||||
to avoid ambiguities, e.g. in case of 2 arguments of the same type.
|
||||
-->
|
||||
<!ATTLIST constructor-arg index CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
The constructor-arg tag can have an optional type attribute,
|
||||
to specify the exact type of the constructor argument. Only needed
|
||||
to avoid ambiguities, e.g. in case of 2 single argument constructors
|
||||
that can both be converted from a String.
|
||||
-->
|
||||
<!ATTLIST constructor-arg type CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
A short-cut alternative to a child element "ref bean=".
|
||||
-->
|
||||
<!ATTLIST constructor-arg ref CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
A short-cut alternative to a child element "value".
|
||||
-->
|
||||
<!ATTLIST constructor-arg value CDATA #IMPLIED>
|
||||
|
||||
|
||||
<!--
|
||||
Bean definitions can have zero or more properties.
|
||||
Property elements correspond to JavaBean setter methods exposed
|
||||
by the bean classes. Spring supports primitives, references to other
|
||||
beans in the same or related factories, lists, maps and properties.
|
||||
-->
|
||||
<!ELEMENT property (
|
||||
description?, meta*,
|
||||
(bean | ref | idref | value | null | list | set | map | props)?
|
||||
)>
|
||||
|
||||
<!--
|
||||
The property name attribute is the name of the JavaBean property.
|
||||
This follows JavaBean conventions: a name of "age" would correspond
|
||||
to setAge()/optional getAge() methods.
|
||||
-->
|
||||
<!ATTLIST property name CDATA #REQUIRED>
|
||||
|
||||
<!--
|
||||
A short-cut alternative to a child element "ref bean=".
|
||||
-->
|
||||
<!ATTLIST property ref CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
A short-cut alternative to a child element "value".
|
||||
-->
|
||||
<!ATTLIST property value CDATA #IMPLIED>
|
||||
|
||||
|
||||
<!--
|
||||
A lookup method causes the IoC container to override the given method and return
|
||||
the bean with the name given in the bean attribute. This is a form of Method Injection.
|
||||
It's particularly useful as an alternative to implementing the BeanFactoryAware
|
||||
interface, in order to be able to make getBean() calls for non-singleton instances
|
||||
at runtime. In this case, Method Injection is a less invasive alternative.
|
||||
-->
|
||||
<!ELEMENT lookup-method EMPTY>
|
||||
|
||||
<!--
|
||||
Name of a lookup method. This method should take no arguments.
|
||||
-->
|
||||
<!ATTLIST lookup-method name CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Name of the bean in the current or ancestor factories that the lookup method
|
||||
should resolve to. Often this bean will be a prototype, in which case the
|
||||
lookup method will return a distinct instance on every invocation. This
|
||||
is useful for single-threaded objects.
|
||||
-->
|
||||
<!ATTLIST lookup-method bean CDATA #IMPLIED>
|
||||
|
||||
|
||||
<!--
|
||||
Similar to the lookup method mechanism, the replaced-method element is used to control
|
||||
IoC container method overriding: Method Injection. This mechanism allows the overriding
|
||||
of a method with arbitrary code.
|
||||
-->
|
||||
<!ELEMENT replaced-method (
|
||||
(arg-type)*
|
||||
)>
|
||||
|
||||
<!--
|
||||
Name of the method whose implementation should be replaced by the IoC container.
|
||||
If this method is not overloaded, there's no need to use arg-type subelements.
|
||||
If this method is overloaded, arg-type subelements must be used for all
|
||||
override definitions for the method.
|
||||
-->
|
||||
<!ATTLIST replaced-method name CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Bean name of an implementation of the MethodReplacer interface in the current
|
||||
or ancestor factories. This may be a singleton or prototype bean. If it's
|
||||
a prototype, a new instance will be used for each method replacement.
|
||||
Singleton usage is the norm.
|
||||
-->
|
||||
<!ATTLIST replaced-method replacer CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Subelement of replaced-method identifying an argument for a replaced method
|
||||
in the event of method overloading.
|
||||
-->
|
||||
<!ELEMENT arg-type (#PCDATA)>
|
||||
|
||||
<!--
|
||||
Specification of the type of an overloaded method argument as a String.
|
||||
For convenience, this may be a substring of the FQN. E.g. all the
|
||||
following would match "java.lang.String":
|
||||
- java.lang.String
|
||||
- String
|
||||
- Str
|
||||
|
||||
As the number of arguments will be checked also, this convenience can often
|
||||
be used to save typing.
|
||||
-->
|
||||
<!ATTLIST arg-type match CDATA #IMPLIED>
|
||||
|
||||
|
||||
<!--
|
||||
Defines a reference to another bean in this factory or an external
|
||||
factory (parent or included factory).
|
||||
-->
|
||||
<!ELEMENT ref EMPTY>
|
||||
|
||||
<!--
|
||||
References must specify a name of the target bean.
|
||||
The "bean" attribute can reference any name from any bean in the context,
|
||||
to be checked at runtime.
|
||||
Local references, using the "local" attribute, have to use bean ids;
|
||||
they can be checked by this DTD, thus should be preferred for references
|
||||
within the same bean factory XML file.
|
||||
-->
|
||||
<!ATTLIST ref bean CDATA #IMPLIED>
|
||||
<!ATTLIST ref local IDREF #IMPLIED>
|
||||
<!ATTLIST ref parent CDATA #IMPLIED>
|
||||
|
||||
|
||||
<!--
|
||||
Defines a string property value, which must also be the id of another
|
||||
bean in this factory or an external factory (parent or included factory).
|
||||
While a regular 'value' element could instead be used for the same effect,
|
||||
using idref in this case allows validation of local bean ids by the XML
|
||||
parser, and name completion by supporting tools.
|
||||
-->
|
||||
<!ELEMENT idref EMPTY>
|
||||
|
||||
<!--
|
||||
ID refs must specify a name of the target bean.
|
||||
The "bean" attribute can reference any name from any bean in the context,
|
||||
potentially to be checked at runtime by bean factory implementations.
|
||||
Local references, using the "local" attribute, have to use bean ids;
|
||||
they can be checked by this DTD, thus should be preferred for references
|
||||
within the same bean factory XML file.
|
||||
-->
|
||||
<!ATTLIST idref bean CDATA #IMPLIED>
|
||||
<!ATTLIST idref local IDREF #IMPLIED>
|
||||
|
||||
|
||||
<!--
|
||||
Contains a string representation of a property value.
|
||||
The property may be a string, or may be converted to the required
|
||||
type using the JavaBeans PropertyEditor machinery. This makes it
|
||||
possible for application developers to write custom PropertyEditor
|
||||
implementations that can convert strings to arbitrary target objects.
|
||||
|
||||
Note that this is recommended for simple objects only.
|
||||
Configure more complex objects by populating JavaBean
|
||||
properties with references to other beans.
|
||||
-->
|
||||
<!ELEMENT value (#PCDATA)>
|
||||
|
||||
<!--
|
||||
The value tag can have an optional type attribute, to specify the
|
||||
exact type that the value should be converted to. Only needed
|
||||
if the type of the target property or constructor argument is
|
||||
too generic: for example, in case of a collection element.
|
||||
-->
|
||||
<!ATTLIST value type CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Denotes a Java null value. Necessary because an empty "value" tag
|
||||
will resolve to an empty String, which will not be resolved to a
|
||||
null value unless a special PropertyEditor does so.
|
||||
-->
|
||||
<!ELEMENT null (#PCDATA)>
|
||||
|
||||
|
||||
<!--
|
||||
A list can contain multiple inner bean, ref, collection, or value elements.
|
||||
Java lists are untyped, pending generics support in Java 1.5,
|
||||
although references will be strongly typed.
|
||||
A list can also map to an array type. The necessary conversion
|
||||
is automatically performed by the BeanFactory.
|
||||
-->
|
||||
<!ELEMENT list (
|
||||
(bean | ref | idref | value | null | list | set | map | props)*
|
||||
)>
|
||||
|
||||
<!--
|
||||
Enable/disable merging for collections when using parent/child beans.
|
||||
-->
|
||||
<!ATTLIST list merge (true | false | default) "default">
|
||||
|
||||
<!--
|
||||
Specify the default Java type for nested values.
|
||||
-->
|
||||
<!ATTLIST list value-type CDATA #IMPLIED>
|
||||
|
||||
|
||||
<!--
|
||||
A set can contain multiple inner bean, ref, collection, or value elements.
|
||||
Java sets are untyped, pending generics support in Java 1.5,
|
||||
although references will be strongly typed.
|
||||
-->
|
||||
<!ELEMENT set (
|
||||
(bean | ref | idref | value | null | list | set | map | props)*
|
||||
)>
|
||||
|
||||
<!--
|
||||
Enable/disable merging for collections when using parent/child beans.
|
||||
-->
|
||||
<!ATTLIST set merge (true | false | default) "default">
|
||||
|
||||
<!--
|
||||
Specify the default Java type for nested values.
|
||||
-->
|
||||
<!ATTLIST set value-type CDATA #IMPLIED>
|
||||
|
||||
|
||||
<!--
|
||||
A Spring map is a mapping from a string key to object.
|
||||
Maps may be empty.
|
||||
-->
|
||||
<!ELEMENT map (
|
||||
(entry)*
|
||||
)>
|
||||
|
||||
<!--
|
||||
Enable/disable merging for collections when using parent/child beans.
|
||||
-->
|
||||
<!ATTLIST map merge (true | false | default) "default">
|
||||
|
||||
<!--
|
||||
Specify the default Java type for nested entry keys.
|
||||
-->
|
||||
<!ATTLIST map key-type CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Specify the default Java type for nested entry values.
|
||||
-->
|
||||
<!ATTLIST map value-type CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
A map entry can be an inner bean, ref, value, or collection.
|
||||
The key of the entry is given by the "key" attribute or child element.
|
||||
-->
|
||||
<!ELEMENT entry (
|
||||
key?,
|
||||
(bean | ref | idref | value | null | list | set | map | props)?
|
||||
)>
|
||||
|
||||
<!--
|
||||
Each map element must specify its key as attribute or as child element.
|
||||
A key attribute is always a String value.
|
||||
-->
|
||||
<!ATTLIST entry key CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
A short-cut alternative to a "key" element with a "ref bean=" child element.
|
||||
-->
|
||||
<!ATTLIST entry key-ref CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
A short-cut alternative to a child element "value".
|
||||
-->
|
||||
<!ATTLIST entry value CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
A short-cut alternative to a child element "ref bean=".
|
||||
-->
|
||||
<!ATTLIST entry value-ref CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
A key element can contain an inner bean, ref, value, or collection.
|
||||
-->
|
||||
<!ELEMENT key (
|
||||
(bean | ref | idref | value | null | list | set | map | props)
|
||||
)>
|
||||
|
||||
|
||||
<!--
|
||||
Props elements differ from map elements in that values must be strings.
|
||||
Props may be empty.
|
||||
-->
|
||||
<!ELEMENT props (
|
||||
(prop)*
|
||||
)>
|
||||
|
||||
<!--
|
||||
Enable/disable merging for collections when using parent/child beans.
|
||||
-->
|
||||
<!ATTLIST props merge (true | false | default) "default">
|
||||
|
||||
<!--
|
||||
Element content is the string value of the property.
|
||||
Note that whitespace is trimmed off to avoid unwanted whitespace
|
||||
caused by typical XML formatting.
|
||||
-->
|
||||
<!ELEMENT prop (#PCDATA)>
|
||||
|
||||
<!--
|
||||
Each property element must specify its key.
|
||||
-->
|
||||
<!ATTLIST prop key CDATA #REQUIRED></programlisting></para>
|
||||
</appendix>
|
||||
1087
src/reference/docbook/dynamic-languages.xml
Normal file
439
src/reference/docbook/ejb.xml
Normal file
@@ -0,0 +1,439 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
|
||||
<chapter id="ejb">
|
||||
<title>Enterprise JavaBeans (EJB) integration</title>
|
||||
|
||||
<section id="ejb-introduction">
|
||||
<title>Introduction</title>
|
||||
<para>
|
||||
As a lightweight container, Spring is often considered an EJB
|
||||
replacement. We do believe that for many if not most applications and use
|
||||
cases, Spring as a container, combined with its rich supporting
|
||||
functionality in the area of transactions, ORM and JDBC access, is a better
|
||||
choice than implementing equivalent functionality via an EJB container and
|
||||
EJBs.
|
||||
</para>
|
||||
<para>
|
||||
However, it is important to note that using Spring does not prevent
|
||||
you from using EJBs. In fact, Spring makes it much easier to access EJBs and
|
||||
implement EJBs and functionality within them. Additionally, using Spring to
|
||||
access services provided by EJBs allows the implementation of those services
|
||||
to later transparently be switched between local EJB, remote EJB, or POJO
|
||||
(plain old Java object) variants, without the client code having to
|
||||
be changed.
|
||||
</para>
|
||||
<para>
|
||||
In this chapter, we look at how Spring can help you access and
|
||||
implement EJBs. Spring provides particular value when accessing stateless
|
||||
session beans (SLSBs), so we'll begin by discussing this.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="ejb-access">
|
||||
<title>Accessing EJBs</title>
|
||||
|
||||
<section id="ejb-access-concepts">
|
||||
<title>Concepts</title>
|
||||
<para>
|
||||
To invoke a method on a local or remote stateless session bean,
|
||||
client code must normally perform a JNDI lookup to obtain the (local or
|
||||
remote) EJB Home object, then use a 'create' method call on that object
|
||||
to obtain the actual (local or remote) EJB object. One or more methods
|
||||
are then invoked on the EJB.
|
||||
</para>
|
||||
<para>
|
||||
To avoid repeated low-level code, many EJB applications use the
|
||||
Service Locator and Business Delegate patterns. These are better than
|
||||
spraying JNDI lookups throughout client code, but their usual
|
||||
implementations have significant disadvantages. For example:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Typically code using EJBs depends on Service Locator or
|
||||
Business Delegate singletons, making it hard to test.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
In the case of the Service Locator pattern used without a
|
||||
Business Delegate, application code still ends up having to invoke
|
||||
the create() method on an EJB home, and deal with the resulting
|
||||
exceptions. Thus it remains tied to the EJB API and the complexity
|
||||
of the EJB programming model.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Implementing the Business Delegate pattern typically results
|
||||
in significant code duplication, where we have to write numerous
|
||||
methods that simply call the same method on the EJB.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
The Spring approach is to allow the creation and use of proxy objects,
|
||||
normally configured inside a Spring container, which act as codeless
|
||||
business delegates. You do not need to write another Service Locator, another
|
||||
JNDI lookup, or duplicate methods in a hand-coded Business Delegate unless
|
||||
you are actually adding real value in such code.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="ejb-access-local">
|
||||
<title>Accessing local SLSBs</title>
|
||||
<para>
|
||||
Assume that we have a web controller that needs to use a local
|
||||
EJB. We’ll follow best practice and use the EJB Business Methods
|
||||
Interface pattern, so that the EJB’s local interface extends a non
|
||||
EJB-specific business methods interface. Let’s call this business
|
||||
methods interface <classname>MyComponent</classname>.
|
||||
</para>
|
||||
<programlisting language="java"><![CDATA[public interface MyComponent {
|
||||
...
|
||||
}]]></programlisting>
|
||||
<para>
|
||||
One of the main reasons to use the Business Methods Interface pattern
|
||||
is to ensure that synchronization between method signatures in local
|
||||
interface and bean implementation class is automatic. Another reason is
|
||||
that it later makes it much easier for us to switch to a POJO (plain old
|
||||
Java object) implementation of the service if it makes sense to do so.
|
||||
Of course we’ll also need to implement the local home interface and
|
||||
provide an implementation class that implements <classname>SessionBean</classname>
|
||||
and the <classname>MyComponent</classname> business methods interface. Now the
|
||||
only Java coding we’ll need to do to hook up our web tier controller to the
|
||||
EJB implementation is to expose a setter method of type <classname>MyComponent</classname>
|
||||
on the controller. This will save the reference as an instance variable in the
|
||||
controller:
|
||||
</para>
|
||||
<programlisting language="java"><![CDATA[private MyComponent myComponent;
|
||||
|
||||
public void setMyComponent(MyComponent myComponent) {
|
||||
this.myComponent = myComponent;
|
||||
}]]></programlisting>
|
||||
<para>
|
||||
We can subsequently use this instance variable in any business
|
||||
method in the controller. Now assuming we are obtaining our controller
|
||||
object out of a Spring container, we can (in the same context) configure a
|
||||
<classname>LocalStatelessSessionProxyFactoryBean</classname> instance, which
|
||||
will be the EJB proxy object. The configuration of the proxy, and setting of
|
||||
the <literal>myComponent</literal> property of the controller is done
|
||||
with a configuration entry such as:
|
||||
</para>
|
||||
<programlisting language="xml"><![CDATA[<bean id="myComponent"
|
||||
class="org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean">
|
||||
<property name="jndiName" value="ejb/myBean"/>
|
||||
<property name="businessInterface" value="com.mycom.MyComponent"/>
|
||||
</bean>
|
||||
|
||||
<bean id="myController" class="com.mycom.myController">
|
||||
<property name="myComponent" ref="myComponent"/>
|
||||
</bean>]]></programlisting>
|
||||
<para>
|
||||
There’s a lot of work happening behind the scenes, courtesy of
|
||||
the Spring AOP framework, although you aren’t forced to work with AOP
|
||||
concepts to enjoy the results. The <literal>myComponent</literal> bean
|
||||
definition creates a proxy for the EJB, which implements the business
|
||||
method interface. The EJB local home is cached on startup, so there’s
|
||||
only a single JNDI lookup. Each time the EJB is invoked, the proxy
|
||||
invokes the <literal>classname</literal> method on the local EJB and
|
||||
invokes the corresponding business method on the EJB.
|
||||
</para>
|
||||
<para>
|
||||
The <literal>myController</literal> bean definition sets the
|
||||
<literal>myComponent</literal> property of the controller class to the
|
||||
EJB proxy.
|
||||
</para>
|
||||
<para>
|
||||
Alternatively (and preferably in case of many such proxy definitions),
|
||||
consider using the <literal><jee:local-slsb></literal>
|
||||
configuration element in Spring's "jee" namespace:
|
||||
</para>
|
||||
<programlisting language="xml"><![CDATA[<jee:local-slsb id="myComponent" jndi-name="ejb/myBean"
|
||||
business-interface="com.mycom.MyComponent"/>
|
||||
|
||||
<bean id="myController" class="com.mycom.myController">
|
||||
<property name="myComponent" ref="myComponent"/>
|
||||
</bean>]]></programlisting>
|
||||
<para>
|
||||
This EJB access mechanism delivers huge simplification of
|
||||
application code: the web tier code (or other EJB client code) has no
|
||||
dependence on the use of EJB. If we want to replace this EJB reference
|
||||
with a POJO or a mock object or other test stub, we could simply change
|
||||
the <literal>myComponent</literal> bean definition without changing a
|
||||
line of Java code. Additionally, we haven’t had to write a single line of
|
||||
JNDI lookup or other EJB plumbing code as part of our application.
|
||||
</para>
|
||||
<para>
|
||||
Benchmarks and experience in real applications indicate that the
|
||||
performance overhead of this approach (which involves reflective
|
||||
invocation of the target EJB) is minimal, and is typically undetectable
|
||||
in typical use. Remember that we don’t want to make fine-grained calls
|
||||
to EJBs anyway, as there’s a cost associated with the EJB infrastructure
|
||||
in the application server.
|
||||
</para>
|
||||
<para>
|
||||
There is one caveat with regards to the JNDI lookup. In a bean
|
||||
container, this class is normally best used as a singleton (there simply
|
||||
is no reason to make it a prototype). However, if that bean container
|
||||
pre-instantiates singletons (as do the various XML
|
||||
<classname>ApplicationContext</classname> variants)
|
||||
you may have a problem if the bean container is loaded before the EJB
|
||||
container loads the target EJB. That is because the JNDI lookup will be
|
||||
performed in the <literal>init()</literal> method of this class and then
|
||||
cached, but the EJB will not have been bound at the target location yet.
|
||||
The solution is to not pre-instantiate this factory object, but allow it
|
||||
to be created on first use. In the XML containers, this is controlled via
|
||||
the <literal>lazy-init</literal> attribute.
|
||||
</para>
|
||||
<para>
|
||||
Although this will not be of interest to the majority of Spring
|
||||
users, those doing programmatic AOP work with EJBs may want to look at
|
||||
<classname>LocalSlsbInvokerInterceptor</classname>.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="ejb-access-remote">
|
||||
<title>Accessing remote SLSBs</title>
|
||||
<para>
|
||||
Accessing remote EJBs is essentially identical to accessing local
|
||||
EJBs, except that the
|
||||
<classname>SimpleRemoteStatelessSessionProxyFactoryBean</classname> or
|
||||
<literal><jee:remote-slsb></literal> configuration element is used.
|
||||
Of course, with or without Spring, remote invocation semantics apply; a
|
||||
call to a method on an object in another VM in another computer does
|
||||
sometimes have to be treated differently in terms of usage scenarios and
|
||||
failure handling.
|
||||
</para>
|
||||
<para>
|
||||
Spring's EJB client support adds one more advantage over the
|
||||
non-Spring approach. Normally it is problematic for EJB client code to
|
||||
be easily switched back and forth between calling EJBs locally or
|
||||
remotely. This is because the remote interface methods must declare that
|
||||
they throw <classname>RemoteException</classname>, and client code must deal
|
||||
with this, while the local interface methods don't. Client code
|
||||
written for local EJBs which needs to be moved to remote EJBs
|
||||
typically has to be modified to add handling for the remote exceptions,
|
||||
and client code written for remote EJBs which needs to be moved to local
|
||||
EJBs, can either stay the same but do a lot of unnecessary handling of
|
||||
remote exceptions, or needs to be modified to remove that code. With the
|
||||
Spring remote EJB proxy, you can instead not declare any thrown
|
||||
<classname>RemoteException</classname> in your Business Method Interface and
|
||||
implementing EJB code, have a remote interface which is identical except
|
||||
that it does throw <classname>RemoteException</classname>, and rely on the
|
||||
proxy to dynamically treat the two interfaces as if they were the same.
|
||||
That is, client code does not have to deal with the checked
|
||||
<classname>RemoteException</classname> class. Any actual
|
||||
<classname>RemoteException</classname> that is thrown during the EJB
|
||||
invocation will be re-thrown as the non-checked
|
||||
<classname>RemoteAccessException</classname> class, which is a subclass of
|
||||
<classname>RuntimeException</classname>. The target service can then be
|
||||
switched at will between a local EJB or remote EJB (or even plain Java
|
||||
object) implementation, without the client code knowing or caring. Of
|
||||
course, this is optional; there is nothing stopping you from declaring
|
||||
<classname>RemoteExceptions</classname> in your business interface.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="ejb-access-ejb2-ejb3">
|
||||
<title>Accessing EJB 2.x SLSBs versus EJB 3 SLSBs</title>
|
||||
<para>
|
||||
Accessing EJB 2.x Session Beans and EJB 3 Session Beans via Spring
|
||||
is largely transparent. Spring's EJB accessors, including the
|
||||
<literal><jee:local-slsb></literal> and <literal><jee:remote-slsb></literal>
|
||||
facilities, transparently adapt to the actual component at runtime.
|
||||
They handle a home interface if found (EJB 2.x style), or perform straight
|
||||
component invocations if no home interface is available (EJB 3 style).
|
||||
</para>
|
||||
<para>
|
||||
Note: For EJB 3 Session Beans, you could effectively use a
|
||||
<classname>JndiObjectFactoryBean</classname> / <literal><jee:jndi-lookup></literal>
|
||||
as well, since fully usable component references are exposed for plain
|
||||
JNDI lookups there. Defining explicit <literal><jee:local-slsb></literal>
|
||||
/ <literal><jee:remote-slsb></literal> lookups simply provides
|
||||
consistent and more explicit EJB access configuration.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="ejb-implementation">
|
||||
<title>Using Spring's EJB implementation support classes</title>
|
||||
|
||||
<section id="ejb-implementation-ejb2">
|
||||
<title>EJB 2.x base classes</title>
|
||||
<para>
|
||||
Spring provides convenience classes to help you implement EJBs.
|
||||
These are designed to encourage the good practice of putting business
|
||||
logic behind EJBs in POJOs, leaving EJBs responsible for transaction
|
||||
demarcation and (optionally) remoting.
|
||||
</para>
|
||||
<para>
|
||||
To implement a Stateless or Stateful session bean, or a Message Driven
|
||||
bean, you need only derive your implementation class from
|
||||
<classname>AbstractStatelessSessionBean</classname>,
|
||||
<classname>AbstractStatefulSessionBean</classname>, and
|
||||
<classname>AbstractMessageDrivenBean</classname>/<classname>AbstractJmsMessageDrivenBean</classname>,
|
||||
respectively.
|
||||
</para>
|
||||
<para>
|
||||
Consider an example Stateless Session bean which actually delegates
|
||||
the implementation to a plain java service object. We have the business
|
||||
interface:
|
||||
</para>
|
||||
<programlisting language="java"><![CDATA[public interface MyComponent {
|
||||
public void myMethod(...);
|
||||
...
|
||||
}]]></programlisting>
|
||||
<para>We also have the plain Java implementation object:</para>
|
||||
<programlisting language="java"><![CDATA[public class MyComponentImpl implements MyComponent {
|
||||
public String myMethod(...) {
|
||||
...
|
||||
}
|
||||
...
|
||||
}]]></programlisting>
|
||||
<para>And finally the Stateless Session Bean itself:</para>
|
||||
<programlisting language="java"><![CDATA[public class MyFacadeEJB extends AbstractStatelessSessionBean
|
||||
implements MyFacadeLocal {
|
||||
|
||||
private MyComponent myComp;
|
||||
|
||||
/**
|
||||
* Obtain our POJO service object from the BeanFactory/ApplicationContext
|
||||
* @see org.springframework.ejb.support.AbstractStatelessSessionBean#onEjbCreate()
|
||||
*/
|
||||
protected void onEjbCreate() throws CreateException {
|
||||
myComp = (MyComponent) getBeanFactory().getBean(
|
||||
ServicesConstants.CONTEXT_MYCOMP_ID);
|
||||
}
|
||||
|
||||
// for business method, delegate to POJO service impl.
|
||||
public String myFacadeMethod(...) {
|
||||
return myComp.myMethod(...);
|
||||
}
|
||||
...
|
||||
}]]></programlisting>
|
||||
<para>
|
||||
The Spring EJB support base classes will by default create and load
|
||||
a Spring IoC container as part of their lifecycle, which is then available
|
||||
to the EJB (for example, as used in the code above to obtain the POJO
|
||||
service object). The loading is done via a strategy object which is a subclass of
|
||||
<classname>BeanFactoryLocator</classname>. The actual implementation of
|
||||
<classname>BeanFactoryLocator</classname> used by default is
|
||||
<classname>ContextJndiBeanFactoryLocator</classname>, which creates the
|
||||
ApplicationContext from a resource locations specified as a JNDI
|
||||
environment variable (in the case of the EJB classes, at
|
||||
<literal>java:comp/env/ejb/BeanFactoryPath</literal>). If there is a need
|
||||
to change the BeanFactory/ApplicationContext loading strategy, the default
|
||||
<classname>BeanFactoryLocator</classname> implementation used may be overridden
|
||||
by calling the <literal>setBeanFactoryLocator()</literal> method, either
|
||||
in <literal>setSessionContext()</literal>, or in the actual constructor of
|
||||
the EJB. Please see the Javadocs for more details.
|
||||
</para>
|
||||
<para>
|
||||
As described in the Javadocs, Stateful Session beans expecting to be
|
||||
passivated and reactivated as part of their lifecycle, and which use a
|
||||
non-serializable container instance (which is the normal case) will have
|
||||
to manually call <literal>unloadBeanFactory()</literal> and
|
||||
<literal>loadBeanFactory()</literal> from <literal>ejbPassivate()</literal>
|
||||
and <literal>ejbActivate()</literal>, respectively, to unload and reload the
|
||||
BeanFactory on passivation and activation, since it can not be saved by
|
||||
the EJB container.
|
||||
</para>
|
||||
<para>
|
||||
The default behavior of the
|
||||
<classname>ContextJndiBeanFactoryLocator</classname> class is to load an
|
||||
<classname>ApplicationContext</classname> for use by an EJB, and is
|
||||
adequate for some situations. However, it is problematic when the
|
||||
<classname>ApplicationContext</classname> is loading a number of beans,
|
||||
or the initialization of those beans is time consuming or memory
|
||||
intensive (such as a Hibernate <classname>SessionFactory</classname>
|
||||
initialization, for example), since every EJB will have their own copy.
|
||||
In this case, the user may want to override the default
|
||||
<classname>ContextJndiBeanFactoryLocator</classname> usage and use
|
||||
another <classname>BeanFactoryLocator</classname> variant, such as the
|
||||
<classname>ContextSingletonBeanFactoryLocator</classname> which can load
|
||||
and use a shared container to be used by multiple EJBs or other clients.
|
||||
Doing this is relatively simple, by adding code similar to this to the
|
||||
EJB:
|
||||
</para>
|
||||
<programlisting language="java"><![CDATA[ /**
|
||||
* Override default BeanFactoryLocator implementation
|
||||
* @see javax.ejb.SessionBean#setSessionContext(javax.ejb.SessionContext)
|
||||
*/
|
||||
public void setSessionContext(SessionContext sessionContext) {
|
||||
super.setSessionContext(sessionContext);
|
||||
setBeanFactoryLocator(ContextSingletonBeanFactoryLocator.getInstance());
|
||||
setBeanFactoryLocatorKey(ServicesConstants.PRIMARY_CONTEXT_ID);
|
||||
}]]></programlisting>
|
||||
<para>
|
||||
You would then need to create a bean definition file named <literal>beanRefContext.xml</literal>.
|
||||
This file defines all bean factories (usually in the form of application contexts) that may be used
|
||||
in the EJB. In many cases, this file will only contain a single bean definition such as this (where
|
||||
<literal>businessApplicationContext.xml</literal> contains the bean definitions for all business
|
||||
service POJOs):
|
||||
</para>
|
||||
<programlisting language="xml"><![CDATA[<beans>
|
||||
<bean id="businessBeanFactory" class="org.springframework.context.support.ClassPathXmlApplicationContext">
|
||||
<constructor-arg value="businessApplicationContext.xml" />
|
||||
</bean>
|
||||
</beans>]]></programlisting>
|
||||
<para>
|
||||
In the above example, the <literal>ServicesConstants.PRIMARY_CONTEXT_ID</literal> constant
|
||||
would be defined as follows:
|
||||
</para>
|
||||
<programlisting language="java"><![CDATA[public static final String ServicesConstants.PRIMARY_CONTEXT_ID = "businessBeanFactory";]]></programlisting>
|
||||
<para>
|
||||
Please see the respective Javadocs for the <classname>BeanFactoryLocator</classname> and
|
||||
<classname>ContextSingletonBeanFactoryLocator</classname> classes for more information on
|
||||
their usage.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="ejb-implementation-ejb3">
|
||||
<title>EJB 3 injection interceptor</title>
|
||||
<para>
|
||||
For EJB 3 Session Beans and Message-Driven Beans, Spring provides a convenient
|
||||
interceptor that resolves Spring 2.5's <literal>@Autowired</literal> annotation
|
||||
in the EJB component class:
|
||||
<classname>org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor</classname>.
|
||||
This interceptor can be applied through an <code>@Interceptors</code> annotation
|
||||
in the EJB component class, or through an <literal>interceptor-binding</literal>
|
||||
XML element in the EJB deployment descriptor.
|
||||
</para>
|
||||
<programlisting language="java"><![CDATA[@Stateless
|
||||
@Interceptors(SpringBeanAutowiringInterceptor.class)
|
||||
public class MyFacadeEJB implements MyFacadeLocal {
|
||||
|
||||
// automatically injected with a matching Spring bean
|
||||
@Autowired
|
||||
private MyComponent myComp;
|
||||
|
||||
// for business method, delegate to POJO service impl.
|
||||
public String myFacadeMethod(...) {
|
||||
return myComp.myMethod(...);
|
||||
}
|
||||
...
|
||||
}]]></programlisting>
|
||||
<para>
|
||||
<classname>SpringBeanAutowiringInterceptor</classname> by default obtains target
|
||||
beans from a <classname>ContextSingletonBeanFactoryLocator</classname>, with the
|
||||
context defined in a bean definition file named <literal>beanRefContext.xml</literal>.
|
||||
By default, a single context definition is expected, which is obtained by type rather
|
||||
than by name. However, if you need to choose between multiple context definitions,
|
||||
a specific locator key is required. The locator key (i.e. the name of the context
|
||||
definition in <literal>beanRefContext.xml</literal>) can be explicitly specified
|
||||
either through overriding the <literal>getBeanFactoryLocatorKey</literal> method
|
||||
in a custom <classname>SpringBeanAutowiringInterceptor</classname> subclass.
|
||||
</para>
|
||||
<para>
|
||||
Alternatively, consider overriding <classname>SpringBeanAutowiringInterceptor</classname>'s
|
||||
<literal>getBeanFactory</literal> method, e.g. obtaining a shared
|
||||
<interfacename>ApplicationContext</interfacename> from a custom holder class.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
1276
src/reference/docbook/expressions.xml
Normal file
BIN
src/reference/docbook/images/DataAccessException.gif
Normal file
|
After Width: | Height: | Size: 7.5 KiB |
BIN
src/reference/docbook/images/aop-proxy-call.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
src/reference/docbook/images/aop-proxy-plain-pojo-call.png
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
BIN
src/reference/docbook/images/aop-uml.gif
Normal file
|
After Width: | Height: | Size: 7.9 KiB |
BIN
src/reference/docbook/images/banner4.jpg
Normal file
|
After Width: | Height: | Size: 81 KiB |
BIN
src/reference/docbook/images/bean-lifecycle-overview.gif
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
BIN
src/reference/docbook/images/bind1.jpg
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
src/reference/docbook/images/bind2.jpg
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
src/reference/docbook/images/container-magic.png
Normal file
|
After Width: | Height: | Size: 8.5 KiB |
BIN
src/reference/docbook/images/eclipse-setup-1.png
Normal file
|
After Width: | Height: | Size: 57 KiB |
BIN
src/reference/docbook/images/eclipse-setup-2.png
Normal file
|
After Width: | Height: | Size: 76 KiB |
BIN
src/reference/docbook/images/eclipse-setup-3.png
Normal file
|
After Width: | Height: | Size: 192 KiB |
BIN
src/reference/docbook/images/ejb.gif
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
src/reference/docbook/images/ejb.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
95
src/reference/docbook/images/ejb.svg
Normal file
@@ -0,0 +1,95 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<!-- Generated by Microsoft Visio 11.0, SVG Export, v1.0 ejb.svg Page-1 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="4.25667in"
|
||||
height="2.64in" viewBox="0 0 306.48 190.08" xml:space="preserve" color-interpolation-filters="sRGB" class="st9">
|
||||
<v:documentProperties v:langID="1033" v:metric="true"/>
|
||||
|
||||
<style type="text/css">
|
||||
<![CDATA[
|
||||
.st1 {fill:#f4f7f0;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
|
||||
.st2 {fill:#000000;font-family:Arial;font-size:0.833336em}
|
||||
.st3 {fill:#ecefe2;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
|
||||
.st4 {visibility:visible}
|
||||
.st5 {fill:#84877b;stroke:#84877b;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
|
||||
.st6 {fill:#dde2cd;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
|
||||
.st7 {fill:#000000;font-family:Arial;font-size:0.75em}
|
||||
.st8 {font-size:1em}
|
||||
.st9 {fill:none;fill-rule:evenodd;font-size:12;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
|
||||
]]>
|
||||
</style>
|
||||
|
||||
<g v:mID="0" v:index="1" v:groupContext="foregroundPage">
|
||||
<title>Page-1</title>
|
||||
<v:pageProperties v:drawingScale="1" v:pageScale="1" v:drawingUnits="0" v:shadowOffsetX="9" v:shadowOffsetY="-9"/>
|
||||
<g id="shape1-1" v:mID="1" v:groupContext="shape" transform="translate(0.24012,-0.24)">
|
||||
<title>Box.1</title>
|
||||
<desc>Application Server (e.g. JBoss, WebLogic)</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)"/>
|
||||
<v:textRect cx="153" cy="104.622" width="306" height="170.916"/>
|
||||
<rect x="0" y="19.164" width="306" height="170.916" class="st1"/>
|
||||
<text x="59.35" y="185.62" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/>Application Server (e.g. JBoss, WebLogic)</text> </g>
|
||||
<g id="shape2-4" v:mID="2" v:groupContext="shape" transform="translate(30.1749,-23.3831)">
|
||||
<title>Box.2</title>
|
||||
<desc>Spring Core</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)"/>
|
||||
<v:textRect cx="49.8912" cy="159.506" width="99.79" height="61.1476"/>
|
||||
<rect x="0" y="128.932" width="99.7826" height="61.1476" class="st3"/>
|
||||
<text x="4" y="174.51" class="st2" v:langID="1033"><v:paragraph/><v:tabList/><v:newlineChar/><v:newlineChar/>Spring Core </text> </g>
|
||||
<g id="shape3-7" v:mID="3" v:groupContext="shape" transform="translate(161.223,-89.6263)">
|
||||
<title>Box.3</title>
|
||||
<desc>Spring Context</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)"/>
|
||||
<v:textRect cx="51.8869" cy="159.506" width="103.78" height="61.1476"/>
|
||||
<rect x="0" y="128.932" width="103.774" height="61.1476" class="st3"/>
|
||||
<text x="33.65" y="174.51" class="st2" v:langID="1033"><v:paragraph v:horizAlign="2"/><v:tabList/><v:newlineChar/><v:newlineChar/>Spring Context</text> </g>
|
||||
<g id="shape4-10" v:mID="4" v:groupContext="shape" transform="translate(6.89229,-150.773)">
|
||||
<title>Box</title>
|
||||
<desc>EJB Access layer using SlsbInvokers</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)"/>
|
||||
<v:textRect cx="69.8477" cy="170.547" width="139.71" height="39.0665"/>
|
||||
<g id="shadow4-11" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
|
||||
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
|
||||
<rect x="0" y="151.014" width="139.696" height="39.0665" class="st5"/>
|
||||
</g>
|
||||
<rect x="0" y="151.014" width="139.696" height="39.0665" class="st6"/>
|
||||
<text x="22.83" y="167.85" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>EJB Access layer using <tspan
|
||||
x="44.09" dy="1.2em" class="st8">SlsbInvokers</tspan></text> </g>
|
||||
<g id="shape5-16" v:mID="5" v:groupContext="shape" transform="translate(161.888,-23.3831)">
|
||||
<title>Box.4</title>
|
||||
<desc>Spring DAO</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)"/>
|
||||
<v:textRect cx="51.2216" cy="159.506" width="102.46" height="61.1476"/>
|
||||
<rect x="0" y="128.932" width="102.443" height="61.1476" class="st3"/>
|
||||
<text x="45.09" y="174.51" class="st2" v:langID="1033"><v:paragraph v:horizAlign="2"/><v:tabList/><v:newlineChar/><v:newlineChar/>Spring DAO</text> </g>
|
||||
<g id="shape6-19" v:mID="6" v:groupContext="shape" transform="translate(26.5572,-60.768)">
|
||||
<title>Box.5</title>
|
||||
<desc>Spring-managed EJBs (using AbstractEnterpriseBean</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)"/>
|
||||
<v:textRect cx="81.1564" cy="149.315" width="162.33" height="81.5301"/>
|
||||
<g id="shadow6-20" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
|
||||
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
|
||||
<rect x="0" y="108.55" width="162.313" height="81.5301" class="st5"/>
|
||||
</g>
|
||||
<rect x="0" y="108.55" width="162.313" height="81.5301" class="st6"/>
|
||||
<text x="36.12" y="152.02" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Spring-managed EJBs</text> </g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.7 KiB |
BIN
src/reference/docbook/images/full.gif
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
src/reference/docbook/images/full.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
254
src/reference/docbook/images/full.svg
Normal file
@@ -0,0 +1,254 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<!-- Generated by Microsoft Visio 11.0, SVG Export, v1.0 full.svg Page-1 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="4.97167in"
|
||||
height="3.59998in" viewBox="0 0 357.96 259.199" xml:space="preserve" color-interpolation-filters="sRGB" class="st9">
|
||||
<v:documentProperties v:langID="1033" v:viewMarkup="false"/>
|
||||
|
||||
<style type="text/css">
|
||||
<![CDATA[
|
||||
.st1 {fill:#f4f7f0;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
|
||||
.st2 {fill:#000000;font-family:Arial;font-size:0.666664em}
|
||||
.st3 {fill:#ecefe2;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
|
||||
.st4 {visibility:visible}
|
||||
.st5 {fill:#84877b;stroke:#84877b;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
|
||||
.st6 {fill:#dde2cd;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
|
||||
.st7 {fill:#000000;font-family:Arial;font-size:0.499992em}
|
||||
.st8 {font-size:1em}
|
||||
.st9 {fill:none;fill-rule:evenodd;font-size:12;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
|
||||
]]>
|
||||
</style>
|
||||
|
||||
<g v:mID="0" v:index="1" v:groupContext="foregroundPage">
|
||||
<title>Page-1</title>
|
||||
<v:pageProperties v:drawingScale="1" v:pageScale="1" v:drawingUnits="0" v:shadowOffsetX="9" v:shadowOffsetY="-9"/>
|
||||
<g id="shape1-1" v:mID="1" v:groupContext="shape" transform="translate(3.12,-11.3134)">
|
||||
<title>Box.1</title>
|
||||
<desc>Servlet Container (Tomcat / Jetty)</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)"/>
|
||||
<v:textRect cx="176.4" cy="140.913" width="352.8" height="236.571"/>
|
||||
<rect x="0" y="22.6271" width="352.8" height="236.571" class="st1"/>
|
||||
<text x="116.6" y="248.91" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/>Servlet Container (Tomcat / Jetty)<v:newlineChar/><v:newlineChar/></text> </g>
|
||||
<g id="shape2-4" v:mID="2" v:groupContext="shape" transform="translate(16.08,-37.4777)">
|
||||
<title>Box.2</title>
|
||||
<desc>Spring Core</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)"/>
|
||||
<v:textRect cx="81.9" cy="239.778" width="163.8" height="38.8414"/>
|
||||
<rect x="0" y="220.357" width="163.8" height="38.8414" class="st3"/>
|
||||
<text x="60.56" y="246.98" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/><v:newlineChar/>Spring Core</text> </g>
|
||||
<g id="shape3-7" v:mID="3" v:groupContext="shape" transform="translate(180.24,-37.4777)">
|
||||
<title>Box.3</title>
|
||||
<desc>Spring DAO</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)"/>
|
||||
<v:textRect cx="81.9" cy="239.778" width="163.81" height="38.8414"/>
|
||||
<rect x="0" y="220.357" width="163.8" height="38.8414" class="st3"/>
|
||||
<text x="60.56" y="246.98" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/><v:newlineChar/>Spring DAO</text> </g>
|
||||
<g id="shape4-10" v:mID="4" v:groupContext="shape" transform="translate(180.24,-74.7955)">
|
||||
<title>Box.4</title>
|
||||
<desc>Spring ORM</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)"/>
|
||||
<v:textRect cx="81.9" cy="240.395" width="163.8" height="37.6071"/>
|
||||
<rect x="0" y="221.591" width="163.8" height="37.6071" class="st3"/>
|
||||
<text x="11" y="238" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/> Spring ORM <v:newlineChar/></text> </g>
|
||||
<g id="shape5-13" v:mID="5" v:groupContext="shape" transform="translate(16.44,-143.999)">
|
||||
<title>Box.5</title>
|
||||
<desc>Spring Web</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)"/>
|
||||
<v:textRect cx="163.8" cy="241.199" width="327.6" height="36"/>
|
||||
<rect x="0" y="223.199" width="327.6" height="36" class="st3"/>
|
||||
<text x="142.9" y="243.6" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Spring Web</text> </g>
|
||||
<g id="shape7-16" v:mID="7" v:groupContext="shape" transform="translate(16.26,-74.7955)">
|
||||
<title>Box.7</title>
|
||||
<desc>Spring AOP</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)"/>
|
||||
<v:textRect cx="81.9" cy="240.395" width="163.8" height="37.6071"/>
|
||||
<rect x="0" y="221.591" width="163.8" height="37.6071" class="st3"/>
|
||||
<text x="4" y="238" class="st2" v:langID="1033"><v:paragraph/><v:tabList/> Spring AOP<v:newlineChar/></text> </g>
|
||||
<g id="shape9-19" v:mID="9" v:groupContext="shape" transform="translate(114,-65.4848)">
|
||||
<title>Box</title>
|
||||
<desc>Hibernate mappings Custom Hibernate DAOs</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)"/>
|
||||
<v:textRect cx="72.45" cy="245.484" width="144.91" height="27.4286"/>
|
||||
<g id="shadow9-20" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
|
||||
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
|
||||
<rect x="0" y="231.77" width="144.9" height="27.4286" class="st5"/>
|
||||
</g>
|
||||
<rect x="0" y="231.77" width="144.9" height="27.4286" class="st6"/>
|
||||
<text x="45.6" y="243.68" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Hibernate mappings<v:newlineChar/><tspan
|
||||
x="39.44" dy="1.2em" class="st8">Custom Hibernate DAOs</tspan></text> </g>
|
||||
<g id="shape10-25" v:mID="10" v:groupContext="shape" transform="translate(16.44,-179.999)">
|
||||
<title>Box.10</title>
|
||||
<desc>Spring Web MVC</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)"/>
|
||||
<v:textRect cx="163.8" cy="246.052" width="327.6" height="26.2929"/>
|
||||
<rect x="0" y="232.906" width="327.6" height="26.2929" class="st3"/>
|
||||
<text x="132.9" y="248.45" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Spring Web MVC</text> </g>
|
||||
<g id="shape6-28" v:mID="6" v:groupContext="shape" transform="translate(20.4,-211.542)">
|
||||
<title>Box.6</title>
|
||||
<desc>Form Controllers handling form interaction</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)"/>
|
||||
<v:textRect cx="36" cy="236.81" width="72" height="44.7771"/>
|
||||
<g id="shadow6-29" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
|
||||
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
|
||||
<rect x="0" y="214.421" width="72" height="44.7771" class="st5"/>
|
||||
</g>
|
||||
<rect x="0" y="214.421" width="72" height="44.7771" class="st6"/>
|
||||
<text x="13.66" y="231.41" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Form Controllers <tspan
|
||||
x="17.82" dy="1.2em" class="st8">handling form </tspan><tspan x="22.16" dy="1.2em" class="st8">interaction</tspan></text> </g>
|
||||
<g id="shape11-35" v:mID="11" v:groupContext="shape" transform="translate(102.48,-211.679)">
|
||||
<title>Box.11</title>
|
||||
<desc>Multipart Resolver to handle file uploads</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)"/>
|
||||
<v:textRect cx="36" cy="236.81" width="72" height="44.7771"/>
|
||||
<g id="shadow11-36" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
|
||||
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
|
||||
<rect x="0" y="214.421" width="72" height="44.7771" class="st5"/>
|
||||
</g>
|
||||
<rect x="0" y="214.421" width="72" height="44.7771" class="st6"/>
|
||||
<text x="11.83" y="235.01" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Multipart Resolver<v:newlineChar/><tspan
|
||||
x="7.65" dy="1.2em" class="st8">to handle file uploads</tspan></text> </g>
|
||||
<g id="shape12-41" v:mID="12" v:groupContext="shape" transform="translate(181.68,-211.679)">
|
||||
<title>Box.12</title>
|
||||
<desc>Dynamic binding of data to the domain model</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)"/>
|
||||
<v:textRect cx="36" cy="236.81" width="72" height="44.7771"/>
|
||||
<g id="shadow12-42" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
|
||||
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
|
||||
<rect x="0" y="214.421" width="72" height="44.7771" class="st5"/>
|
||||
</g>
|
||||
<rect x="0" y="214.421" width="72" height="44.7771" class="st6"/>
|
||||
<text x="10.49" y="231.41" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Dynamic binding of <tspan
|
||||
x="11.15" dy="1.2em" class="st8">data to the domain </tspan><tspan x="27.83" dy="1.2em" class="st8">model</tspan></text> </g>
|
||||
<g id="shape13-48" v:mID="13" v:groupContext="shape" transform="translate(263.76,-211.679)">
|
||||
<title>Box.13</title>
|
||||
<desc>Integration with JSP, Velocity, XSLT, PDF, Excel</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)"/>
|
||||
<v:textRect cx="36" cy="236.81" width="72" height="44.7771"/>
|
||||
<g id="shadow13-49" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
|
||||
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
|
||||
<rect x="0" y="214.421" width="72" height="44.7771" class="st5"/>
|
||||
</g>
|
||||
<rect x="0" y="214.421" width="72" height="44.7771" class="st6"/>
|
||||
<text x="8.49" y="231.41" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Integration with JSP, <tspan
|
||||
x="7.83" dy="1.2em" class="st8">Velocity</tspan>, XSLT, PDF, <tspan x="28.66" dy="1.2em" class="st8">Excel</tspan></text> </g>
|
||||
<g id="shape15-55" v:mID="15" v:groupContext="shape" transform="translate(16.44,-112.319)">
|
||||
<title>Box.15</title>
|
||||
<desc>Spring Context</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)"/>
|
||||
<v:textRect cx="163.8" cy="243.359" width="327.6" height="31.68"/>
|
||||
<rect x="0" y="227.519" width="327.6" height="31.68" class="st3"/>
|
||||
<text x="137.34" y="245.76" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Spring Context</text> </g>
|
||||
<g id="shape8-58" v:mID="8" v:groupContext="shape" transform="translate(114,-138.239)">
|
||||
<title>Box.8</title>
|
||||
<desc>Declarative transaction management for POJOs</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)"/>
|
||||
<v:textRect cx="72" cy="251.999" width="144" height="14.4"/>
|
||||
<g id="shadow8-59" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
|
||||
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
|
||||
<rect x="0" y="244.799" width="144" height="14.4" class="st5"/>
|
||||
</g>
|
||||
<rect x="0" y="244.799" width="144" height="14.4" class="st6"/>
|
||||
<text x="8.31" y="253.8" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Declarative transaction management for POJOs</text> </g>
|
||||
<g id="shape14-63" v:mID="14" v:groupContext="shape" transform="translate(114,-107.999)">
|
||||
<title>Box.14</title>
|
||||
<desc>Custom business logic</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)"/>
|
||||
<v:textRect cx="72" cy="251.999" width="144" height="14.4"/>
|
||||
<g id="shadow14-64" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
|
||||
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
|
||||
<rect x="0" y="244.799" width="144" height="14.4" class="st5"/>
|
||||
</g>
|
||||
<rect x="0" y="244.799" width="144" height="14.4" class="st6"/>
|
||||
<text x="41.99" y="253.8" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Custom business logic</text> </g>
|
||||
<g id="shape16-68" v:mID="16" v:groupContext="shape" transform="translate(0.24,-107.999)">
|
||||
<title>Box.16</title>
|
||||
<desc>Sending Email</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)"/>
|
||||
<v:textRect cx="23.04" cy="231.839" width="46.08" height="54.72"/>
|
||||
<g id="shadow16-69" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
|
||||
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
|
||||
<rect x="0" y="204.479" width="46.08" height="54.72" class="st5"/>
|
||||
</g>
|
||||
<rect x="0" y="204.479" width="46.08" height="54.72" class="st6"/>
|
||||
<text x="12.04" y="230.04" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Sending <tspan
|
||||
x="15.55" dy="1.2em" class="st8">Email</tspan></text> </g>
|
||||
<g id="shape17-74" v:mID="17" v:groupContext="shape" transform="translate(309.84,-107.999)">
|
||||
<title>Box.17</title>
|
||||
<desc>Remote access via Hession, Burlap, SOAP</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)"/>
|
||||
<v:textRect cx="23.04" cy="231.839" width="46.08" height="54.72"/>
|
||||
<g id="shadow17-75" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
|
||||
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
|
||||
<rect x="0" y="204.479" width="46.08" height="54.72" class="st5"/>
|
||||
</g>
|
||||
<rect x="0" y="204.479" width="46.08" height="54.72" class="st6"/>
|
||||
<text x="12.55" y="222.84" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Remote <tspan
|
||||
x="9.04" dy="1.2em" class="st8">access via<v:newlineChar/></tspan><tspan x="11.38" dy="1.2em" class="st8">Hession</tspan>, <tspan
|
||||
x="4.38" dy="1.2em" class="st8">Burlap</tspan>, SOAP</text> </g>
|
||||
<g id="shape18-82" v:mID="18" v:groupContext="shape" transform="translate(114,-172.799)">
|
||||
<title>Box.18</title>
|
||||
<desc>WebApplicationContext providing e.g. messaging</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)"/>
|
||||
<v:textRect cx="72" cy="251.999" width="144" height="14.4"/>
|
||||
<g id="shadow18-83" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
|
||||
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
|
||||
<rect x="0" y="244.799" width="144" height="14.4" class="st5"/>
|
||||
</g>
|
||||
<rect x="0" y="244.799" width="144" height="14.4" class="st6"/>
|
||||
<text x="6.63" y="253.8" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>WebApplicationContext providing e.g. messaging</text> </g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 15 KiB |
BIN
src/reference/docbook/images/html-logo.png
Normal file
|
After Width: | Height: | Size: 77 KiB |
BIN
src/reference/docbook/images/idea-setup-1.png
Normal file
|
After Width: | Height: | Size: 69 KiB |
BIN
src/reference/docbook/images/idea-setup-2.png
Normal file
|
After Width: | Height: | Size: 123 KiB |
BIN
src/reference/docbook/images/idea-setup-3.png
Normal file
|
After Width: | Height: | Size: 122 KiB |
BIN
src/reference/docbook/images/idea-setup-4.png
Normal file
|
After Width: | Height: | Size: 115 KiB |
BIN
src/reference/docbook/images/idea-setup-5.png
Normal file
|
After Width: | Height: | Size: 88 KiB |
BIN
src/reference/docbook/images/idea-setup-6.png
Normal file
|
After Width: | Height: | Size: 73 KiB |
BIN
src/reference/docbook/images/logo-pdf.png
Normal file
|
After Width: | Height: | Size: 76 KiB |
BIN
src/reference/docbook/images/logo.gif
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
BIN
src/reference/docbook/images/logo.jpg
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
src/reference/docbook/images/logo.psd
Normal file
BIN
src/reference/docbook/images/logo.xcf
Normal file
BIN
src/reference/docbook/images/mvc-contexts.gif
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
src/reference/docbook/images/mvc.png
Normal file
|
After Width: | Height: | Size: 124 KiB |
BIN
src/reference/docbook/images/note.gif
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
src/reference/docbook/images/note.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
3559
src/reference/docbook/images/overview-ejb.graffle
Normal file
BIN
src/reference/docbook/images/overview-ejb.png
Normal file
|
After Width: | Height: | Size: 53 KiB |
4884
src/reference/docbook/images/overview-full.graffle
Normal file
BIN
src/reference/docbook/images/overview-full.png
Normal file
|
After Width: | Height: | Size: 94 KiB |
4445
src/reference/docbook/images/overview-remoting.graffle
Normal file
BIN
src/reference/docbook/images/overview-remoting.png
Normal file
|
After Width: | Height: | Size: 56 KiB |
5410
src/reference/docbook/images/overview-thirdparty-web.graffle
Normal file
BIN
src/reference/docbook/images/overview-thirdparty-web.png
Normal file
|
After Width: | Height: | Size: 71 KiB |
1619
src/reference/docbook/images/oxm-exceptions.graffle
Normal file
BIN
src/reference/docbook/images/oxm-exceptions.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
src/reference/docbook/images/pdf-logo.png
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
src/reference/docbook/images/prototype.png
Normal file
|
After Width: | Height: | Size: 92 KiB |
BIN
src/reference/docbook/images/remoting.gif
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
src/reference/docbook/images/remoting.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
143
src/reference/docbook/images/remoting.svg
Normal file
@@ -0,0 +1,143 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<!-- Generated by Microsoft Visio 11.0, SVG Export, v1.0 remoting.svg Page-1 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="4.70667in"
|
||||
height="2.65333in" viewBox="0 0 338.88 191.04" xml:space="preserve" color-interpolation-filters="sRGB" class="st9">
|
||||
<v:documentProperties v:langID="1033" v:metric="true"/>
|
||||
|
||||
<style type="text/css">
|
||||
<![CDATA[
|
||||
.st1 {fill:#f4f7f0;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
|
||||
.st2 {fill:#000000;font-family:Arial;font-size:0.75em}
|
||||
.st3 {fill:#ecefe2;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
|
||||
.st4 {visibility:visible}
|
||||
.st5 {fill:#84877b;stroke:#84877b;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
|
||||
.st6 {fill:#dde2cd;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
|
||||
.st7 {fill:#000000;font-family:Arial;font-size:0.666664em}
|
||||
.st8 {font-size:1em}
|
||||
.st9 {fill:none;fill-rule:evenodd;font-size:12;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
|
||||
]]>
|
||||
</style>
|
||||
|
||||
<g v:mID="0" v:index="1" v:groupContext="foregroundPage">
|
||||
<title>Page-1</title>
|
||||
<v:pageProperties v:drawingScale="1" v:pageScale="1" v:drawingUnits="0" v:shadowOffsetX="8.99999"
|
||||
v:shadowOffsetY="-8.99999"/>
|
||||
<g id="shape1-1" v:mID="1" v:groupContext="shape" transform="translate(0.240333,-10.8)">
|
||||
<title>Box.1</title>
|
||||
<desc>Servlet Container (e.g. Tomcat / Jetty)</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(3.99999,3.99999,3.99999,3.99999)"/>
|
||||
<v:textRect cx="169.199" cy="126.24" width="338.4" height="129.6"/>
|
||||
<rect x="0" y="61.4399" width="338.4" height="129.6" class="st1"/>
|
||||
<text x="93.17" y="177.54" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/>Servlet Container (e.g. Tomcat / Jetty)<v:newlineChar/><v:newlineChar/></text> </g>
|
||||
<g id="shape2-4" v:mID="2" v:groupContext="shape" transform="translate(12.326,-37.8001)">
|
||||
<title>Box.2</title>
|
||||
<desc>Spring Core</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(3.99999,3.99999,3.99999,3.99999)"/>
|
||||
<v:textRect cx="78.5567" cy="158.64" width="157.12" height="64.7999"/>
|
||||
<rect x="0" y="126.24" width="157.114" height="64.7999" class="st3"/>
|
||||
<text x="54.54" y="177.54" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/><v:newlineChar/><v:newlineChar/><v:newlineChar/>Spring Core</text> </g>
|
||||
<g id="shape3-7" v:mID="3" v:groupContext="shape" transform="translate(169.44,-37.8001)">
|
||||
<title>Box.3</title>
|
||||
<desc>Spring Context</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(3.99999,3.99999,3.99999,3.99999)"/>
|
||||
<v:textRect cx="78.5567" cy="158.64" width="157.12" height="64.7999"/>
|
||||
<rect x="0" y="126.24" width="157.114" height="64.7999" class="st3"/>
|
||||
<text x="48.78" y="177.54" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/><v:newlineChar/><v:newlineChar/><v:newlineChar/>Spring Context </text> </g>
|
||||
<g id="shape4-10" v:mID="4" v:groupContext="shape" transform="translate(8.09603,-151.2)">
|
||||
<title>Box.10</title>
|
||||
<desc>JAX RPC client</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(3.99999,3.99999,3.99999,3.99999)"/>
|
||||
<v:textRect cx="38.3717" cy="171.24" width="76.75" height="39.6"/>
|
||||
<g id="shadow4-11" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
|
||||
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
|
||||
<rect x="0" y="151.44" width="76.7442" height="39.6" class="st5"/>
|
||||
</g>
|
||||
<rect x="0" y="151.44" width="76.7442" height="39.6" class="st6"/>
|
||||
<text x="11.03" y="173.64" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>JAX RPC client</text> </g>
|
||||
<g id="shape5-15" v:mID="5" v:groupContext="shape" transform="translate(18.9732,-97.2)">
|
||||
<title>Box.4</title>
|
||||
<desc>Transprarent remote access (using remote package)</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(3.99999,3.99999,3.99999,3.99999)"/>
|
||||
<v:textRect cx="150.466" cy="176.64" width="300.94" height="28.8"/>
|
||||
<g id="shadow5-16" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
|
||||
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
|
||||
<rect x="0" y="162.24" width="300.934" height="28.8" class="st5"/>
|
||||
</g>
|
||||
<rect x="0" y="162.24" width="300.934" height="28.8" class="st6"/>
|
||||
<text x="58.65" y="179.04" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Transp<tspan
|
||||
class="st8" v:langID="2057">ar</tspan>ent remote access (using remote package)</text> </g>
|
||||
<g id="shape6-21" v:mID="6" v:groupContext="shape" transform="translate(18.9732,-68.4)">
|
||||
<title>Box</title>
|
||||
<desc>Custom logic contained by beans</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(3.99999,3.99999,3.99999,3.99999)"/>
|
||||
<v:textRect cx="150.466" cy="176.64" width="300.94" height="28.8"/>
|
||||
<g id="shadow6-22" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
|
||||
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
|
||||
<rect x="0" y="162.24" width="300.934" height="28.8" class="st5"/>
|
||||
</g>
|
||||
<rect x="0" y="162.24" width="300.934" height="28.8" class="st6"/>
|
||||
<text x="91.55" y="179.04" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Custom logic contained by beans</text> </g>
|
||||
<g id="shape7-26" v:mID="7" v:groupContext="shape" transform="translate(96.9259,-151.2)">
|
||||
<title>Box.5</title>
|
||||
<desc>Hessian client</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(3.99999,3.99999,3.99999,3.99999)"/>
|
||||
<v:textRect cx="36.1057" cy="171.24" width="72.22" height="39.6"/>
|
||||
<g id="shadow7-27" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
|
||||
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
|
||||
<rect x="0" y="151.44" width="72.212" height="39.6" class="st5"/>
|
||||
</g>
|
||||
<rect x="0" y="151.44" width="72.212" height="39.6" class="st6"/>
|
||||
<text x="11.2" y="173.64" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Hessian client</text> </g>
|
||||
<g id="shape8-31" v:mID="8" v:groupContext="shape" transform="translate(184.094,-151.2)">
|
||||
<title>Box.6</title>
|
||||
<desc>Burlap client</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(3.99999,3.99999,3.99999,3.99999)"/>
|
||||
<v:textRect cx="33.6885" cy="171.24" width="67.38" height="39.6"/>
|
||||
<g id="shadow8-32" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
|
||||
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
|
||||
<rect x="0" y="151.44" width="67.3778" height="39.6" class="st5"/>
|
||||
</g>
|
||||
<rect x="0" y="151.44" width="67.3778" height="39.6" class="st6"/>
|
||||
<text x="11.69" y="173.64" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Burlap client</text> </g>
|
||||
<g id="shape9-36" v:mID="9" v:groupContext="shape" transform="translate(266.126,-151.2)">
|
||||
<title>Box.7</title>
|
||||
<desc>RMI client</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(3.99999,3.99999,3.99999,3.99999)"/>
|
||||
<v:textRect cx="33.6885" cy="171.24" width="67.38" height="39.6"/>
|
||||
<g id="shadow9-37" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
|
||||
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
|
||||
<rect x="0" y="151.44" width="67.3778" height="39.6" class="st5"/>
|
||||
</g>
|
||||
<rect x="0" y="151.44" width="67.3778" height="39.6" class="st6"/>
|
||||
<text x="26.37" y="168.84" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>RMI<v:newlineChar/><tspan
|
||||
x="24.36" dy="1.2em" class="st8">client</tspan></text> </g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 8.5 KiB |
BIN
src/reference/docbook/images/singleton.png
Normal file
|
After Width: | Height: | Size: 95 KiB |
BIN
src/reference/docbook/images/spring-overview.gif
Normal file
|
After Width: | Height: | Size: 19 KiB |
4787
src/reference/docbook/images/spring-overview.graffle
Normal file
BIN
src/reference/docbook/images/spring-overview.png
Normal file
|
After Width: | Height: | Size: 65 KiB |
198
src/reference/docbook/images/spring-overview.svg
Normal file
@@ -0,0 +1,198 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<!-- Generated by Microsoft Visio 11.0, SVG Export, v1.0 spring-overview.svg Page-1 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="8.26772in"
|
||||
height="11.6929in" viewBox="0 0 595.276 841.89" xml:space="preserve" color-interpolation-filters="sRGB" class="st5">
|
||||
<v:documentProperties v:langID="1033" v:viewMarkup="false"/>
|
||||
|
||||
<style type="text/css">
|
||||
<![CDATA[
|
||||
.st1 {fill:#969696;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
|
||||
.st2 {fill:#dde2cd;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
|
||||
.st3 {fill:#000000;font-family:Arial;font-size:2.50001em;font-weight:bold}
|
||||
.st4 {font-size:0.333333em;font-weight:normal}
|
||||
.st5 {fill:none;fill-rule:evenodd;font-size:12;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
|
||||
]]>
|
||||
</style>
|
||||
|
||||
<g v:mID="0" v:index="1" v:groupContext="foregroundPage">
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="SchemeName" v:val="VT4(Default)"/>
|
||||
</v:userDefs>
|
||||
<title>Page-1</title>
|
||||
<v:pageProperties v:drawingScale="0.0393701" v:pageScale="0.0393701" v:drawingUnits="24" v:shadowOffsetX="8.50394"
|
||||
v:shadowOffsetY="-8.50394"/>
|
||||
<v:layer v:name="Connector" v:index="0"/>
|
||||
<g id="group9-1" transform="translate(549.921,-255.118) scale(-1,1)" v:mID="9" v:groupContext="group">
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="Scale" v:val="VT0(1):26"/>
|
||||
<v:ud v:nameU="AntiScale" v:val="VT0(1):26"/>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<title>3-D box.9</title>
|
||||
<desc>Core The IoC container</desc>
|
||||
<g id="shape10-2" v:mID="10" v:groupContext="shape" transform="translate(0,14.1732)">
|
||||
<title>Sheet.10</title>
|
||||
<path d="M0 827.72 L521.57 827.72 L507.4 841.89 L-14.17 841.89 L0 827.72 Z" class="st1"/>
|
||||
</g>
|
||||
<g id="shape11-4" v:mID="11" v:groupContext="shape" transform="translate(-14.1732,0)">
|
||||
<title>Sheet.11</title>
|
||||
<path d="M0 856.06 L14.17 841.89 L14.17 756.85 L0 771.02 L0 856.06 Z" class="st1"/>
|
||||
</g>
|
||||
<g id="shape12-6" v:mID="12" v:groupContext="shape">
|
||||
<title>Sheet.12</title>
|
||||
<rect x="0" y="756.85" width="521.575" height="85.0394" class="st2"/>
|
||||
</g>
|
||||
<g id="shape9-8" v:mID="9" v:groupContext="groupContent">
|
||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
||||
<v:textRect cx="260.787" cy="799.37" width="521.58" height="85.0394"/>
|
||||
<text x="-294.97" y="797.57" transform="scale(-1,1)" class="st3" v:langID="2057"><v:paragraph v:horizAlign="1"/><v:tabList/>Core<v:newlineChar/><v:newlineChar/><tspan
|
||||
x="-300.54" dy="2.76em" class="st4">The IoC container</tspan></text> </g>
|
||||
</g>
|
||||
<g id="group1-11" transform="translate(269.291,-368.504) scale(-1,1)" v:mID="1" v:groupContext="group">
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="Scale" v:val="VT0(1):26"/>
|
||||
<v:ud v:nameU="AntiScale" v:val="VT0(1):26"/>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<title>3-D box.1</title>
|
||||
<desc>AOP Spring AOP AspectJ integration</desc>
|
||||
<g id="shape2-12" v:mID="2" v:groupContext="shape" transform="translate(0,14.1732)">
|
||||
<title>Sheet.2</title>
|
||||
<path d="M0 827.72 L240.94 827.72 L226.77 841.89 L-14.17 841.89 L0 827.72 Z" class="st1"/>
|
||||
</g>
|
||||
<g id="shape3-14" v:mID="3" v:groupContext="shape" transform="translate(-14.1732,0)">
|
||||
<title>Sheet.3</title>
|
||||
<path d="M0 856.06 L14.17 841.89 L14.17 756.85 L0 771.02 L0 856.06 Z" class="st1"/>
|
||||
</g>
|
||||
<g id="shape4-16" v:mID="4" v:groupContext="shape">
|
||||
<title>Sheet.4</title>
|
||||
<rect x="0" y="756.85" width="240.945" height="85.0394" class="st2"/>
|
||||
</g>
|
||||
<g id="shape1-18" v:mID="1" v:groupContext="groupContent">
|
||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
||||
<v:textRect cx="120.472" cy="799.37" width="240.95" height="85.0394"/>
|
||||
<text x="-152.97" y="791.57" transform="scale(-1,1)" class="st3" v:langID="2057"><v:paragraph v:horizAlign="1"/><v:tabList/>AOP<v:newlineChar/><v:newlineChar/><tspan
|
||||
x="-146.87" dy="2.76em" class="st4">Spring AOP<v:newlineChar/></tspan><tspan x="-162.99" dy="1.2em"
|
||||
class="st4">AspectJ integration</tspan></text> </g>
|
||||
</g>
|
||||
<g id="group5-22" transform="translate(133.228,-481.89) scale(-1,1)" v:mID="5" v:groupContext="group">
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="Scale" v:val="VT0(1):26"/>
|
||||
<v:ud v:nameU="AntiScale" v:val="VT0(1):26"/>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<title>3-D box.5</title>
|
||||
<desc>DAO Spring JDBC Transaction management</desc>
|
||||
<g id="shape6-23" v:mID="6" v:groupContext="shape" transform="translate(0,14.1732)">
|
||||
<title>Sheet.6</title>
|
||||
<path d="M0 827.72 L104.88 827.72 L90.71 841.89 L-14.17 841.89 L0 827.72 Z" class="st1"/>
|
||||
</g>
|
||||
<g id="shape7-25" v:mID="7" v:groupContext="shape" transform="translate(-14.1732,0)">
|
||||
<title>Sheet.7</title>
|
||||
<path d="M0 856.06 L14.17 841.89 L14.17 657.64 L0 671.81 L0 856.06 Z" class="st1"/>
|
||||
</g>
|
||||
<g id="shape8-27" v:mID="8" v:groupContext="shape">
|
||||
<title>Sheet.8</title>
|
||||
<rect x="0" y="657.638" width="104.882" height="184.252" class="st2"/>
|
||||
</g>
|
||||
<g id="shape5-29" v:mID="5" v:groupContext="groupContent">
|
||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
||||
<v:textRect cx="52.4409" cy="749.764" width="104.89" height="184.252"/>
|
||||
<text x="-85.76" y="735.96" transform="scale(-1,1)" class="st3" v:langID="2057"><v:paragraph v:horizAlign="1"/><v:tabList/>DAO<v:newlineChar/><v:newlineChar/><tspan
|
||||
x="-81.33" dy="2.76em" class="st4">Spring JDBC<v:newlineChar/></tspan><tspan x="-78.56" dy="1.2em"
|
||||
class="st4">Transaction </tspan><tspan x="-81.62" dy="1.2em" class="st4">management</tspan></text> </g>
|
||||
</g>
|
||||
<g id="group13-34" transform="translate(413.858,-368.504) scale(-1,1)" v:mID="13" v:groupContext="group">
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="Scale" v:val="VT0(1):26"/>
|
||||
<v:ud v:nameU="AntiScale" v:val="VT0(1):26"/>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<title>3-D box.13</title>
|
||||
<desc>JEE JMX JMS JCA Remoting EJBs Email</desc>
|
||||
<g id="shape14-35" v:mID="14" v:groupContext="shape" transform="translate(0,14.1732)">
|
||||
<title>Sheet.14</title>
|
||||
<path d="M0 827.72 L113.39 827.72 L99.21 841.89 L-14.17 841.89 L0 827.72 Z" class="st1"/>
|
||||
</g>
|
||||
<g id="shape15-37" v:mID="15" v:groupContext="shape" transform="translate(-14.1732,0)">
|
||||
<title>Sheet.15</title>
|
||||
<path d="M0 856.06 L14.17 841.89 L14.17 544.25 L0 558.43 L0 856.06 Z" class="st1"/>
|
||||
</g>
|
||||
<g id="shape16-39" v:mID="16" v:groupContext="shape">
|
||||
<title>Sheet.16</title>
|
||||
<rect x="0" y="544.252" width="113.386" height="297.638" class="st2"/>
|
||||
</g>
|
||||
<g id="shape13-41" v:mID="13" v:groupContext="groupContent">
|
||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
||||
<v:textRect cx="56.6929" cy="693.071" width="113.39" height="297.638"/>
|
||||
<text x="-85.04" y="661.27" transform="scale(-1,1)" class="st3" v:langID="2057"><v:paragraph v:horizAlign="1"/><v:tabList/>JEE<v:newlineChar/><v:newlineChar/><tspan
|
||||
x="-66.69" dy="2.76em" class="st4">JMX<v:newlineChar/></tspan><tspan x="-66.69" dy="1.2em" class="st4">JMS<v:newlineChar/></tspan><tspan
|
||||
x="-66.13" dy="1.2em" class="st4">JCA<v:newlineChar/></tspan><tspan x="-78.08" dy="1.2em" class="st4">Remoting<v:newlineChar/></tspan><tspan
|
||||
x="-68.36" dy="1.2em" class="st4">EJBs<v:newlineChar/></tspan><tspan x="-69.19" dy="1.2em" class="st4">Email</tspan></text> </g>
|
||||
</g>
|
||||
<g id="group17-49" transform="translate(552.756,-368.504) scale(-1,1)" v:mID="17" v:groupContext="group">
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="Scale" v:val="VT0(1):26"/>
|
||||
<v:ud v:nameU="AntiScale" v:val="VT0(1):26"/>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<title>3-D box.17</title>
|
||||
<desc>Web Spring Web MVC Framework Integration Struts WebWork Tapes...</desc>
|
||||
<g id="shape18-50" v:mID="18" v:groupContext="shape" transform="translate(0,14.1732)">
|
||||
<title>Sheet.18</title>
|
||||
<path d="M0 827.72 L113.39 827.72 L99.21 841.89 L-14.17 841.89 L0 827.72 Z" class="st1"/>
|
||||
</g>
|
||||
<g id="shape19-52" v:mID="19" v:groupContext="shape" transform="translate(-14.1732,0)">
|
||||
<title>Sheet.19</title>
|
||||
<path d="M0 856.06 L14.17 841.89 L14.17 544.25 L0 558.43 L0 856.06 Z" class="st1"/>
|
||||
</g>
|
||||
<g id="shape20-54" v:mID="20" v:groupContext="shape">
|
||||
<title>Sheet.20</title>
|
||||
<rect x="0" y="544.252" width="113.386" height="297.638" class="st2"/>
|
||||
</g>
|
||||
<g id="shape17-56" v:mID="17" v:groupContext="groupContent">
|
||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
||||
<v:textRect cx="56.6929" cy="693.071" width="113.39" height="297.638"/>
|
||||
<text x="-88.35" y="613.27" transform="scale(-1,1)" class="st3" v:langID="2057"><v:paragraph v:horizAlign="1"/><v:tabList/>Web<v:newlineChar/><v:newlineChar/><tspan
|
||||
x="-95.31" dy="2.76em" class="st4">Spring Web MVC<v:newlineChar/></tspan><tspan x="-106.71" dy="1.2em"
|
||||
class="st4">Framework Integration<v:newlineChar/></tspan><tspan x="-69.75" dy="1.2em" class="st4">Struts<v:newlineChar/></tspan><tspan
|
||||
x="-78.63" dy="1.2em" class="st4">WebWork<v:newlineChar/></tspan><tspan x="-76.14" dy="1.2em"
|
||||
class="st4">Tapestry<v:newlineChar/></tspan><tspan x="-65.57" dy="1.2em" class="st4">JSF<v:newlineChar/></tspan><tspan
|
||||
x="-97.82" dy="1.2em" class="st4">Rich View Support<v:newlineChar/></tspan><tspan x="-68.36" dy="1.2em"
|
||||
class="st4">JSPs<v:newlineChar/></tspan><tspan x="-74.19" dy="1.2em" class="st4">Velocity<v:newlineChar/></tspan><tspan
|
||||
x="-82.52" dy="1.2em" class="st4">FreeMarker<v:newlineChar/></tspan><tspan x="-66.69" dy="1.2em"
|
||||
class="st4">PDF<v:newlineChar/></tspan><tspan x="-90.59" dy="1.2em" class="st4">Jasper Reports<v:newlineChar/></tspan><tspan
|
||||
x="-68.91" dy="1.2em" class="st4">Excel<v:newlineChar/></tspan><tspan x="-99.48" dy="1.2em" class="st4">Spring Portlet MVC</tspan></text> </g>
|
||||
</g>
|
||||
<g id="group21-72" transform="translate(269.291,-481.89) scale(-1,1)" v:mID="21" v:groupContext="group">
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="Scale" v:val="VT0(1):26"/>
|
||||
<v:ud v:nameU="AntiScale" v:val="VT0(1):26"/>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<title>3-D box.21</title>
|
||||
<desc>ORM Hibernate JPA TopLink JDO OJB iBatis</desc>
|
||||
<g id="shape22-73" v:mID="22" v:groupContext="shape" transform="translate(0,14.1732)">
|
||||
<title>Sheet.22</title>
|
||||
<path d="M0 827.72 L107.72 827.72 L93.54 841.89 L-14.17 841.89 L0 827.72 Z" class="st1"/>
|
||||
</g>
|
||||
<g id="shape23-75" v:mID="23" v:groupContext="shape" transform="translate(-14.1732,0)">
|
||||
<title>Sheet.23</title>
|
||||
<path d="M0 856.06 L14.17 841.89 L14.17 657.64 L0 671.81 L0 856.06 Z" class="st1"/>
|
||||
</g>
|
||||
<g id="shape24-77" v:mID="24" v:groupContext="shape">
|
||||
<title>Sheet.24</title>
|
||||
<rect x="0" y="657.638" width="107.717" height="184.252" class="st2"/>
|
||||
</g>
|
||||
<g id="shape21-79" v:mID="21" v:groupContext="groupContent">
|
||||
<v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
|
||||
<v:textRect cx="53.8583" cy="749.764" width="107.72" height="184.252"/>
|
||||
<text x="-88.86" y="717.96" transform="scale(-1,1)" class="st3" v:langID="2057"><v:paragraph v:horizAlign="1"/><v:tabList/>ORM<v:newlineChar/><v:newlineChar/><tspan
|
||||
x="-75.55" dy="2.76em" class="st4">Hibernate<v:newlineChar/></tspan><tspan x="-63.04" dy="1.2em"
|
||||
class="st4">JPA<v:newlineChar/></tspan><tspan x="-71.65" dy="1.2em" class="st4">TopLink<v:newlineChar/></tspan><tspan
|
||||
x="-63.87" dy="1.2em" class="st4">JDO<v:newlineChar/></tspan><tspan x="-63.59" dy="1.2em" class="st4">OJB<v:newlineChar/></tspan><tspan
|
||||
x="-66.09" dy="1.2em" class="st4">iBatis</tspan></text> </g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 12 KiB |
BIN
src/reference/docbook/images/spring-overview.vsd
Normal file
BIN
src/reference/docbook/images/spring.sxd
Normal file
BIN
src/reference/docbook/images/springsource-banner-rhs.png
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
BIN
src/reference/docbook/images/thirdparty-web.gif
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
src/reference/docbook/images/thirdparty-web.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
131
src/reference/docbook/images/thirdparty-web.svg
Normal file
@@ -0,0 +1,131 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<!-- Generated by Microsoft Visio 11.0, SVG Export, v1.0 thirdparty-web.svg Page-1 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="4.90667in"
|
||||
height="3.29238in" viewBox="0 0 353.28 237.051" xml:space="preserve" color-interpolation-filters="sRGB" class="st9">
|
||||
<v:documentProperties v:langID="1033" v:viewMarkup="false"/>
|
||||
|
||||
<style type="text/css">
|
||||
<![CDATA[
|
||||
.st1 {fill:#f4f7f0;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
|
||||
.st2 {fill:#000000;font-family:Arial;font-size:0.833336em}
|
||||
.st3 {fill:#ecefe2;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
|
||||
.st4 {visibility:visible}
|
||||
.st5 {fill:#84877b;stroke:#84877b;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
|
||||
.st6 {fill:#dde2cd;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
|
||||
.st7 {fill:#000000;font-family:Arial;font-size:0.75em}
|
||||
.st8 {font-size:1em}
|
||||
.st9 {fill:none;fill-rule:evenodd;font-size:12;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
|
||||
]]>
|
||||
</style>
|
||||
|
||||
<g v:mID="0" v:index="1" v:groupContext="foregroundPage">
|
||||
<title>Page-1</title>
|
||||
<v:pageProperties v:drawingScale="1" v:pageScale="1" v:drawingUnits="0" v:shadowOffsetX="9" v:shadowOffsetY="-9"/>
|
||||
<g id="shape11-1" v:mID="11" v:groupContext="shape" transform="translate(0.24,-0.24)">
|
||||
<title>Box.11</title>
|
||||
<desc>Servlet Container (Tomcat / Jetty)</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)"/>
|
||||
<v:textRect cx="176.4" cy="118.766" width="352.8" height="236.571"/>
|
||||
<rect x="0" y="0.48" width="352.8" height="236.571" class="st1"/>
|
||||
<text x="101.65" y="223.77" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/><v:newlineChar/>Servlet Container (Tomcat / Jetty)</text> </g>
|
||||
<g id="shape6-4" v:mID="6" v:groupContext="shape" transform="translate(12.84,-25.9543)">
|
||||
<title>Box.6</title>
|
||||
<desc>Spring Core</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)"/>
|
||||
<v:textRect cx="81.9" cy="206.194" width="163.8" height="61.7143"/>
|
||||
<rect x="0" y="175.337" width="163.8" height="61.7143" class="st3"/>
|
||||
<text x="55.22" y="221.19" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/><v:newlineChar/><v:newlineChar/>Spring Core</text> </g>
|
||||
<g id="shape7-7" v:mID="7" v:groupContext="shape" transform="translate(176.64,-25.9543)">
|
||||
<title>Box.7</title>
|
||||
<desc>Spring DAO</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)"/>
|
||||
<v:textRect cx="81.9" cy="206.194" width="163.81" height="61.7143"/>
|
||||
<rect x="0" y="175.337" width="163.8" height="61.7143" class="st3"/>
|
||||
<text x="55.22" y="221.19" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/><v:newlineChar/><v:newlineChar/>Spring DAO</text> </g>
|
||||
<g id="shape8-10" v:mID="8" v:groupContext="shape" transform="translate(176.64,-87.6686)">
|
||||
<title>Box.8</title>
|
||||
<desc>Spring ORM</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)"/>
|
||||
<v:textRect cx="81.9" cy="206.194" width="163.8" height="61.7143"/>
|
||||
<rect x="0" y="175.337" width="163.8" height="61.7143" class="st3"/>
|
||||
<text x="54.39" y="197.19" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Spring ORM<v:newlineChar/><v:newlineChar/></text> </g>
|
||||
<g id="shape9-13" v:mID="9" v:groupContext="shape" transform="translate(12.84,-149.383)">
|
||||
<title>Box.9</title>
|
||||
<desc>Spring WEB</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)"/>
|
||||
<v:textRect cx="163.8" cy="206.194" width="327.6" height="61.7143"/>
|
||||
<rect x="0" y="175.337" width="327.6" height="61.7143" class="st3"/>
|
||||
<text x="136.57" y="221.19" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/><v:newlineChar/><v:newlineChar/>Spring WEB</text> </g>
|
||||
<g id="shape10-16" v:mID="10" v:groupContext="shape" transform="translate(107.34,-188.811)">
|
||||
<title>Box.10</title>
|
||||
<desc>Web frontend using Struts or WebWork</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)"/>
|
||||
<v:textRect cx="72.45" cy="218.194" width="144.91" height="37.7143"/>
|
||||
<g id="shadow10-17" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
|
||||
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
|
||||
<rect x="0" y="199.337" width="144.9" height="37.7143" class="st5"/>
|
||||
</g>
|
||||
<rect x="0" y="199.337" width="144.9" height="37.7143" class="st6"/>
|
||||
<text x="33.43" y="215.49" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Web frontend using<v:newlineChar/><tspan
|
||||
x="34.44" dy="1.2em" class="st8">Struts or WebWork</tspan></text> </g>
|
||||
<g id="shape12-22" v:mID="12" v:groupContext="shape" transform="translate(12.84,-87.6686)">
|
||||
<title>Box.12</title>
|
||||
<desc>Spring AOP</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)"/>
|
||||
<v:textRect cx="81.9" cy="206.194" width="163.8" height="61.7143"/>
|
||||
<rect x="0" y="175.337" width="163.8" height="61.7143" class="st3"/>
|
||||
<text x="55.5" y="197.19" class="st2" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Spring AOP<v:newlineChar/><v:newlineChar/></text> </g>
|
||||
<g id="shape13-25" v:mID="13" v:groupContext="shape" transform="translate(107.34,-94.5257)">
|
||||
<title>Box.13</title>
|
||||
<desc>Transaction management Using Spring decl. trans.</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)"/>
|
||||
<v:textRect cx="72.45" cy="223.337" width="144.91" height="27.4286"/>
|
||||
<g id="shadow13-26" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
|
||||
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
|
||||
<rect x="0" y="209.623" width="144.9" height="27.4286" class="st5"/>
|
||||
</g>
|
||||
<rect x="0" y="209.623" width="144.9" height="27.4286" class="st6"/>
|
||||
<text x="21.42" y="220.64" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Transaction management<v:newlineChar/><tspan
|
||||
x="23.43" dy="1.2em" class="st8">Using Spring decl</tspan>. trans.</text> </g>
|
||||
<g id="shape5-31" v:mID="5" v:groupContext="shape" transform="translate(107.34,-67.0971)">
|
||||
<title>Box</title>
|
||||
<desc>Hibernate mappings Custom Hibernate DAOs</desc>
|
||||
<v:userDefs>
|
||||
<v:ud v:nameU="visVersion" v:val="VT0(11):26"/>
|
||||
</v:userDefs>
|
||||
<v:textBlock v:margins="rect(4,4,4,4)"/>
|
||||
<v:textRect cx="72.45" cy="223.337" width="144.91" height="27.4286"/>
|
||||
<g id="shadow5-32" v:groupContext="shadow" v:shadowOffsetX="1.8" v:shadowOffsetY="-1.8" v:shadowType="1"
|
||||
transform="matrix(1,0,0,1,1.8,1.8)" class="st4">
|
||||
<rect x="0" y="209.623" width="144.9" height="27.4286" class="st5"/>
|
||||
</g>
|
||||
<rect x="0" y="209.623" width="144.9" height="27.4286" class="st6"/>
|
||||
<text x="32.18" y="220.64" class="st7" v:langID="1033"><v:paragraph v:horizAlign="1"/><v:tabList/>Hibernate mappings<v:newlineChar/><tspan
|
||||
x="22.93" dy="1.2em" class="st8">Custom Hibernate DAOs</tspan></text> </g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.8 KiB |
BIN
src/reference/docbook/images/tx.png
Normal file
|
After Width: | Height: | Size: 81 KiB |
BIN
src/reference/docbook/images/tx_prop_required.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
src/reference/docbook/images/tx_prop_requires_new.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
src/reference/docbook/images/xdev-spring_logo.jpg
Normal file
|
After Width: | Height: | Size: 36 KiB |
517
src/reference/docbook/index.xml
Normal file
@@ -0,0 +1,517 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
<book>
|
||||
<bookinfo>
|
||||
<title>Reference Documentation</title>
|
||||
|
||||
<productname>Spring Framework</productname>
|
||||
|
||||
<releaseinfo>3.1</releaseinfo>
|
||||
|
||||
<mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata align="center" fileref="images/logo-pdf.png" format="PNG"
|
||||
width="240" />
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
|
||||
<authorgroup>
|
||||
<author>
|
||||
<firstname>Rod</firstname>
|
||||
|
||||
<surname>Johnson</surname>
|
||||
</author>
|
||||
|
||||
<author>
|
||||
<firstname>Juergen</firstname>
|
||||
|
||||
<surname>Hoeller</surname>
|
||||
</author>
|
||||
|
||||
<author>
|
||||
<firstname>Keith</firstname>
|
||||
|
||||
<surname>Donald</surname>
|
||||
</author>
|
||||
|
||||
<author>
|
||||
<firstname>Colin</firstname>
|
||||
|
||||
<surname>Sampaleanu</surname>
|
||||
</author>
|
||||
|
||||
<author>
|
||||
<firstname>Rob</firstname>
|
||||
|
||||
<surname>Harrop</surname>
|
||||
</author>
|
||||
|
||||
<author>
|
||||
<firstname>Thomas</firstname>
|
||||
|
||||
<surname>Risberg</surname>
|
||||
</author>
|
||||
|
||||
<author>
|
||||
<firstname>Alef</firstname>
|
||||
|
||||
<surname>Arendsen</surname>
|
||||
</author>
|
||||
|
||||
<author>
|
||||
<firstname>Darren</firstname>
|
||||
|
||||
<surname>Davison</surname>
|
||||
</author>
|
||||
|
||||
<author>
|
||||
<firstname>Dmitriy</firstname>
|
||||
|
||||
<surname>Kopylenko</surname>
|
||||
</author>
|
||||
|
||||
<author>
|
||||
<firstname>Mark</firstname>
|
||||
|
||||
<surname>Pollack</surname>
|
||||
</author>
|
||||
|
||||
<author>
|
||||
<firstname>Thierry</firstname>
|
||||
|
||||
<surname>Templier</surname>
|
||||
</author>
|
||||
|
||||
<author>
|
||||
<firstname>Erwin</firstname>
|
||||
|
||||
<surname>Vervaet</surname>
|
||||
</author>
|
||||
|
||||
<author>
|
||||
<firstname>Portia</firstname>
|
||||
|
||||
<surname>Tung</surname>
|
||||
</author>
|
||||
|
||||
<author>
|
||||
<firstname>Ben</firstname>
|
||||
|
||||
<surname>Hale</surname>
|
||||
</author>
|
||||
|
||||
<author>
|
||||
<firstname>Adrian</firstname>
|
||||
|
||||
<surname>Colyer</surname>
|
||||
</author>
|
||||
|
||||
<author>
|
||||
<firstname>John</firstname>
|
||||
|
||||
<surname>Lewis</surname>
|
||||
</author>
|
||||
|
||||
<author>
|
||||
<firstname>Costin</firstname>
|
||||
|
||||
<surname>Leau</surname>
|
||||
</author>
|
||||
|
||||
<author>
|
||||
<firstname>Mark</firstname>
|
||||
|
||||
<surname>Fisher</surname>
|
||||
</author>
|
||||
|
||||
<author>
|
||||
<firstname>Sam</firstname>
|
||||
|
||||
<surname>Brannen</surname>
|
||||
</author>
|
||||
|
||||
<author>
|
||||
<firstname>Ramnivas</firstname>
|
||||
|
||||
<surname>Laddad</surname>
|
||||
</author>
|
||||
|
||||
<author>
|
||||
<firstname>Arjen</firstname>
|
||||
|
||||
<surname>Poutsma</surname>
|
||||
</author>
|
||||
|
||||
<author>
|
||||
<firstname>Chris</firstname>
|
||||
|
||||
<surname>Beams</surname>
|
||||
</author>
|
||||
|
||||
<author>
|
||||
<firstname>Tareq</firstname>
|
||||
|
||||
<surname>Abedrabbo</surname>
|
||||
</author>
|
||||
|
||||
<author>
|
||||
<firstname>Andy</firstname>
|
||||
|
||||
<surname>Clement</surname>
|
||||
</author>
|
||||
|
||||
<author>
|
||||
<firstname>Dave</firstname>
|
||||
|
||||
<surname>Syer</surname>
|
||||
</author>
|
||||
|
||||
<author>
|
||||
<firstname>Oliver</firstname>
|
||||
|
||||
<surname>Gierke</surname>
|
||||
</author>
|
||||
|
||||
<author>
|
||||
<firstname>Rossen</firstname>
|
||||
<surname>Stoyanchev</surname>
|
||||
</author>
|
||||
|
||||
</authorgroup>
|
||||
|
||||
<copyright>
|
||||
<year>2004-2011</year>
|
||||
|
||||
<holder>Rod Johnson, Juergen Hoeller, Keith Donald, Colin Sampaleanu,
|
||||
Rob Harrop, Alef Arendsen, Thomas Risberg, Darren Davison, Dmitriy
|
||||
Kopylenko, Mark Pollack, Thierry Templier, Erwin Vervaet, Portia Tung,
|
||||
Ben Hale, Adrian Colyer, John Lewis, Costin Leau, Mark Fisher, Sam
|
||||
Brannen, Ramnivas Laddad, Arjen Poutsma, Chris Beams, Tareq Abedrabbo,
|
||||
Andy Clement, Dave Syer, Oliver Gierke, Rossen Stoyanchev</holder>
|
||||
</copyright>
|
||||
|
||||
<legalnotice>
|
||||
<para>Copies of this document may be made for your own use and for
|
||||
distribution to others, provided that you do not charge any fee for such
|
||||
copies and further provided that each copy contains this Copyright
|
||||
Notice, whether distributed in print or electronically.</para>
|
||||
</legalnotice>
|
||||
</bookinfo>
|
||||
|
||||
<!-- front matter -->
|
||||
|
||||
<toc></toc>
|
||||
|
||||
<part id="spring-introduction">
|
||||
<title>Overview of Spring Framework</title>
|
||||
|
||||
<partintro id="spring-core-intro">
|
||||
<para>The Spring Framework is a lightweight solution and a potential
|
||||
one-stop-shop for building your enterprise-ready applications. However,
|
||||
Spring is modular, allowing you to use only those parts that you need,
|
||||
without having to bring in the rest. You can use the IoC container, with
|
||||
Struts on top, but you can also use only the <link
|
||||
linkend="orm-hibernate">Hibernate integration code</link> or the <link
|
||||
linkend="jdbc-introduction">JDBC abstraction layer</link>. The Spring
|
||||
Framework supports declarative transaction management, remote access to
|
||||
your logic through RMI or web services, and various options for
|
||||
persisting your data. It offers a full-featured <link
|
||||
linkend="mvc-introduction">MVC framework</link>, and enables you to
|
||||
integrate <link linkend="aop-introduction">AOP</link> transparently into
|
||||
your software.</para>
|
||||
|
||||
<para>Spring is designed to be non-intrusive, meaning that your domain
|
||||
logic code generally has no dependencies on the framework itself. In
|
||||
your integration layer (such as the data access layer), some
|
||||
dependencies on the data access technology and the Spring libraries will
|
||||
exist. However, it should be easy to isolate these dependencies from the
|
||||
rest of your code base.</para>
|
||||
|
||||
<para>This document is a reference guide to Spring Framework features.
|
||||
If you have any requests, comments, or questions on this document,
|
||||
please post them on the user mailing list or on the support forums at
|
||||
<ulink url="http://forum.springsource.org/"></ulink>.<!--Missing link above. PDF shows it as http://forum.springsource.org/--></para>
|
||||
</partintro>
|
||||
|
||||
<xi:include href="overview.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</part>
|
||||
|
||||
<part id="spring-whats-new">
|
||||
<title>What's New in Spring 3</title>
|
||||
|
||||
<xi:include href="new-in-3.0.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
<xi:include href="new-in-3.1.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</part>
|
||||
|
||||
<part id="spring-core">
|
||||
<title>Core Technologies</title>
|
||||
|
||||
<partintro id="spring-core-intro">
|
||||
<para>This part of the reference documentation covers all of those
|
||||
technologies that are absolutely integral to the Spring
|
||||
Framework.</para>
|
||||
|
||||
<para>Foremost amongst these is the Spring Framework's Inversion of
|
||||
Control (IoC) container. A thorough treatment of the Spring Framework's
|
||||
IoC container is closely followed by comprehensive coverage of Spring's
|
||||
Aspect-Oriented Programming (AOP) technologies. The Spring Framework has
|
||||
its own AOP framework, which is conceptually easy to understand, and
|
||||
which successfully addresses the 80% sweet spot of AOP requirements in
|
||||
Java enterprise programming.</para>
|
||||
|
||||
<para>Coverage of Spring's integration with AspectJ (currently the
|
||||
richest - in terms of features - and certainly most mature AOP
|
||||
implementation in the Java enterprise space) is also provided.</para>
|
||||
|
||||
<para>Finally, the adoption of the test-driven-development (TDD)
|
||||
approach to software development is certainly advocated by the Spring
|
||||
team, and so coverage of Spring's support for integration testing is
|
||||
covered (alongside best practices for unit testing). The Spring team has
|
||||
found that the correct use of IoC certainly does make both unit and
|
||||
integration testing easier (in that the presence of setter methods and
|
||||
appropriate constructors on classes makes them easier to wire together
|
||||
in a test without having to set up service locator registries and
|
||||
suchlike)... the chapter dedicated solely to testing will hopefully
|
||||
convince you of this as well.</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><xref linkend="beans" /></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><xref linkend="resources" /></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><xref linkend="validation" /></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><xref linkend="expressions" /></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><xref linkend="aop" /></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><xref linkend="aop-api" /></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><xref linkend="testing" /></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</partintro>
|
||||
|
||||
<xi:include href="beans.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
|
||||
<xi:include href="resources.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
|
||||
<xi:include href="validation.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
|
||||
<xi:include href="expressions.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
|
||||
<xi:include href="aop.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
|
||||
<xi:include href="aop-api.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
|
||||
<xi:include href="testing.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</part>
|
||||
|
||||
<part id="spring-data-tier">
|
||||
<title>Data Access</title>
|
||||
|
||||
<partintro id="spring-data-tier-intro">
|
||||
<para>This part of the reference documentation is concerned with data
|
||||
access and the interaction between the data access layer and the
|
||||
business or service layer.</para>
|
||||
|
||||
<para>Spring's comprehensive transaction management support is covered
|
||||
in some detail, followed by thorough coverage of the various data access
|
||||
frameworks and technologies that the Spring Framework integrates
|
||||
with.</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><xref linkend="transaction" /></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><xref linkend="dao" /></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><xref linkend="jdbc" /></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><xref linkend="orm" /></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><xref linkend="oxm" /></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</partintro>
|
||||
|
||||
<xi:include href="transaction.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
|
||||
<xi:include href="dao.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
|
||||
<xi:include href="jdbc.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
|
||||
<xi:include href="orm.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
|
||||
<xi:include href="oxm.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</part>
|
||||
|
||||
<part id="spring-web">
|
||||
<title>The Web</title>
|
||||
|
||||
<partintro id="spring-web-intro">
|
||||
<para>This part of the reference documentation covers the Spring
|
||||
Framework's support for the presentation tier (and specifically
|
||||
web-based presentation tiers).</para>
|
||||
|
||||
<para>The Spring Framework's own web framework, <link
|
||||
linkend="mvc">Spring Web MVC</link>, is covered in the first couple of
|
||||
chapters. A number of the remaining chapters in this part of the
|
||||
reference documentation are concerned with the Spring Framework's
|
||||
integration with other web technologies, such as <link
|
||||
linkend="struts">Struts</link> and <link linkend="jsf">JSF</link> (to
|
||||
name but two).</para>
|
||||
|
||||
<para>This section concludes with coverage of Spring's MVC <link
|
||||
linkend="portlet">portlet framework</link>.</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><xref linkend="mvc" /></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><xref linkend="view" /></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><xref linkend="web-integration" /></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><xref linkend="portlet" /></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</partintro>
|
||||
|
||||
<xi:include href="mvc.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
|
||||
<xi:include href="view.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
|
||||
<xi:include href="web-integration.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
|
||||
<xi:include href="portlet.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</part>
|
||||
|
||||
<part id="spring-integration">
|
||||
<title>Integration</title>
|
||||
|
||||
<partintro id="spring-integration-intro">
|
||||
<para>This part of the reference documentation covers the Spring
|
||||
Framework's integration with a number of Java EE (and related)
|
||||
technologies.</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><xref linkend="remoting" /></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><xref linkend="ejb" /></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><xref linkend="jms" /></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><xref linkend="jmx" /></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><xref linkend="cci" /></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><xref linkend="mail" /></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><xref linkend="scheduling" /></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><xref linkend="dynamic-language" /></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><xref linkend="cache" /></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</partintro>
|
||||
|
||||
<xi:include href="remoting.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
|
||||
<xi:include href="ejb.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
|
||||
<xi:include href="jms.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
|
||||
<xi:include href="jmx.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
|
||||
<xi:include href="cci.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
|
||||
<xi:include href="mail.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
|
||||
<xi:include href="scheduling.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
|
||||
<xi:include href="dynamic-languages.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
|
||||
<xi:include href="cache.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</part>
|
||||
|
||||
<!-- back matter -->
|
||||
|
||||
<part id="spring-appendices">
|
||||
<title>Appendices</title>
|
||||
|
||||
<xi:include href="classic-spring.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
|
||||
<xi:include href="classic-aop-spring.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
|
||||
<xi:include href="xsd-configuration.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
|
||||
<xi:include href="xml-custom.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
|
||||
<xi:include href="dtd.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
|
||||
<xi:include href="spring.tld.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
|
||||
<xi:include href="spring-form.tld.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</part>
|
||||
</book>
|
||||
3101
src/reference/docbook/jdbc.xml
Normal file
1328
src/reference/docbook/jms.xml
Normal file
1623
src/reference/docbook/jmx.xml
Normal file
400
src/reference/docbook/mail.xml
Normal file
@@ -0,0 +1,400 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
|
||||
<chapter id="mail">
|
||||
<title>Email</title>
|
||||
|
||||
<section id="mail-introduction">
|
||||
<title>Introduction</title>
|
||||
<sidebar>
|
||||
<title>Library dependencies</title>
|
||||
<para>The following additional jars to be on the classpath of your
|
||||
application in order to be able to use the Spring Framework's email library.</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>The <ulink url="http://java.sun.com/products/javamail/">JavaMail</ulink> <filename class="libraryfile">mail.jar</filename> library</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>The <ulink url="http://java.sun.com/products/javabeans/jaf/downloads/index.html">JAF</ulink> <filename class="libraryfile">activation.jar</filename> library</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>All of these libraries are freely available on the web.</para>
|
||||
</sidebar>
|
||||
|
||||
<para>The Spring Framework provides a helpful utility library for sending
|
||||
email that shields the user from the specifics of the underlying mailing
|
||||
system and is responsible for low level resource handling on behalf of
|
||||
the client.</para>
|
||||
|
||||
<para>The <literal>org.springframework.mail</literal> package is the root level package
|
||||
for the Spring Framework's email support. The central interface for sending
|
||||
emails is the <interfacename>MailSender</interfacename> interface; a simple value object
|
||||
encapsulating the properties of a simple mail such as <emphasis>from</emphasis> and
|
||||
<emphasis>to</emphasis> (plus many others) is the <classname>SimpleMailMessage</classname> class.
|
||||
This package also contains a hierarchy of checked exceptions which provide
|
||||
a higher level of abstraction over the lower level mail system exceptions
|
||||
with the root exception being <exceptionname>MailException</exceptionname>. Please
|
||||
refer to the JavaDocs for more information on the rich mail exception hierarchy.</para>
|
||||
|
||||
<para>The <interfacename>org.springframework.mail.javamail.JavaMailSender</interfacename>
|
||||
interface adds specialized <emphasis>JavaMail</emphasis> features such as MIME
|
||||
message support to the <interfacename>MailSender</interfacename> interface
|
||||
(from which it inherits). <interfacename>JavaMailSender</interfacename> also provides a
|
||||
callback interface for preparation of JavaMail MIME messages, called
|
||||
<interfacename>org.springframework.mail.javamail.MimeMessagePreparator</interfacename></para>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="mail-usage">
|
||||
<title>Usage</title>
|
||||
<para>Let's assume there is a business interface called <interfacename>OrderManager</interfacename>:</para>
|
||||
<programlisting language="java"><![CDATA[public interface OrderManager {
|
||||
|
||||
void placeOrder(Order order);
|
||||
}]]></programlisting>
|
||||
|
||||
<para>Let us also assume that there is a requirement stating that an email message
|
||||
with an order number needs to be generated and sent to a customer placing the
|
||||
relevant order.</para>
|
||||
|
||||
<section id="mail-usage-simple">
|
||||
<title>Basic <interfacename>MailSender</interfacename> and <classname>SimpleMailMessage</classname> usage</title>
|
||||
<programlisting language="java"><![CDATA[import org.springframework.mail.MailException;
|
||||
import org.springframework.mail.MailSender;
|
||||
import org.springframework.mail.SimpleMailMessage;
|
||||
|
||||
public class SimpleOrderManager implements OrderManager {
|
||||
|
||||
private MailSender mailSender;
|
||||
private SimpleMailMessage templateMessage;
|
||||
|
||||
public void setMailSender(MailSender mailSender) {
|
||||
this.mailSender = mailSender;
|
||||
}
|
||||
|
||||
public void setTemplateMessage(SimpleMailMessage templateMessage) {
|
||||
this.templateMessage = templateMessage;
|
||||
}
|
||||
|
||||
public void placeOrder(Order order) {
|
||||
|
||||
]]><lineannotation>// Do the business calculations...</lineannotation><![CDATA[
|
||||
|
||||
]]><lineannotation>// Call the collaborators to persist the order...</lineannotation><![CDATA[
|
||||
|
||||
]]><lineannotation>// Create a thread safe "copy" of the template message and customize it</lineannotation><![CDATA[
|
||||
SimpleMailMessage msg = new SimpleMailMessage(this.templateMessage);
|
||||
msg.setTo(order.getCustomer().getEmailAddress());
|
||||
msg.setText(
|
||||
"Dear " + order.getCustomer().getFirstName()
|
||||
+ order.getCustomer().getLastName()
|
||||
+ ", thank you for placing order. Your order number is "
|
||||
+ order.getOrderNumber());
|
||||
try{
|
||||
this.mailSender.send(msg);
|
||||
}
|
||||
catch(MailException ex) {
|
||||
]]><lineannotation>// simply log it and go on...</lineannotation><![CDATA[
|
||||
System.err.println(ex.getMessage());
|
||||
}
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
<para>Find below the bean definitions for the above code:</para>
|
||||
<programlisting language="xml"><![CDATA[<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
|
||||
<property name="host" value="mail.mycompany.com"/>
|
||||
</bean>
|
||||
|
||||
]]><lineannotation><!-- this is a template message that we can pre-load with default state --></lineannotation><![CDATA[
|
||||
<bean id="templateMessage" class="org.springframework.mail.SimpleMailMessage">
|
||||
<property name="from" value="customerservice@mycompany.com"/>
|
||||
<property name="subject" value="Your order"/>
|
||||
</bean>
|
||||
|
||||
<bean id="orderManager" class="com.mycompany.businessapp.support.SimpleOrderManager">
|
||||
<property name="mailSender" ref="mailSender"/>
|
||||
<property name="templateMessage" ref="templateMessage"/>
|
||||
</bean>]]></programlisting>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="mail-usage-mime">
|
||||
<title>Using the <interfacename>JavaMailSender</interfacename> and the <classname>MimeMessagePreparator</classname></title>
|
||||
<para>Here is another implementation of <interfacename>OrderManager</interfacename> using
|
||||
the <interfacename>MimeMessagePreparator</interfacename> callback interface. Please note
|
||||
in this case that the <literal>mailSender</literal> property is of type
|
||||
<interfacename>JavaMailSender</interfacename> so that we are able to use the JavaMail
|
||||
<classname>MimeMessage</classname> class:</para>
|
||||
|
||||
<programlisting language="java"><![CDATA[import javax.mail.Message;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import org.springframework.mail.MailException;
|
||||
import org.springframework.mail.javamail.JavaMailSender;
|
||||
import org.springframework.mail.javamail.MimeMessagePreparator;
|
||||
|
||||
public class SimpleOrderManager implements OrderManager {
|
||||
|
||||
private JavaMailSender mailSender;
|
||||
|
||||
public void setMailSender(JavaMailSender mailSender) {
|
||||
this.mailSender = mailSender;
|
||||
}
|
||||
|
||||
public void placeOrder(final Order order) {
|
||||
|
||||
]]><lineannotation>// Do the business calculations...</lineannotation><![CDATA[
|
||||
|
||||
]]><lineannotation>// Call the collaborators to persist the order...</lineannotation><![CDATA[
|
||||
|
||||
MimeMessagePreparator preparator = new MimeMessagePreparator() {
|
||||
|
||||
public void prepare(MimeMessage mimeMessage) throws Exception {
|
||||
|
||||
mimeMessage.setRecipient(Message.RecipientType.TO,
|
||||
new InternetAddress(order.getCustomer().getEmailAddress()));
|
||||
mimeMessage.setFrom(new InternetAddress("mail@mycompany.com"));
|
||||
mimeMessage.setText(
|
||||
"Dear " + order.getCustomer().getFirstName() + " "
|
||||
+ order.getCustomer().getLastName()
|
||||
+ ", thank you for placing order. Your order number is "
|
||||
+ order.getOrderNumber());
|
||||
}
|
||||
};
|
||||
try {
|
||||
this.mailSender.send(preparator);
|
||||
}
|
||||
catch (MailException ex) {
|
||||
]]><lineannotation>// simply log it and go on...</lineannotation><![CDATA[
|
||||
System.err.println(ex.getMessage());
|
||||
}
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
<note>
|
||||
<para>The mail code is a crosscutting concern and could well be a candidate
|
||||
for refactoring into a <link linkend="aop">custom Spring AOP aspect</link>,
|
||||
which then could be executed at appropriate joinpoints on the
|
||||
<interfacename>OrderManager</interfacename> target.</para>
|
||||
</note>
|
||||
|
||||
<para>The Spring Framework's mail support ships with the standard JavaMail
|
||||
implementation. Please refer to the relevant JavaDocs for more information.</para>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="mail-javamail-mime">
|
||||
<title>Using the JavaMail <classname>MimeMessageHelper</classname></title>
|
||||
|
||||
<para>A class that comes in pretty handy when dealing with JavaMail messages is
|
||||
the <classname>org.springframework.mail.javamail.MimeMessageHelper</classname> class,
|
||||
which shields you from having to use the verbose JavaMail API. Using
|
||||
the <classname>MimeMessageHelper</classname> it is pretty easy to
|
||||
create a <classname>MimeMessage</classname>:</para>
|
||||
<programlisting language="java"><lineannotation>// of course you would use DI in any real-world cases</lineannotation><![CDATA[
|
||||
JavaMailSenderImpl sender = new JavaMailSenderImpl();
|
||||
sender.setHost("mail.host.com");
|
||||
|
||||
MimeMessage message = sender.createMimeMessage();
|
||||
MimeMessageHelper helper = new MimeMessageHelper(message);
|
||||
helper.setTo("test@host.com");
|
||||
helper.setText("Thank you for ordering!");
|
||||
|
||||
sender.send(message);]]></programlisting>
|
||||
|
||||
<section id="mail-javamail-mime-attachments">
|
||||
<title>Sending attachments and inline resources</title>
|
||||
<para>Multipart email messages allow for both attachments and inline resources.
|
||||
Examples of inline resources would be images or a stylesheet you want to use
|
||||
in your message, but that you don't want displayed as an attachment.</para>
|
||||
<section id="mail-javamail-mime-attachments-attachment">
|
||||
<title>Attachments</title>
|
||||
<para>The following example shows you how to use the
|
||||
<classname>MimeMessageHelper</classname> to send an email along with a
|
||||
single JPEG image attachment.</para>
|
||||
<programlisting language="java"><![CDATA[JavaMailSenderImpl sender = new JavaMailSenderImpl();
|
||||
sender.setHost("mail.host.com");
|
||||
|
||||
MimeMessage message = sender.createMimeMessage();
|
||||
|
||||
]]><lineannotation>// use the true flag to indicate you need a multipart message</lineannotation><![CDATA[
|
||||
MimeMessageHelper helper = new MimeMessageHelper(message, true);
|
||||
helper.setTo("test@host.com");
|
||||
|
||||
helper.setText("Check out this image!");
|
||||
|
||||
]]><lineannotation>// let's attach the infamous windows Sample file (this time copied to c:/)</lineannotation><![CDATA[
|
||||
FileSystemResource file = new FileSystemResource(new File("c:/Sample.jpg"));
|
||||
helper.addAttachment("CoolImage.jpg", file);
|
||||
|
||||
sender.send(message);]]></programlisting>
|
||||
</section>
|
||||
<section id="mail-javamail-mime-attachments-inline">
|
||||
<title>Inline resources</title>
|
||||
<para>The following example shows you how to use the
|
||||
<classname>MimeMessageHelper</classname> to send an email along with an
|
||||
inline image.</para>
|
||||
<programlisting language="java"><![CDATA[JavaMailSenderImpl sender = new JavaMailSenderImpl();
|
||||
sender.setHost("mail.host.com");
|
||||
|
||||
MimeMessage message = sender.createMimeMessage();
|
||||
|
||||
]]><lineannotation>// use the true flag to indicate you need a multipart message</lineannotation><![CDATA[
|
||||
MimeMessageHelper helper = new MimeMessageHelper(message, true);
|
||||
helper.setTo("test@host.com");
|
||||
|
||||
]]><lineannotation>// use the true flag to indicate the text included is HTML</lineannotation><![CDATA[
|
||||
helper.setText("<html><body><img src='cid:identifier1234'></body></html>", true);
|
||||
|
||||
]]><lineannotation>// let's include the infamous windows Sample file (this time copied to c:/)</lineannotation><![CDATA[
|
||||
FileSystemResource res = new FileSystemResource(new File("c:/Sample.jpg"));
|
||||
helper.addInline("identifier1234", res);
|
||||
|
||||
sender.send(message);]]></programlisting>
|
||||
<warning>
|
||||
<para>Inline resources are added to the mime message using the
|
||||
specified <literal>Content-ID</literal> (<literal>identifier1234</literal>
|
||||
in the above example). The order in which you are adding the text and the
|
||||
resource are <emphasis role="bold">very</emphasis> important. Be sure to
|
||||
<emphasis>first add the text</emphasis> and after that the resources. If
|
||||
you are doing it the other way around, it won't work!</para>
|
||||
</warning>
|
||||
</section>
|
||||
</section>
|
||||
<section id="mail-templates">
|
||||
<title>Creating email content using a templating library</title>
|
||||
<para>The code in the previous examples explicitly created the
|
||||
content of the email message, using methods calls such as
|
||||
<methodname>message.setText(..)</methodname>. This is fine for
|
||||
simple cases, and it is okay in the context of the aforementioned
|
||||
examples, where the intent was to show you the very basics of the API.</para>
|
||||
<para>In your typical enterprise application though, you are not going
|
||||
to create the content of your emails using the above approach for a number
|
||||
of reasons.</para>
|
||||
<para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Creating HTML-based email content in Java code is tedious and error prone</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>There is no clear separation between display logic and business logic</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Changing the display structure of the email content requires writing Java code, recompiling, redeploying...</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<para>Typically the approach taken to address these issues is to use a template library
|
||||
such as FreeMarker or Velocity to define the display structure of email content. This leaves
|
||||
your code tasked only with creating the data that is to be rendered in the email
|
||||
template and sending the email. It is definitely a best practice for when
|
||||
the content of your emails becomes even moderately complex, and with
|
||||
the Spring Framework's support classes for FreeMarker and Velocity becomes
|
||||
quite easy to do. Find below an example of using the Velocity template library
|
||||
to create email content.</para>
|
||||
<section id="mail-templates-example">
|
||||
<title>A Velocity-based example</title>
|
||||
<para>To use <ulink url="http://velocity.apache.org">Velocity</ulink> to
|
||||
create your email template(s), you will need to have the Velocity libraries
|
||||
available on your classpath. You will also need to create one or more Velocity templates
|
||||
for the email content that your application needs. Find below the Velocity
|
||||
template that this example will be using. As you can see it is HTML-based,
|
||||
and since it is plain text it can be created using your favorite HTML
|
||||
or text editor.</para>
|
||||
<programlisting language="xml"><lineannotation># in the <literal>com/foo/package</literal></lineannotation><![CDATA[
|
||||
<html>
|
||||
<body>
|
||||
<h3>Hi ${user.userName}, welcome to the Chipping Sodbury On-the-Hill message boards!</h3>
|
||||
|
||||
<div>
|
||||
Your email address is <a href="mailto:${user.emailAddress}">${user.emailAddress}</a>.
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>]]></programlisting>
|
||||
<para>Find below some simple code and Spring XML configuration that
|
||||
makes use of the above Velocity template to create email content and
|
||||
send email(s).</para>
|
||||
<programlisting language="java"><![CDATA[package com.foo;
|
||||
|
||||
import org.apache.velocity.app.VelocityEngine;
|
||||
import org.springframework.mail.javamail.JavaMailSender;
|
||||
import org.springframework.mail.javamail.MimeMessageHelper;
|
||||
import org.springframework.mail.javamail.MimeMessagePreparator;
|
||||
import org.springframework.ui.velocity.VelocityEngineUtils;
|
||||
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class SimpleRegistrationService implements RegistrationService {
|
||||
|
||||
private JavaMailSender mailSender;
|
||||
private VelocityEngine velocityEngine;
|
||||
|
||||
public void setMailSender(JavaMailSender mailSender) {
|
||||
this.mailSender = mailSender;
|
||||
}
|
||||
|
||||
public void setVelocityEngine(VelocityEngine velocityEngine) {
|
||||
this.velocityEngine = velocityEngine;
|
||||
}
|
||||
|
||||
public void register(User user) {
|
||||
|
||||
]]><lineannotation>// Do the registration logic...</lineannotation><![CDATA[
|
||||
|
||||
sendConfirmationEmail(user);
|
||||
}
|
||||
|
||||
private void sendConfirmationEmail(final User user) {
|
||||
MimeMessagePreparator preparator = new MimeMessagePreparator() {
|
||||
public void prepare(MimeMessage mimeMessage) throws Exception {
|
||||
MimeMessageHelper message = new MimeMessageHelper(mimeMessage);
|
||||
message.setTo(user.getEmailAddress());
|
||||
message.setFrom("webmaster@csonth.gov.uk"); ]]><lineannotation>// could be parameterized...</lineannotation><![CDATA[
|
||||
Map model = new HashMap();
|
||||
model.put("user", user);
|
||||
String text = VelocityEngineUtils.mergeTemplateIntoString(
|
||||
velocityEngine, "com/dns/registration-confirmation.vm", model);
|
||||
message.setText(text, true);
|
||||
}
|
||||
};
|
||||
this.mailSender.send(preparator);
|
||||
}
|
||||
}]]></programlisting>
|
||||
<programlisting language="xml"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
|
||||
|
||||
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
|
||||
<property name="host" value="mail.csonth.gov.uk"/>
|
||||
</bean>
|
||||
|
||||
<bean id="registrationService" class="com.foo.SimpleRegistrationService">
|
||||
<property name="mailSender" ref="mailSender"/>
|
||||
<property name="velocityEngine" ref="velocityEngine"/>
|
||||
</bean>
|
||||
|
||||
<bean id="velocityEngine" class="org.springframework.ui.velocity.VelocityEngineFactoryBean">
|
||||
<property name="velocityProperties">
|
||||
<value>
|
||||
resource.loader=class
|
||||
class.resource.loader.class=org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
|
||||
</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
</beans>]]></programlisting>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
4632
src/reference/docbook/mvc.xml
Normal file
514
src/reference/docbook/new-in-3.0.xml
Normal file
@@ -0,0 +1,514 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
<chapter id="new-in-3.0">
|
||||
<title>New Features and Enhancements in Spring 3.0</title>
|
||||
|
||||
<para>If you have been using the Spring Framework for some time, you will be
|
||||
aware that Spring has undergone two major revisions: Spring 2.0, released in
|
||||
October 2006, and Spring 2.5, released in November 2007. It is now time for
|
||||
a third overhaul resulting in Spring 3.0.</para>
|
||||
|
||||
<sidebar id="new-in-3.0-intro-java">
|
||||
<title>Java SE and Java EE Support</title>
|
||||
|
||||
<para>The Spring Framework is now based on Java 5, and Java 6 is fully
|
||||
supported.</para>
|
||||
|
||||
<para>Furthermore, Spring is compatible with J2EE 1.4 and Java EE 5, while
|
||||
at the same time introducing some early support for Java EE 6.</para>
|
||||
</sidebar>
|
||||
|
||||
<section id="new-in-3.0-intro">
|
||||
<title>Java 5</title>
|
||||
|
||||
<para>The entire framework code has been revised to take advantage of Java
|
||||
5 features like generics, varargs and other language improvements. We have
|
||||
done our best to still keep the code backwards compatible. We now have
|
||||
consistent use of generic Collections and Maps, consistent use of generic
|
||||
FactoryBeans, and also consistent resolution of bridge methods in the
|
||||
Spring AOP API. Generic ApplicationListeners automatically receive
|
||||
specific event types only. All callback interfaces such as
|
||||
TransactionCallback and HibernateCallback declare a generic result value
|
||||
now. Overall, the Spring core codebase is now freshly revised and
|
||||
optimized for Java 5.</para>
|
||||
|
||||
<para>Spring's TaskExecutor abstraction has been updated for close
|
||||
integration with Java 5's java.util.concurrent facilities. We provide
|
||||
first-class support for Callables and Futures now, as well as
|
||||
ExecutorService adapters, ThreadFactory integration, etc. This has been
|
||||
aligned with JSR-236 (Concurrency Utilities for Java EE 6) as far as
|
||||
possible. Furthermore, we provide support for asynchronous method
|
||||
invocations through the use of the new @Async annotation (or EJB 3.1's
|
||||
@Asynchronous annotation).</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-3.0-improved-docs">
|
||||
<title>Improved documentation</title>
|
||||
|
||||
<para>The Spring reference documentation has also substantially been
|
||||
updated to reflect all of the changes and new features for Spring 3.0.
|
||||
While every effort has been made to ensure that there are no errors in
|
||||
this documentation, some errors may nevertheless have crept in. If you do
|
||||
spot any typos or even more serious errors, and you can spare a few cycles
|
||||
during lunch, please do bring the error to the attention of the Spring
|
||||
team by <ulink url="http://jira.springframework.org/">raising an
|
||||
issue</ulink>.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-3.0-new-tutorial">
|
||||
<title>New articles and tutorials</title>
|
||||
|
||||
<para>
|
||||
There are many excellent articles and tutorials that show how to get started with Spring 3 features.
|
||||
Read them at the <ulink url="http://www.springsource.org/documentation">Spring Documentation</ulink> page.
|
||||
</para>
|
||||
<para id="new-in-3.0-samples">
|
||||
The samples have been improved and updated to take advantage of the new features in Spring 3.
|
||||
Additionally, the samples have been moved out of the source tree into a dedicated SVN
|
||||
<ulink url="https://anonsvn.springframework.org/svn/spring-samples/">repository</ulink> available at:</para>
|
||||
|
||||
<para>
|
||||
<literal>https://anonsvn.springframework.org/svn/spring-samples/</literal>
|
||||
</para>
|
||||
|
||||
<para>As such, the samples are no longer distributed alongside Spring 3 and need to be downloaded separately from the repository mentioned above. However, this documentation
|
||||
will continue to refer to some samples (in particular Petclinic) to illustrate various features.</para>
|
||||
|
||||
<note>For more information on Subversion (or in short SVN), see the project homepage at:
|
||||
<literal>http://subversion.apache.org/</literal>
|
||||
</note>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="new-in-3.0-modules-build">
|
||||
<title>New module organization and build system</title>
|
||||
|
||||
<para>The framework modules have been revised and are now managed
|
||||
separately with one source-tree per module jar:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>org.springframework.aop</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>org.springframework.beans</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>org.springframework.context</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>org.springframework.context.support</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>org.springframework.expression</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>org.springframework.instrument</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>org.springframework.jdbc</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>org.springframework.jms</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>org.springframework.orm</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>org.springframework.oxm</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>org.springframework.test</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>org.springframework.transaction</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>org.springframework.web</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>org.springframework.web.portlet</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>org.springframework.web.servlet</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>org.springframework.web.struts</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<sidebar id="new-in-3.0-intro-spring-jar">
|
||||
<title>Note:</title>
|
||||
|
||||
<para>The spring.jar artifact that contained almost the entire framework
|
||||
is no longer provided.</para>
|
||||
</sidebar>
|
||||
|
||||
<para>We are now using a new Spring build system as known from Spring Web
|
||||
Flow 2.0. This gives us:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Ivy-based "Spring Build" system</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>consistent deployment procedure</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>consistent dependency management</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>consistent generation of OSGi manifests</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section id="new-in-3.0-features-overview">
|
||||
<title>Overview of new features</title>
|
||||
|
||||
<para>This is a list of new features for Spring 3.0. We will cover these
|
||||
features in more detail later in this section.</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Spring Expression Language</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>IoC enhancements/Java based bean metadata</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>General-purpose type conversion system and field formatting
|
||||
system</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Object to XML mapping functionality (OXM) moved from Spring Web
|
||||
Services project</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Comprehensive REST support</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>@MVC additions</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Declarative model validation</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Early support for Java EE 6</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Embedded database support</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<section id="new-feature-java5">
|
||||
<title>Core APIs updated for Java 5</title>
|
||||
|
||||
<para>BeanFactory interface returns typed bean instances as far as
|
||||
possible: <itemizedlist>
|
||||
<listitem>
|
||||
<para>T getBean(Class<T> requiredType)</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>T getBean(String name, Class<T> requiredType)</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Map<String, T> getBeansOfType(Class<T>
|
||||
type)</para>
|
||||
</listitem>
|
||||
</itemizedlist></para>
|
||||
|
||||
<para>Spring's TaskExecutor interface now extends
|
||||
<classname>java.util.concurrent.Executor</classname>: <itemizedlist>
|
||||
<listitem>
|
||||
<para>extended AsyncTaskExecutor supports standard Callables with
|
||||
Futures</para>
|
||||
</listitem>
|
||||
</itemizedlist></para>
|
||||
|
||||
<para>New Java 5 based converter API and SPI: <itemizedlist>
|
||||
<listitem>
|
||||
<para>stateless ConversionService and Converters</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>superseding standard JDK PropertyEditors</para>
|
||||
</listitem>
|
||||
</itemizedlist></para>
|
||||
|
||||
<para>Typed ApplicationListener<E></para>
|
||||
</section>
|
||||
|
||||
<section id="new-feature-el">
|
||||
<title>Spring Expression Language</title>
|
||||
|
||||
<para>Spring introduces an expression language which is similar to
|
||||
Unified EL in its syntax but offers significantly more features. The
|
||||
expression language can be used when defining XML and Annotation based
|
||||
bean definitions and also serves as the foundation for expression
|
||||
language support across the Spring portfolio. Details of this new
|
||||
functionality can be found in the chapter <link
|
||||
linkend="expressions">Spring Expression Language (SpEL).</link></para>
|
||||
|
||||
<para>The Spring Expression Language was created to provide the Spring
|
||||
community a single, well supported expression language that can be used
|
||||
across all the products in the Spring portfolio. Its language features
|
||||
are driven by the requirements of the projects in the Spring portfolio,
|
||||
including tooling requirements for code completion support within the
|
||||
Eclipse based <ulink url="http://www.springsource.com/products/sts">SpringSource
|
||||
Tool Suite</ulink>.</para>
|
||||
|
||||
<para>The following is an example of how the Expression Language can be
|
||||
used to configure some properties of a database setup <programlisting
|
||||
language="xml"><bean class="mycompany.RewardsTestDatabase">
|
||||
<property name="databaseName"
|
||||
value="#{systemProperties.databaseName}"/>
|
||||
<property name="keyGenerator"
|
||||
value="#{strategyBean.databaseKeyGenerator}"/>
|
||||
</bean>
|
||||
</programlisting></para>
|
||||
|
||||
<para>This functionality is also available if you prefer to configure
|
||||
your components using annotations: <programlisting language="java">@Repository
|
||||
public class RewardsTestDatabase {
|
||||
|
||||
@Value("#{systemProperties.databaseName}")
|
||||
public void setDatabaseName(String dbName) { … }
|
||||
|
||||
@Value("#{strategyBean.databaseKeyGenerator}")
|
||||
public void setKeyGenerator(KeyGenerator kg) { … }
|
||||
}
|
||||
</programlisting></para>
|
||||
</section>
|
||||
|
||||
<section id="new-feature-java-config">
|
||||
<title>The Inversion of Control (IoC) container</title>
|
||||
|
||||
<section id="new-java-configuration">
|
||||
<title>Java based bean metadata</title>
|
||||
|
||||
<para>Some core features from the <ulink
|
||||
url="http://www.springsource.org/javaconfig">JavaConfig</ulink>
|
||||
project have been added to the Spring Framework now. This means that
|
||||
the following annotations are now directly supported: <itemizedlist>
|
||||
<listitem>
|
||||
<para>@Configuration</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>@Bean</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>@DependsOn</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>@Primary</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>@Lazy</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>@Import</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>@ImportResource</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>@Value</para>
|
||||
</listitem>
|
||||
</itemizedlist></para>
|
||||
|
||||
<para>Here is an example of a Java class providing basic configuration
|
||||
using the new JavaConfig features: <programlisting language="java">package org.example.config;
|
||||
|
||||
@Configuration
|
||||
public class AppConfig {
|
||||
private @Value("#{jdbcProperties.url}") String jdbcUrl;
|
||||
private @Value("#{jdbcProperties.username}") String username;
|
||||
private @Value("#{jdbcProperties.password}") String password;
|
||||
|
||||
@Bean
|
||||
public FooService fooService() {
|
||||
return new FooServiceImpl(fooRepository());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FooRepository fooRepository() {
|
||||
return new HibernateFooRepository(sessionFactory());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SessionFactory sessionFactory() {
|
||||
// wire up a session factory
|
||||
AnnotationSessionFactoryBean asFactoryBean =
|
||||
new AnnotationSessionFactoryBean();
|
||||
asFactoryBean.setDataSource(dataSource());
|
||||
// additional config
|
||||
return asFactoryBean.getObject();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
return new DriverManagerDataSource(jdbcUrl, username, password);
|
||||
}
|
||||
}
|
||||
</programlisting> To get this to work you need to add the following component
|
||||
scanning entry in your minimal application context XML file.
|
||||
<programlisting language="xml"><context:component-scan base-package="org.example.config"/>
|
||||
<util:properties id="jdbcProperties" location="classpath:org/example/config/jdbc.properties"/>
|
||||
</programlisting>
|
||||
Or you can bootstrap a <literal>@Configuration</literal> class directly using
|
||||
<literal>AnnotationConfigApplicationContext</literal>:
|
||||
<programlisting language="java">public static void main(String[] args) {
|
||||
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
|
||||
FooService fooService = ctx.getBean(FooService.class);
|
||||
fooService.doStuff();
|
||||
}</programlisting>
|
||||
See <xref linkend="beans-java-instantiating-container"/> for full information on
|
||||
<literal>AnnotationConfigApplicationContext</literal>.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Defining bean metadata within components</title>
|
||||
|
||||
<para><literal>@Bean</literal> annotated methods are also supported
|
||||
inside Spring components. They contribute a factory bean definition to
|
||||
the container. See <link
|
||||
linkend="beans-factorybeans-annotations">Defining bean metadata within
|
||||
components</link> for more information</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="new-feature-convert-and-format">
|
||||
<title>General purpose type conversion system and field formatting
|
||||
system</title>
|
||||
|
||||
<para>A general purpose <link linkend="core-convert">type conversion
|
||||
system</link> has been introduced. The system is currently used by SpEL
|
||||
for type conversion, and may also be used by a Spring Container and DataBinder when
|
||||
binding bean property values.</para>
|
||||
|
||||
<para>In addition, a <link linkend="format">formatter</link> SPI
|
||||
has been introduced for formatting field values. This SPI provides
|
||||
a simpler and more robust alternative to JavaBean PropertyEditors for use in client
|
||||
environments such as Spring MVC.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-feature-oxm">
|
||||
<title>The Data Tier</title>
|
||||
|
||||
<para>Object to XML mapping functionality (OXM) from the Spring Web
|
||||
Services project has been moved to the core Spring Framework now. The
|
||||
functionality is found in the <literal>org.springframework.oxm</literal>
|
||||
package. More information on the use of the <literal>OXM</literal>
|
||||
module can be found in the <link linkend="oxm">Marshalling XML using O/X
|
||||
Mappers</link> chapter.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-feature-rest">
|
||||
<title>The Web Tier</title>
|
||||
|
||||
<para>The most exciting new feature for the Web Tier is the support for
|
||||
building RESTful web services and web applications. There are also some
|
||||
new annotations that can be used in any web application.</para>
|
||||
|
||||
<section>
|
||||
<title>Comprehensive REST support</title>
|
||||
|
||||
<para>Server-side support for building RESTful applications has been
|
||||
provided as an extension of the existing annotation driven MVC web
|
||||
framework. Client-side support is provided by the
|
||||
<classname>RestTemplate</classname> class in the spirit of other
|
||||
template classes such as <classname>JdbcTemplate</classname> and
|
||||
<classname>JmsTemplate</classname>. Both server and client side REST
|
||||
functionality make use of
|
||||
<interfacename>HttpConverter</interfacename>s to facilitate the
|
||||
conversion between objects and their representation in HTTP requests
|
||||
and responses.</para>
|
||||
|
||||
<para>The <classname>MarshallingHttpMessageConverter</classname> uses
|
||||
the <emphasis>Object to XML mapping</emphasis> functionality mentioned
|
||||
earlier.</para>
|
||||
|
||||
<para>Refer to the sections on <link linkend="mvc">MVC</link> and <link
|
||||
linkend="rest-resttemplate">the RestTemplate</link> for more
|
||||
information.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>@MVC additions</title>
|
||||
|
||||
<para>A <literal>mvc</literal> namespace has been introduced that greatly simplifies Spring MVC configuration.</para>
|
||||
|
||||
<para>Additional annotations such as
|
||||
<classname>@CookieValue</classname> and
|
||||
<classname>@RequestHeaders</classname> have been added. See <link
|
||||
linkend="mvc-ann-cookievalue">Mapping cookie values with the
|
||||
@CookieValue annotation</link> and <link
|
||||
linkend="mvc-ann-requestheader">Mapping request header attributes with
|
||||
the @RequestHeader annotation</link> for more information.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="new-feature-validation">
|
||||
<title>Declarative model validation</title>
|
||||
|
||||
<para>Several <link linkend="validation-beanvalidation">validation enhancements</link>,
|
||||
including JSR 303 support that uses Hibernate Validator as the default provider.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-feature-jee-6">
|
||||
<title>Early support for Java EE 6</title>
|
||||
|
||||
<para>We provide support for asynchronous method invocations through the
|
||||
use of the new @Async annotation (or EJB 3.1's @Asynchronous
|
||||
annotation).</para>
|
||||
|
||||
<para>JSR 303, JSF 2.0, JPA 2.0, etc</para>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="new-feature-embedded-databases">
|
||||
<title>Support for embedded databases</title>
|
||||
|
||||
<para>Convenient support for <link
|
||||
linkend="jdbc-embedded-database-support">embedded Java database
|
||||
engines</link>, including HSQL, H2, and Derby, is now provided.</para>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
||||
508
src/reference/docbook/new-in-3.1.xml
Normal file
@@ -0,0 +1,508 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
<chapter id="new-in-3.1">
|
||||
<title>New Features and Enhancements in Spring 3.1</title>
|
||||
|
||||
<para>Building on the support introduced in Spring 3.0, Spring 3.1 is
|
||||
currently under development, and at the time of this writing Spring 3.1 RC1
|
||||
is being prepared for release.</para>
|
||||
|
||||
<section id="new-in-3.1-features-overview">
|
||||
<title>Overview of new features</title>
|
||||
|
||||
<para>This is a list of new features for Spring 3.1. Most features do not
|
||||
yet have dedicated reference documentation but do have Javadoc. In such
|
||||
cases, fully-qualified class names are given.</para>
|
||||
|
||||
<section>
|
||||
<title>Cache Abstraction</title>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><xref linkend="cache" /></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><ulink
|
||||
url="http://blog.springsource.com/2011/02/23/spring-3-1-m1-caching/">
|
||||
Cache Abstraction</ulink> (SpringSource team blog)</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Bean Definition Profiles</title>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><ulink
|
||||
url="http://blog.springsource.com/2011/02/11/spring-framework-3-1-m1-released/">
|
||||
XML profiles</ulink> (SpringSource Team Blog)</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><ulink
|
||||
url="http://blog.springsource.com/2011/02/14/spring-3-1-m1-introducing-profile/">
|
||||
Introducing @Profile</ulink> (SpringSource Team Blog)</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>See org.springframework.context.annotation.Configuration
|
||||
Javadoc</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>See org.springframework.context.annotation.Profile
|
||||
Javadoc</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Environment Abstraction</title>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><ulink
|
||||
url="http://blog.springsource.com/2011/02/11/spring-framework-3-1-m1-released/">
|
||||
Environment Abstraction</ulink> (SpringSource Team Blog)</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>See org.springframework.core.env.Environment Javadoc</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>PropertySource Abstraction</title>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><ulink
|
||||
url="http://blog.springsource.com/2011/02/15/spring-3-1-m1-unified-property-management/">
|
||||
Unified Property Management</ulink> (SpringSource Team Blog)</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>See org.springframework.core.env.Environment Javadoc</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>See org.springframework.core.env.PropertySource Javadoc</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>See org.springframework.context.annotation.PropertySource
|
||||
Javadoc</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Code equivalents for Spring's XML namespaces</title>
|
||||
|
||||
<para>Code-based equivalents to popular Spring XML namespace elements
|
||||
<context:component-scan/>, <tx:annotation-driven/>
|
||||
and <mvc:annotation-driven> have been developed, most in the
|
||||
form of <interfacename>@Enable</interfacename> annotations. These are
|
||||
designed for use in conjunction with Spring's
|
||||
<interfacename>@Configuration</interfacename> classes, which were
|
||||
introduced in Spring 3.0.</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>See org.springframework.context.annotation.Configuration
|
||||
Javadoc</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>See org.springframework.context.annotation.ComponentScan
|
||||
Javadoc</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>See
|
||||
org.springframework.transaction.annotation.EnableTransactionManagement
|
||||
Javadoc</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>See
|
||||
org.springframework.cache.annotation.EnableCaching Javadoc</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>See org.springframework.web.servlet.config.annotation.EnableWebMvc
|
||||
Javadoc</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>See org.springframework.scheduling.annotation.EnableScheduling
|
||||
Javadoc</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>See org.springframework.scheduling.annotation.EnableAsync
|
||||
Javadoc</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>See
|
||||
org.springframework.context.annotation.EnableAspectJAutoProxy
|
||||
Javadoc</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>See
|
||||
org.springframework.context.annotation.EnableLoadTimeWeaving
|
||||
Javadoc</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>See
|
||||
org.springframework.beans.factory.aspectj.EnableSpringConfigured
|
||||
Javadoc</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Support for Hibernate 4.x</title>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>See Javadoc for classes within the new
|
||||
org.springframework.orm.hibernate4 package</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>TestContext framework support for @Configuration classes and bean
|
||||
definition profiles</title>
|
||||
|
||||
<para>The <interfacename>@ContextConfiguration</interfacename>
|
||||
annotation now supports supplying
|
||||
<interfacename>@Configuration</interfacename> classes for configuring
|
||||
the Spring <classname>TestContext</classname>. In addition, a new
|
||||
<interfacename>@ActiveProfiles</interfacename> annotation has been
|
||||
introduced to support declarative configuration of active bean
|
||||
definition profiles in <interfacename>ApplicationContext</interfacename>
|
||||
integration tests.</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><ulink
|
||||
url="http://blog.springsource.com/2011/06/21/spring-3-1-m2-testing-with-configuration-classes-and-profiles/">Spring
|
||||
3.1 M2: Testing with @Configuration Classes and Profiles</ulink>
|
||||
(SpringSource Team Blog)</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>See <xref linkend="testcontext-framework" /></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>See <xref linkend="testcontext-ctx-management-javaconfig" />
|
||||
and
|
||||
<interfacename>org.springframework.test.context.ContextConfiguration</interfacename>
|
||||
Javadoc</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>See
|
||||
<interfacename>org.springframework.test.context.ActiveProfiles</interfacename>
|
||||
Javadoc</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>See
|
||||
<interfacename>org.springframework.test.context.SmartContextLoader</interfacename>
|
||||
Javadoc</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>See
|
||||
<interfacename>org.springframework.test.context.support.DelegatingSmartContextLoader</interfacename>
|
||||
Javadoc</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>See
|
||||
<interfacename>org.springframework.test.context.support.AnnotationConfigContextLoader</interfacename>
|
||||
Javadoc</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>c: namespace for more concise constructor injection</title>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><xref linkend="beans-c-namespace" /></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Support for injection against non-standard JavaBeans
|
||||
setters</title>
|
||||
|
||||
<para>Prior to Spring 3.1, in order to inject against a property method
|
||||
it had to conform strictly to JavaBeans property signature rules, namely
|
||||
that any 'setter' method must be void-returning. It is now possible in
|
||||
Spring XML to specify setter methods that return any object type. This
|
||||
is useful when considering designing APIs for method-chaining, where
|
||||
setter methods return a reference to 'this'.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Support for Servlet 3 code-based configuration of Servlet
|
||||
Container</title>
|
||||
|
||||
<para>The new <interfacename>WebApplicationInitializer</interfacename>
|
||||
builds atop Servlet 3.0's
|
||||
<interfacename>ServletContainerInitializer</interfacename> support to
|
||||
provide a programmatic alternative to the traditional web.xml.</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>See org.springframework.web.WebApplicationInitializer
|
||||
Javadoc</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><ulink url="http://bit.ly/lrDHja">Diff from Spring's
|
||||
Greenhouse reference application</ulink> demonstrating migration
|
||||
from web.xml to
|
||||
<interfacename>WebApplicationInitializer</interfacename></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Support for Servlet 3 MultipartResolver</title>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>See
|
||||
org.springframework.web.multipart.support.StandardServletMultipartResolver
|
||||
Javadoc</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>JPA EntityManagerFactory bootstrapping without
|
||||
persistence.xml</title>
|
||||
|
||||
<para>In standard JPA, persistence units get defined through
|
||||
<literal>META-INF/persistence.xml</literal> files in specific jar files
|
||||
which will in turn get searched for <literal>@Entity</literal> classes.
|
||||
In many cases, persistence.xml does not contain more than a unit name
|
||||
and relies on defaults and/or external setup for all other concerns
|
||||
(such as the DataSource to use, etc). For that reason, Spring 3.1
|
||||
provides an alternative:
|
||||
<classname>LocalContainerEntityManagerFactoryBean</classname> accepts a
|
||||
'packagesToScan' property, specifying base packages to scan for
|
||||
<literal>@Entity</literal> classes. This is analogous to
|
||||
<classname>AnnotationSessionFactoryBean</classname>'s property of the
|
||||
same name for native Hibernate setup, and also to Spring's
|
||||
component-scan feature for regular Spring beans. Effectively, this
|
||||
allows for XML-free JPA setup at the mere expense of specifying a base
|
||||
package for entity scanning: a particularly fine match for Spring
|
||||
applications which rely on component scanning for Spring beans as well,
|
||||
possibly even bootstrapped using a code-based Servlet 3.0
|
||||
initializer.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>New HandlerMethod-based Support Classes For Annotated Controller
|
||||
Processing</title>
|
||||
|
||||
<para>Spring 3.1 introduces a new set of support classes for processing
|
||||
requests with annotated controllers:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><classname>RequestMappingHandlerMapping</classname></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><classname>RequestMappingHandlerAdapter</classname></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><classname>ExceptionHandlerExceptionResolver</classname></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>These classes are a replacement for the existing:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><classname>DefaultAnnotationHandlerMapping</classname></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><classname>AnnotationMethodHandlerAdapter</classname></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><classname>AnnotationMethodHandlerExceptionResolver</classname></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>The new classes were developed in response to many requests to
|
||||
make annotation controller support classes more customizable and open
|
||||
for extension. Whereas previously you could configure a custom annotated
|
||||
controller method argument resolver, with the new support classes you
|
||||
can customize the processing for any supported method argument or return
|
||||
value type.</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>See
|
||||
org.springframework.web.method.support.HandlerMethodArgumentResolver
|
||||
Javadoc</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>See
|
||||
org.springframework.web.method.support.HandlerMethodReturnValueHandler
|
||||
Javadoc</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>A second notable difference is the introduction of a
|
||||
<classname>HandlerMethod</classname> abstraction to represent an
|
||||
<interface>@RequestMapping</interface> method. This abstraction is used
|
||||
throughout by the new support classes as the <literal>handler</literal>
|
||||
instance. For example a <classname>HandlerInterceptor</classname> can
|
||||
cast the <literal>handler</literal> from <classname>Object</classname>
|
||||
to <classname>HandlerMethod</classname> and get access to the target
|
||||
controller method, its annotations, etc.</para>
|
||||
|
||||
<para>The new classes are enabled by default by the MVC namespace and by
|
||||
Java-based configuration via <interface>@EnableWebMvc</interface>. The
|
||||
existing classes will continue to be available but use of the new
|
||||
classes is recommended going forward.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>"consumes" and "produces" conditions in
|
||||
<interface>@RequestMapping</interface></title>
|
||||
|
||||
<para>Improved support for specifying media types consumed by a method
|
||||
through the <literal>'Content-Type'</literal> header as well as for
|
||||
producible types specified through the <literal>'Accept'</literal>
|
||||
header. See <xref linkend="mvc-ann-requestmapping-consumes" /> and <xref
|
||||
linkend="mvc-ann-requestmapping-produces" /></para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Flash Attributes and
|
||||
<interfacename>RedirectAttributes</interfacename></title>
|
||||
|
||||
<para>Flash attributes can now be stored in a
|
||||
<classname>FlashMap</classname> and saved in the HTTP session to survive
|
||||
a redirect. For an overview of the general support for flash attributes
|
||||
in Spring MVC see <xref linkend="mvc-flash-attributes" />.</para>
|
||||
|
||||
<para>In annotated controllers, an
|
||||
<interfacename>@RequestMapping</interfacename> method can add flash
|
||||
attributes by declaring a method argument of type
|
||||
<interfacename>RedirectAttributes</interfacename>. This method argument
|
||||
can now also be used to get precise control over the attributes used in
|
||||
a redirect scenario. See <xref linkend="mvc-ann-redirect-attributes" />
|
||||
for more details.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>URI Template Variable Enhancements</title>
|
||||
|
||||
<para>URI template variables from the current request are used in more
|
||||
places: <itemizedlist>
|
||||
<listitem>
|
||||
<para>URI template variables are used in addition to request
|
||||
parameters when binding a request to
|
||||
<interfacename>@ModelAttribute</interfacename> method
|
||||
arguments.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>@PathVariable method argument values are merged into the
|
||||
model before rendering, except in views that generate content in
|
||||
an automated fashion such as JSON serialization or XML
|
||||
marshalling.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>A redirect string can contain placeholders for URI variables
|
||||
(e.g. <literal>"redirect:/blog/{year}/{month}"</literal>). When
|
||||
expanding the placeholders, URI template variables from the
|
||||
current request are automatically considered.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>An <interfacename>@ModelAttribute</interfacename> method
|
||||
argument can be instantiated from a URI template variable provided
|
||||
there is a registered Converter or PropertyEditor to convert from
|
||||
a String to the target object type.</para>
|
||||
</listitem>
|
||||
</itemizedlist></para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title><interfacename>@Valid</interfacename> On
|
||||
<interface>@RequestBody</interface> Controller Method Arguments</title>
|
||||
|
||||
<para>An <interface>@RequestBody</interface> method argument can be
|
||||
annotated with <interface>@Valid</interface> to invoke automatic
|
||||
validation similar to the support for
|
||||
<interface>@ModelAttribute</interface> method arguments. A resulting
|
||||
<classname>MethodArgumentNotValidException</classname> is handled in the
|
||||
<classname>DefaultHandlerExceptionResolver</classname> and results in a
|
||||
<literal>400</literal> response code.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title><interfacename>@RequestPart</interfacename> Annotation On
|
||||
Controller Method Arguments</title>
|
||||
|
||||
<para>This new annotation provides access to the content of a
|
||||
"multipart/form-data" request part. See <xref
|
||||
linkend="mvc-multipart-forms-non-browsers" /> and <xref
|
||||
linkend="mvc-multipart" />.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title><classname>UriComponentsBuilder</classname> and <classname>UriComponents</classname></title>
|
||||
|
||||
<para>A new <classname>UriComponents</classname> class has been added,
|
||||
which is an immutable container of URI components providing
|
||||
access to all contained URI components.
|
||||
A nenw <classname>UriComponentsBuilder</classname> class is also
|
||||
provided to help create <classname>UriComponents</classname> instances.
|
||||
Together the two classes give fine-grained control over all
|
||||
aspects of preparing a URI including construction, expansion
|
||||
from URI template variables, and encoding.</para>
|
||||
|
||||
<para>In most cases the new classes can be used as a more flexible
|
||||
alternative to the existing <classname>UriTemplate</classname>
|
||||
especially since <classname>UriTemplate</classname> relies on those
|
||||
same classes internally.
|
||||
</para>
|
||||
|
||||
<para>A <classname>ServletUriComponentsBuilder</classname> sub-class
|
||||
provides static factory methods to copy information from
|
||||
a Servlet request. See <xref linkend="mvc-construct-encode-uri"/>.
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
</section>
|
||||
</chapter>
|
||||
2054
src/reference/docbook/orm.xml
Normal file
962
src/reference/docbook/overview.xml
Normal file
@@ -0,0 +1,962 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
<chapter id="overview">
|
||||
<title>Introduction to Spring Framework</title>
|
||||
|
||||
<para>Spring Framework is a Java platform that provides comprehensive
|
||||
infrastructure support for developing Java applications. Spring handles the
|
||||
infrastructure so you can focus on your application.<!--First text mention should be *Spring Framework* not just *Spring*. I revised next sentence because *plumbing* is idiomatic and --><!--*the domain problem* is an unclear reference. Isn't the point that Spring takes care of *under the covers* so you can focus on app? TR: OK.--></para>
|
||||
|
||||
<para>Spring enables you to build applications from “plain old Java objects”
|
||||
(POJOs) and to apply enterprise services non-invasively to POJOs. This
|
||||
capability applies to the Java SE programming model and to full and partial
|
||||
Java EE.</para>
|
||||
|
||||
<para>Examples of how you, as an application developer, can use the Spring
|
||||
platform advantage:<!--In each of the examples, clarify what you mean by *the implementer* (identify it, or is it a person?). ALSO in each sentence replace--><!--*dealing with* APIs with what you mean: what does not have to be done in regard to APIs? IMPORTANT, because this discusses advantage--><!--of product. TR: REVISED, PLS REVIEW. I changed *implementer* to *application developer* and put it upfront rather than repeat it.--></para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Make a Java method execute in a database transaction without
|
||||
having to deal with transaction APIs.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Make a local Java method a remote procedure without having to deal
|
||||
with remote APIs.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Make a local Java method a management operation without having to
|
||||
deal with JMX APIs.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Make a local Java method a message handler without having to deal
|
||||
with JMS APIs.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<section id="overview-dependency-injection">
|
||||
<title>Dependency Injection and Inversion of Control</title>
|
||||
|
||||
<sidebar id="background-ioc">
|
||||
<title>Background</title>
|
||||
|
||||
<para><quote><emphasis>The question is, what aspect of control are
|
||||
[they] inverting?</emphasis></quote> Martin Fowler posed this question
|
||||
about Inversion of Control (IoC) on his site in 2004. Fowler suggested
|
||||
renaming the principle to make it more self-explanatory and came up with
|
||||
<firstterm>Dependency Injection</firstterm>.</para>
|
||||
|
||||
<para>For insight into IoC and DI, refer to Fowler's article at <ulink
|
||||
url="http://martinfowler.com/articles/injection.html">http://martinfowler.com/articles/injection.html</ulink>.</para>
|
||||
</sidebar>
|
||||
|
||||
<para>Java applications -- a loose term that runs the gamut from
|
||||
constrained applets to n-tier server-side enterprise applications --
|
||||
typically consist of objects that collaborate to form the application
|
||||
proper. Thus the objects in an application have
|
||||
<emphasis>dependencies</emphasis> on each other.</para>
|
||||
|
||||
<para>Although the Java platform provides a wealth of application
|
||||
development functionality, it lacks the means to organize the basic
|
||||
building blocks into a coherent whole, leaving that task to architects and
|
||||
developers. True, you can use design patterns such as
|
||||
<firstterm>Factory</firstterm>, <firstterm>Abstract Factory</firstterm>,
|
||||
<firstterm>Builder</firstterm>, <firstterm>Decorator</firstterm>, and
|
||||
<firstterm>Service Locator</firstterm> to compose the various classes and
|
||||
object instances that make up an application. However, these patterns are
|
||||
simply that: best practices given a name, with a description of what the
|
||||
pattern does, where to apply it, the problems it addresses, and so forth.
|
||||
Patterns are formalized best practices that <emphasis>you must implement
|
||||
yourself</emphasis> in your application.</para>
|
||||
|
||||
<para>The Spring Framework <emphasis>Inversion of Control</emphasis> (IoC)
|
||||
component addresses this concern by providing a formalized means of
|
||||
composing disparate components into a fully working application ready for
|
||||
use. <!--Preceding sentence sounds like a description of what patterns do (and Spring uses patterns). Distinguish from patterns.-->The
|
||||
Spring Framework codifies formalized design patterns as first-class
|
||||
objects that you can integrate into your own application(s). <!--Preceding sentence suggests that you already have the application and *then* you integrate design patterns into it. Again, I--><!--don't see a major distinction here from use of patterns (as described in earlier paragraph) and use of IoC component to build apps.
|
||||
|
||||
TR: This section doesn't read well and I think we should try to rewrite it.-->Numerous
|
||||
organizations and institutions use the Spring Framework in this manner to
|
||||
engineer robust, <emphasis>maintainable</emphasis> applications.</para>
|
||||
</section>
|
||||
|
||||
<section id="overview-modules">
|
||||
<title>Modules</title>
|
||||
|
||||
<para>The Spring Framework consists of features organized into about 20
|
||||
modules. These modules are grouped into Core Container, Data
|
||||
Access/Integration, Web, AOP (Aspect Oriented Programming),
|
||||
Instrumentation, and Test, as shown in the following diagram.</para>
|
||||
|
||||
<para><mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata align="left" fileref="images/spring-overview.png"
|
||||
format="PNG" />
|
||||
</imageobject>
|
||||
|
||||
<imageobject role="html">
|
||||
<imagedata align="center" fileref="images/spring-overview.png"
|
||||
format="PNG" />
|
||||
</imageobject>
|
||||
|
||||
<caption><para>Overview of the Spring Framework</para></caption>
|
||||
</mediaobject></para>
|
||||
|
||||
<section>
|
||||
<title>Core Container</title>
|
||||
|
||||
<para>The <link linkend="beans-introduction"><emphasis>Core
|
||||
Container</emphasis></link> consists of the Core, Beans, Context, and
|
||||
Expression Language modules.</para>
|
||||
|
||||
<para>The <link linkend="beans-introduction"><emphasis>Core and
|
||||
Beans</emphasis></link> modules provide the fundamental parts of the
|
||||
framework, including the IoC and Dependency Injection features. The
|
||||
<classname>BeanFactory</classname> is a sophisticated implementation of
|
||||
the factory pattern. It removes the need for programmatic singletons and
|
||||
allows you to decouple the configuration and specification of
|
||||
dependencies from your actual program logic.</para>
|
||||
|
||||
<para>The <link
|
||||
linkend="context-introduction"><emphasis>Context</emphasis></link>
|
||||
module builds on the solid base provided by the <link
|
||||
linkend="beans-introduction"><emphasis>Core and Beans</emphasis></link>
|
||||
modules: it is a means to access objects in a framework-style manner
|
||||
that is similar to a JNDI registry. The Context module inherits its
|
||||
features from the Beans module and adds support for internationalization
|
||||
(using, for example, resource bundles), event-propagation,
|
||||
resource-loading, and the transparent creation of contexts by, for
|
||||
example, a servlet container. The Context module also supports Java EE
|
||||
features such as EJB, JMX ,and basic remoting. The
|
||||
<classname>ApplicationContext</classname> interface is the focal point
|
||||
of the Context module.</para>
|
||||
|
||||
<para>The <link linkend="expressions"><emphasis>Expression
|
||||
Language</emphasis></link> module <!--Provide link as you do with others TR: FIXED.-->provides
|
||||
a powerful expression language for querying and manipulating an object
|
||||
graph at runtime. It is an extension of the unified expression language
|
||||
(unified EL) as specified in the JSP 2.1 specification. The language
|
||||
supports setting and getting property values, property assignment,
|
||||
method invocation, accessing the context of arrays, collections and
|
||||
indexers, logical and arithmetic operators, named variables, and
|
||||
retrieval of objects by name from Spring's IoC container. It also
|
||||
supports list projection and selection as well as common list
|
||||
aggregations.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Data Access/Integration</title>
|
||||
|
||||
<para>The <emphasis>Data Access/Integration</emphasis> layer consists of
|
||||
the JDBC, ORM, OXM, JMS and Transaction modules.</para>
|
||||
|
||||
<para>The <link linkend="jdbc-introduction">JDBC</link> module provides
|
||||
a JDBC-abstraction layer that removes the need to do tedious JDBC coding
|
||||
and parsing of database-vendor specific error codes.</para>
|
||||
|
||||
<para>The <link
|
||||
linkend="orm-introduction"><emphasis>ORM</emphasis></link> module
|
||||
provides integration layers for popular object-relational mapping APIs,
|
||||
including <link linkend="orm-jpa">JPA</link>, <link
|
||||
linkend="orm-jdo">JDO</link>, <link
|
||||
linkend="orm-hibernate">Hibernate</link>, and <link
|
||||
linkend="orm-ibatis">iBatis</link>. Using the ORM package you can use
|
||||
all of these O/R-mapping frameworks in combination with all of the other
|
||||
features Spring offers, such as the simple declarative transaction
|
||||
management feature mentioned previously.</para>
|
||||
|
||||
<para>The <link linkend="oxm">OXM</link> module provides an abstraction
|
||||
layer that supports Object/XML mapping implementations for JAXB, Castor,
|
||||
XMLBeans, JiBX and XStream.</para>
|
||||
|
||||
<para>The Java Messaging Service (<link linkend="jms">JMS</link>) module
|
||||
contains features for producing and consuming messages.</para>
|
||||
|
||||
<para>The <link linkend="transaction">Transaction</link> module supports
|
||||
programmatic and declarative transaction management for classes that
|
||||
implement special interfaces and for <emphasis>all your POJOs (plain old
|
||||
Java objects)</emphasis>.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Web</title>
|
||||
|
||||
<para>The <emphasis>Web</emphasis> layer consists of the Web,
|
||||
Web-Servlet, Web-Struts, and Web-Portlet modules.</para>
|
||||
|
||||
<para>Spring's <emphasis>Web</emphasis> module provides basic
|
||||
web-oriented integration features such as multipart file-upload
|
||||
functionality and the initialization of the IoC container using servlet
|
||||
listeners and a web-oriented application context. It also contains the
|
||||
web-related parts of Spring's remoting support.</para>
|
||||
|
||||
<para>The <emphasis>Web-Servlet</emphasis> module contains Spring's
|
||||
model-view-controller (<link
|
||||
linkend="mvc-introduction"><emphasis>MVC</emphasis></link>)
|
||||
implementation for web applications. Spring's MVC framework provides a
|
||||
clean separation between domain model code and web forms, and integrates
|
||||
with all the other features of the Spring Framework.<!--MVC allows you to use *all other features*? (Or just all other features in Web layer?) How do you mean? Does this need elaboration?
|
||||
It sounds important.--><!--TR: REVISED, PLS REVIEW.--></para>
|
||||
|
||||
<para>The <emphasis>Web-Struts</emphasis> module contains the support
|
||||
classes for integrating a classic Struts web tier within a Spring
|
||||
application. Note that this support is now deprecated as of Spring 3.0.
|
||||
Consider migrating your application to Struts 2.0 and its Spring
|
||||
integration or to a Spring MVC solution.</para>
|
||||
|
||||
<para>The <emphasis>Web-Portlet</emphasis> module provides the MVC
|
||||
implementation to be used in a portlet environment and mirrors the
|
||||
functionality of Web-Servlet module.<!--mirrors it in what way?--><!--TR: REVISED, PLS REVIEW. The functionality is mirrored - one for Servlets and the other for Portlets--></para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>AOP and Instrumentation</title>
|
||||
|
||||
<para>Spring's <link
|
||||
linkend="aop-introduction"><emphasis>AOP</emphasis></link> module
|
||||
provides an <emphasis>AOP Alliance</emphasis>-compliant aspect-oriented
|
||||
programming implementation allowing you to define, for example,
|
||||
method-interceptors and pointcuts to cleanly decouple code that
|
||||
implements functionality that should be separated. Using source-level
|
||||
metadata functionality, you can also incorporate behavioral information
|
||||
into your code, in a manner similar to that of .NET attributes.</para>
|
||||
|
||||
<para>The separate <emphasis>Aspects</emphasis> module provides
|
||||
integration with AspectJ.<!--Aspects module not shown in diagram, add it to that. Also, why is this line under AOP and Instrumentation if it's separate?
|
||||
|
||||
TR: OK. Added to diagram.--></para>
|
||||
|
||||
<para>The <emphasis>Instrumentation</emphasis> module provides class
|
||||
instrumentation support and classloader implementations to be used in
|
||||
certain application servers.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Test</title>
|
||||
|
||||
<para>The <emphasis>Test</emphasis> module supports the testing of
|
||||
Spring components with JUnit or TestNG. It provides consistent loading
|
||||
of Spring ApplicationContexts and caching of those contexts. It also
|
||||
provides mock objects that you can use to test your code in
|
||||
isolation.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="overview-usagescenarios">
|
||||
<title>Usage scenarios</title>
|
||||
|
||||
<para>The building blocks described previously make Spring a logical
|
||||
choice in many scenarios, from applets to full-fledged enterprise
|
||||
applications that use Spring's transaction management functionality and
|
||||
web framework integration.</para>
|
||||
|
||||
<para><mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata align="center" fileref="images/overview-full.png"
|
||||
format="PNG" />
|
||||
</imageobject>
|
||||
|
||||
<imageobject role="html">
|
||||
<imagedata align="center" fileref="images/overview-full.png"
|
||||
format="PNG" />
|
||||
</imageobject>
|
||||
|
||||
<caption><para>Typical full-fledged Spring web
|
||||
application</para></caption>
|
||||
</mediaobject></para>
|
||||
|
||||
<para>Spring's <link linkend="transaction-declarative">declarative
|
||||
transaction management features</link> make the web application fully
|
||||
transactional, just as it would be if you used EJB container-managed
|
||||
transactions. All your custom business logic can be implemented with
|
||||
simple POJOs and managed by Spring's IoC container. Additional services
|
||||
include support for sending email and validation that is independent of
|
||||
the web layer, which lets you choose where to execute validation rules.
|
||||
Spring's ORM support is integrated with JPA, Hibernate, JDO and iBatis;
|
||||
for example, when using Hibernate, you can continue to use your existing
|
||||
mapping files and standard Hibernate
|
||||
<interfacename>SessionFactory</interfacename> configuration. Form
|
||||
controllers seamlessly integrate the web-layer with the domain model,
|
||||
removing the need for <classname>ActionForms</classname> or other classes
|
||||
that transform HTTP parameters to values for your domain model.</para>
|
||||
|
||||
<para><mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata align="center"
|
||||
fileref="images/overview-thirdparty-web.png" format="PNG" />
|
||||
</imageobject>
|
||||
|
||||
<imageobject role="html">
|
||||
<imagedata align="center"
|
||||
fileref="images/overview-thirdparty-web.png" format="PNG" />
|
||||
</imageobject>
|
||||
|
||||
<caption><para>Spring middle-tier using a third-party web
|
||||
framework</para></caption>
|
||||
</mediaobject></para>
|
||||
|
||||
<para>Sometimes circumstances do not allow you to completely switch to a
|
||||
different framework. The Spring Framework does <emphasis>not</emphasis>
|
||||
force you to use everything within it; it is not an
|
||||
<emphasis>all-or-nothing</emphasis> solution. Existing front-ends built
|
||||
with WebWork, Struts, Tapestry, or other UI frameworks can be integrated
|
||||
with a Spring-based middle-tier, which allows you to use Spring
|
||||
transaction features. You simply need to wire up your business logic using
|
||||
an <classname>ApplicationContext</classname> and use a
|
||||
<classname>WebApplicationContext </classname>to integrate your web
|
||||
layer.</para>
|
||||
|
||||
<para><mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata align="center" fileref="images/overview-remoting.png"
|
||||
format="PNG" />
|
||||
</imageobject>
|
||||
|
||||
<imageobject role="html">
|
||||
<imagedata align="center" fileref="images/overview-remoting.png"
|
||||
format="PNG" />
|
||||
</imageobject>
|
||||
|
||||
<caption><para>Remoting usage scenario</para></caption>
|
||||
</mediaobject></para>
|
||||
|
||||
<para>When you need to access existing code through web services, you can
|
||||
use Spring's <literal>Hessian-</literal>, <literal>Burlap-</literal>,
|
||||
<literal>Rmi-</literal> or <classname>JaxRpcProxyFactory</classname>
|
||||
classes. Enabling remote access to existing applications is not
|
||||
difficult.</para>
|
||||
|
||||
<para><mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata align="center" fileref="images/overview-ejb.png"
|
||||
format="PNG" />
|
||||
</imageobject>
|
||||
|
||||
<imageobject role="html">
|
||||
<imagedata align="center" fileref="images/overview-ejb.png"
|
||||
format="PNG" />
|
||||
</imageobject>
|
||||
|
||||
<caption><para>EJBs - Wrapping existing POJOs</para></caption>
|
||||
</mediaobject></para>
|
||||
|
||||
<para>The Spring Framework also provides an <link linkend="ejb">access and
|
||||
abstraction layer</link> for Enterprise JavaBeans, enabling you to reuse
|
||||
your existing POJOs and wrap them in stateless session beans for use in
|
||||
scalable, fail-safe web applications that might need declarative
|
||||
security.</para>
|
||||
|
||||
<section id="dependency-management">
|
||||
<title>Dependency Management and Naming Conventions</title>
|
||||
|
||||
<para>Dependency management and dependency injection are different
|
||||
things. To get those nice features of Spring into your application (like
|
||||
dependency injection) you need to assemble all the libraries needed (jar
|
||||
files) and get them onto your classpath at runtime, and possibly at
|
||||
compile time. These dependencies are not virtual components that are
|
||||
injected, but physical resources in a file system (typically). The
|
||||
process of dependency management involves locating those resources,
|
||||
storing them and adding them to classpaths. Dependencies can be direct
|
||||
(e.g. my application depends on Spring at runtime), or indirect (e.g. my
|
||||
application depends on <code>commons-dbcp</code> which depends on
|
||||
<code>commons-pool</code>). The indirect dependencies are also known as
|
||||
"transitive" and it is those dependencies that are hardest to identify
|
||||
and manage.</para>
|
||||
|
||||
<para>If you are going to use Spring you need to get a copy of the jar
|
||||
libraries that comprise the pieces of Spring that you need. To make this
|
||||
easier Spring is packaged as a set of modules that separate the
|
||||
dependencies as much as possible, so for example if you don't want to
|
||||
write a web application you don't need the spring-web modules. To refer
|
||||
to Spring library modules in this guide we use a shorthand naming
|
||||
convention <code>spring-*</code> or <code>spring-*.jar,</code> where "*"
|
||||
represents the short name for the module (e.g. <code>spring-core</code>,
|
||||
<code>spring-webmvc</code>, <code>spring-jms</code>, etc.). The actual
|
||||
jar file name that you use may be in this form (see below) or it may
|
||||
not, and normally it also has a version number in the file name (e.g.
|
||||
<code>spring-core-3.0.0.RELEASE.jar</code>).</para>
|
||||
|
||||
<para>In general, Spring publishes its artifacts to four different
|
||||
places:<itemizedlist>
|
||||
<listitem>
|
||||
<para>On the community download site <ulink
|
||||
url="http://www.springsource.org/downloads/community">http://www.springsource.org/downloads/community</ulink>.
|
||||
Here you find all the Spring jars bundled together into a zip file
|
||||
for easy download. The names of the jars here since version 3.0
|
||||
are in the form
|
||||
<code>org.springframework.*-<version>.jar</code>.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Maven Central, which is the default repository that Maven
|
||||
queries, and does not require any special configuration to use.
|
||||
Many of the common libraries that Spring depends on also are
|
||||
available from Maven Central and a large section of the Spring
|
||||
community uses Maven for dependency management, so this is
|
||||
convenient for them. The names of the jars here are in the form
|
||||
<code>spring-*-<version>.jar</code> and the Maven groupId is
|
||||
<code>org.springframework</code>.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>The Enterprise Bundle Repository (EBR), which is run by
|
||||
SpringSource and also hosts all the libraries that integrate with
|
||||
Spring. Both Maven and Ivy repositories are available here for all
|
||||
Spring jars and their dependencies, plus a large number of other
|
||||
common libraries that people use in applications with Spring. Both
|
||||
full releases and also milestones and development snapshots are
|
||||
deployed here. The names of the jar files are in the same form as
|
||||
the community download
|
||||
(<code>org.springframework.*-<version>.jar</code>), and the
|
||||
dependencies are also in this "long" form, with external libraries
|
||||
(not from SpringSource) having the prefix
|
||||
<code>com.springsource</code>. See the <ulink security=""
|
||||
url="http://www.springsource.com/repository/app/faq">FAQ</ulink>
|
||||
for more information.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>In a public Maven repository hosted on Amazon S3 for
|
||||
development snapshots and milestone releases (a copy of the final
|
||||
releases is also held here). The jar file names are in the same
|
||||
form as Maven Central, so this is a useful place to get
|
||||
development versions of Spring to use with other libraries depoyed
|
||||
in Maven Central.</para>
|
||||
</listitem>
|
||||
</itemizedlist></para>
|
||||
|
||||
<para>So the first thing you need to decide is how to manage your
|
||||
dependencies: most people use an automated system like Maven or Ivy, but
|
||||
you can also do it manually by downloading all the jars yourself. When
|
||||
obtaining Spring with Maven or Ivy you have then to decide which place
|
||||
you'll get it from. In general, if you care about OSGi, use the EBR,
|
||||
since it houses OSGi compatible artifacts for all of Spring's
|
||||
dependencies, such as Hibernate and Freemarker. If OSGi does not matter
|
||||
to you, either place works, though there are some pros and cons between
|
||||
them. In general, pick one place or the other for your project; do not
|
||||
mix them. This is particularly important since EBR artifacts necessarily
|
||||
use a different naming convention than Maven Central artifacts.</para>
|
||||
|
||||
<para><table>
|
||||
<title>Comparison of Maven Central and SpringSource EBR
|
||||
Repositories</title>
|
||||
|
||||
<tgroup cols="3">
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Feature</entry>
|
||||
|
||||
<entry>Maven Central</entry>
|
||||
|
||||
<entry>EBR</entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>OSGi Compatible</entry>
|
||||
|
||||
<entry>Not explicit</entry>
|
||||
|
||||
<entry>Yes</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Number of Artifacts</entry>
|
||||
|
||||
<entry>Tens of thousands; all kinds</entry>
|
||||
|
||||
<entry>Hundreds; those that Spring integrates with</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Consistent Naming Conventions</entry>
|
||||
|
||||
<entry>No</entry>
|
||||
|
||||
<entry>Yes</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Naming Convention: GroupId</entry>
|
||||
|
||||
<entry>Varies. Newer artifacts often use domain name, e.g.
|
||||
org.slf4j. Older ones often just use the artifact name, e.g.
|
||||
log4j.</entry>
|
||||
|
||||
<entry>Domain name of origin or main package root, e.g.
|
||||
org.springframework</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Naming Convention: ArtifactId</entry>
|
||||
|
||||
<entry>Varies. Generally the project or module name, using a
|
||||
hyphen "-" separator, e.g. spring-core, logj4.</entry>
|
||||
|
||||
<entry>Bundle Symbolic Name, derived from the main package
|
||||
root, e.g. org.springframework.beans. If the jar had to be
|
||||
patched to ensure OSGi compliance then com.springsource is
|
||||
appended, e.g. com.springsource.org.apache.log4j</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Naming Convention: Version</entry>
|
||||
|
||||
<entry>Varies. Many new artifacts use m.m.m or m.m.m.X (with
|
||||
m=digit, X=text). Older ones use m.m. Some neither. Ordering
|
||||
is defined but not often relied on, so not strictly
|
||||
reliable.</entry>
|
||||
|
||||
<entry>OSGi version number m.m.m.X, e.g. 3.0.0.RC3. The text
|
||||
qualifier imposes alphabetic ordering on versions with the
|
||||
same numeric values.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Publishing</entry>
|
||||
|
||||
<entry>Usually automatic via rsync or source control updates.
|
||||
Project authors can upload individual jars to JIRA.</entry>
|
||||
|
||||
<entry>Manual (JIRA processed by SpringSource)</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Quality Assurance</entry>
|
||||
|
||||
<entry>By policy. Accuracy is responsibility of
|
||||
authors.</entry>
|
||||
|
||||
<entry>Extensive for OSGi manifest, Maven POM and Ivy
|
||||
metadata. QA performed by Spring team.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Hosting</entry>
|
||||
|
||||
<entry>Contegix. Funded by Sonatype with several
|
||||
mirrors.</entry>
|
||||
|
||||
<entry>S3 funded by SpringSource.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Search Utilities</entry>
|
||||
|
||||
<entry>Various</entry>
|
||||
|
||||
<entry><ulink
|
||||
url="http://www.springsource.com/repository">http://www.springsource.com/repository</ulink></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Integration with SpringSource Tools</entry>
|
||||
|
||||
<entry>Integration through STS with Maven dependency
|
||||
management</entry>
|
||||
|
||||
<entry>Extensive integration through STS with Maven, Roo,
|
||||
CloudFoundry</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table></para>
|
||||
|
||||
<section>
|
||||
<title>Spring Dependencies and Depending on Spring</title>
|
||||
|
||||
<para>Although Spring provides integration and support for a huge
|
||||
range of enterprise and other external tools, it intentionally keeps
|
||||
its mandatory dependencies to an absolute minimum: you shouldn't have
|
||||
to locate and download (even automatically) a large number of jar
|
||||
libraries in order to use Spring for simple use cases. For basic
|
||||
dependency injection there is only one mandatory external dependency,
|
||||
and that is for logging (see below for a more detailed description of
|
||||
logging options).</para>
|
||||
|
||||
<para>Next we outline the basic steps needed to configure an
|
||||
application that depends on Spring, first with Maven and then with
|
||||
Ivy. In all cases, if anything is unclear, refer to the documentation
|
||||
of your dependency management system, or look at some sample code -
|
||||
Spring itself uses Ivy to manage dependencies when it is building, and
|
||||
our samples mostly use Maven.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Maven Dependency Management</title>
|
||||
|
||||
<para>If you are using Maven for dependency management you don't even
|
||||
need to supply the logging dependency explicitly. For example, to
|
||||
create an application context and use dependency injection to
|
||||
configure an application, your Maven dependencies will look like
|
||||
this:</para>
|
||||
|
||||
<para><programlisting><dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>3.0.0.RELEASE</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
</dependencies> </programlisting></para>
|
||||
|
||||
<para>That's it. Note the scope can be declared as runtime if you
|
||||
don't need to compile against Spring APIs, which is typically the case
|
||||
for basic dependency injection use cases.</para>
|
||||
|
||||
<para>We used the Maven Central naming conventions in the example
|
||||
above, so that works with Maven Central or the SpringSource S3 Maven
|
||||
repository. To use the S3 Maven repository (e.g. for milestones or
|
||||
developer snaphots), you need to specify the repository location in
|
||||
your Maven configuration. For full releases:</para>
|
||||
|
||||
<programlisting><repositories>
|
||||
<repository>
|
||||
<id>com.springsource.repository.maven.release</id>
|
||||
<url>http://maven.springframework.org/release/</url>
|
||||
<snapshots><enabled>false</enabled></snapshots>
|
||||
</repository>
|
||||
</repositories></programlisting>
|
||||
|
||||
<para>For milestones:</para>
|
||||
|
||||
<programlisting><repositories>
|
||||
<repository>
|
||||
<id>com.springsource.repository.maven.milestone</id>
|
||||
<url>http://maven.springframework.org/milestone/</url>
|
||||
<snapshots><enabled>false</enabled></snapshots>
|
||||
</repository>
|
||||
</repositories></programlisting>
|
||||
|
||||
<para>And for snapshots:</para>
|
||||
|
||||
<programlisting><repositories>
|
||||
<repository>
|
||||
<id>com.springsource.repository.maven.snapshot</id>
|
||||
<url>http://maven.springframework.org/snapshot/</url>
|
||||
<snapshots><enabled>true</enabled></snapshots>
|
||||
</repository>
|
||||
</repositories></programlisting>
|
||||
|
||||
<para>To use the SpringSource EBR you would need to use a different
|
||||
naming convention for the dependencies. The names are usually easy to
|
||||
guess, e.g. in this case it is:</para>
|
||||
|
||||
<programlisting><dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>org.springframework.context</artifactId>
|
||||
<version>3.0.0.RELEASE</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
</dependencies></programlisting>
|
||||
|
||||
<para>You also need to declare the location of the repository
|
||||
explicitly (only the URL is important):</para>
|
||||
|
||||
<programlisting><repositories>
|
||||
<repository>
|
||||
<id>com.springsource.repository.bundles.release</id>
|
||||
<url>http://repository.springsource.com/maven/bundles/release/</url>
|
||||
</repository>
|
||||
</repositories></programlisting>
|
||||
|
||||
<para>If you are managing your dependencies by hand, the URL in the
|
||||
repository declaration above is not browseable, but there is a user
|
||||
interface at <ulink
|
||||
url="http://www.springsource.com/repository">http://www.springsource.com/repository</ulink>
|
||||
that can be used to search for and download dependencies. It also has
|
||||
handy snippets of Maven and Ivy configuration that you can copy and
|
||||
paste if you are using those tools.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Ivy Dependency Management</title>
|
||||
|
||||
<para>If you prefer to use <ulink
|
||||
url="http://ant.apache.org/ivy">Ivy</ulink> to manage dependencies
|
||||
then there are similar names and configuration options. </para>
|
||||
|
||||
<para>To configure Ivy to point to the SpringSource EBR add the
|
||||
following resolvers to your
|
||||
<filename>ivysettings.xml</filename>:</para>
|
||||
|
||||
<programlisting><resolvers>
|
||||
|
||||
<url name="com.springsource.repository.bundles.release">
|
||||
|
||||
<ivy pattern="http://repository.springsource.com/ivy/bundles/release/
|
||||
[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" />
|
||||
<artifact pattern="http://repository.springsource.com/ivy/bundles/release/
|
||||
[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" />
|
||||
|
||||
</url>
|
||||
|
||||
<url name="com.springsource.repository.bundles.external">
|
||||
|
||||
<ivy pattern="http://repository.springsource.com/ivy/bundles/external/
|
||||
[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" />
|
||||
<artifact pattern="http://repository.springsource.com/ivy/bundles/external/
|
||||
[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" />
|
||||
|
||||
</url>
|
||||
|
||||
</resolvers></programlisting>
|
||||
|
||||
<para>The XML above is not valid because the lines are too long - if
|
||||
you copy-paste then remove the extra line endings in the middle of the
|
||||
url patterns.</para>
|
||||
|
||||
<para>Once Ivy is configured to look in the EBR adding a dependency is
|
||||
easy. Simply pull up the details page for the bundle in question in
|
||||
the repository browser and you'll find an Ivy snippet ready for you to
|
||||
include in your dependencies section. For example (in
|
||||
<filename>ivy.xml</filename>): </para>
|
||||
|
||||
<programlisting><dependency org="org.springframework"
|
||||
name="org.springframework.core" rev="3.0.0.RELEASE" conf="compile->runtime"/></programlisting>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Logging</title>
|
||||
|
||||
<para>Logging is a very important dependency for Spring because a) it is
|
||||
the only mandatory external dependency, b) everyone likes to see some
|
||||
output from the tools they are using, and c) Spring integrates with lots
|
||||
of other tools all of which have also made a choice of logging
|
||||
dependency. One of the goals of an application developer is often to
|
||||
have unified logging configured in a central place for the whole
|
||||
application, including all external components. This is more difficult
|
||||
than it might have been since there are so many choices of logging
|
||||
framework.</para>
|
||||
|
||||
<para>The mandatory logging dependency in Spring is the Jakarta Commons
|
||||
Logging API (JCL). We compile against JCL and we also make JCL
|
||||
<classname>Log</classname> objects visible for classes that extend the
|
||||
Spring Framework. It's important to users that all versions of Spring
|
||||
use the same logging library: migration is easy because backwards
|
||||
compatibility is preserved even with applications that extend Spring.
|
||||
The way we do this is to make one of the modules in Spring depend
|
||||
explicitly on <code>commons-logging</code> (the canonical implementation
|
||||
of JCL), and then make all the other modules depend on that at compile
|
||||
time. If you are using Maven for example, and wondering where you picked
|
||||
up the dependency on <code>commons-logging</code>, then it is from
|
||||
Spring and specifically from the central module called
|
||||
<code>spring-core</code>.</para>
|
||||
|
||||
<para>The nice thing about <code>commons-logging</code> is that you
|
||||
don't need anything else to make your application work. It has a runtime
|
||||
discovery algorithm that looks for other logging frameworks in well
|
||||
known places on the classpath and uses one that it thinks is appropriate
|
||||
(or you can tell it which one if you need to). If nothing else is
|
||||
available you get pretty nice looking logs just from the JDK
|
||||
(java.util.logging or JUL for short). You should find that your Spring
|
||||
application works and logs happily to the console out of the box in most
|
||||
situations, and that's important.</para>
|
||||
|
||||
<section>
|
||||
<title>Not Using Commons Logging</title>
|
||||
|
||||
<para>Unfortunately, the runtime discovery algorithm in
|
||||
<code>commons-logging</code>, while convenient for the end-user, is
|
||||
problematic. If we could turn back the clock and start Spring now
|
||||
as a new project it would use a different logging dependency. The
|
||||
first choice would probably be the Simple Logging Facade for Java (<ulink
|
||||
url="http://www.slf4j.org">SLF4J</ulink>), which is also used by a lot
|
||||
of other tools that people use with Spring inside their
|
||||
applications.</para>
|
||||
|
||||
<para>Switching off <code>commons-logging</code> is easy: just make
|
||||
sure it isn't on the classpath at runtime. In Maven terms you exclude
|
||||
the dependency, and because of the way that the Spring dependencies
|
||||
are declared, you only have to do that once.</para>
|
||||
|
||||
<programlisting><dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>3.0.0.RELEASE</version>
|
||||
<scope>runtime</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
</dependencies> </programlisting>
|
||||
|
||||
<para>Now this application is probably broken because there is no
|
||||
implementation of the JCL API on the classpath, so to fix it a new one
|
||||
has to be provided. In the next section we show you how to provide an
|
||||
alternative implementation of JCL using SLF4J as an example.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Using SLF4J</title>
|
||||
</section>
|
||||
|
||||
<para>SLF4J is a cleaner dependency and more efficient at runtime than
|
||||
<code>commons-logging</code> because it uses compile-time bindings
|
||||
instead of runtime discovery of the other logging frameworks it
|
||||
integrates. This also means that you have to be more explicit about what
|
||||
you want to happen at runtime, and declare it or configure it
|
||||
accordingly. SLF4J provides bindings to many common logging frameworks,
|
||||
so you can usually choose one that you already use, and bind to that for
|
||||
configuration and management.</para>
|
||||
|
||||
<para>SLF4J provides bindings to many common logging frameworks,
|
||||
including JCL, and it also does the reverse: bridges between other
|
||||
logging frameworks and itself. So to use SLF4J with Spring you need to
|
||||
replace the <code>commons-logging</code> dependency with the SLF4J-JCL
|
||||
bridge. Once you have done that then logging calls from within Spring
|
||||
will be translated into logging calls to the SLF4J API, so if other
|
||||
libraries in your application use that API, then you have a single place
|
||||
to configure and manage logging.</para>
|
||||
|
||||
<para>A common choice might be to bridge Spring to SLF4J, and then
|
||||
provide explicit binding from SLF4J to Log4J. You need to supply 4
|
||||
dependencies (and exclude the existing <code>commons-logging</code>):
|
||||
the bridge, the SLF4J API, the binding to Log4J, and the Log4J
|
||||
implementation itself. In Maven you would do that like this</para>
|
||||
|
||||
<programlisting><dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>3.0.0.RELEASE</version>
|
||||
<scope>runtime</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
<version>1.5.8</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>1.5.8</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
<version>1.5.8</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<version>1.2.14</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
</dependencies> </programlisting>
|
||||
|
||||
<para>That might seem like a lot of dependencies just to get some
|
||||
logging. Well it is, but it <emphasis>is</emphasis> optional, and it
|
||||
should behave better than the vanilla <code>commons-logging</code> with
|
||||
respect to classloader issues, notably if you are in a strict container
|
||||
like an OSGi platform. Allegedly there is also a performance benefit
|
||||
because the bindings are at compile-time not runtime.</para>
|
||||
|
||||
<para>A more common choice amongst SLF4J users, which uses fewer steps
|
||||
and generates fewer dependencies, is to bind directly to <ulink type=""
|
||||
url="http://logback.qos.ch">Logback</ulink>. This removes the extra
|
||||
binding step because Logback implements SLF4J directly, so you only need
|
||||
to depend on two libaries not four (<code>jcl-over-slf4j</code> and
|
||||
<code>logback</code>). If you do that you might also need to exlude the
|
||||
slf4j-api dependency from other external dependencies (not Spring),
|
||||
because you only want one version of that API on the classpath.</para>
|
||||
|
||||
<section>
|
||||
<title>Using Log4J</title>
|
||||
|
||||
<para>Many people use <ulink
|
||||
url="http://logging.apache.org/log4j">Log4j</ulink> as a logging
|
||||
framework for configuration and management purposes. It's efficient
|
||||
and well-established, and in fact it's what we use at runtime when we
|
||||
build and test Spring. Spring also provides some utilities for
|
||||
configuring and initializing Log4j, so it has an optional compile-time
|
||||
dependency on Log4j in some modules.</para>
|
||||
|
||||
<para>To make Log4j work with the default JCL dependency
|
||||
(<code>commons-logging</code>) all you need to do is put Log4j on the
|
||||
classpath, and provide it with a configuration file
|
||||
(<code>log4j.properties</code> or <code>log4j.xml</code> in the root
|
||||
of the classpath). So for Maven users this is your dependency
|
||||
declaration:</para>
|
||||
|
||||
<programlisting><dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>3.0.0.RELEASE</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<version>1.2.14</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
</dependencies> </programlisting>
|
||||
|
||||
<para>And here's a sample log4j.properties for logging to the
|
||||
console:</para>
|
||||
|
||||
<programlisting>log4j.rootCategory=INFO, stdout
|
||||
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %t %c{2}:%L - %m%n
|
||||
|
||||
log4j.category.org.springframework.beans.factory=DEBUG</programlisting>
|
||||
|
||||
<section>
|
||||
<title>Runtime Containers with Native JCL</title>
|
||||
|
||||
<para>Many people run their Spring applications in a container that
|
||||
itself provides an implementation of JCL. IBM Websphere Application
|
||||
Server (WAS) is the archetype. This often causes problems, and
|
||||
unfortunately there is no silver bullet solution; simply excluding
|
||||
<code>commons-logging</code> from your application is not enough in
|
||||
most situations.</para>
|
||||
|
||||
<para>To be clear about this: the problems reported are usually not
|
||||
with JCL per se, or even with <code>commons-logging</code>: rather
|
||||
they are to do with binding <code>commons-logging</code> to another
|
||||
framework (often Log4J). This can fail because
|
||||
<code>commons-logging</code> changed the way they do the runtime
|
||||
discovery in between the older versions (1.0) found in some
|
||||
containers and the modern versions that most people use now (1.1).
|
||||
Spring does not use any unusual parts of the JCL API, so nothing
|
||||
breaks there, but as soon as Spring or your application tries to do
|
||||
any logging you can find that the bindings to Log4J are not
|
||||
working.</para>
|
||||
|
||||
<para>In such cases with WAS the easiest thing to do is to invert
|
||||
the class loader hierarchy (IBM calls it "parent last") so that the
|
||||
application controls the JCL dependency, not the container. That
|
||||
option isn't always open, but there are plenty of other suggestions
|
||||
in the public domain for alternative approaches, and your mileage
|
||||
may vary depending on the exact version and feature set of the
|
||||
container.</para>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
||||
695
src/reference/docbook/oxm.xml
Normal file
@@ -0,0 +1,695 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
|
||||
<chapter id="oxm">
|
||||
<title>Marshalling XML using O/X Mappers</title>
|
||||
|
||||
<section id="oxm-introduction">
|
||||
<title>Introduction</title>
|
||||
<para>
|
||||
In this chapter, we will describe Spring's Object/XML Mapping support. Object/XML Mapping, or O/X mapping
|
||||
for short, is the act of converting an XML document to and from an object. This conversion process is also
|
||||
known as XML Marshalling, or XML Serialization. This chapter uses these terms interchangeably.
|
||||
</para>
|
||||
<para>
|
||||
Within the field of O/X mapping, a <emphasis>marshaller</emphasis> is responsible for serializing an
|
||||
object (graph) to XML. In similar fashion, an <emphasis>unmarshaller</emphasis> deserializes the XML to an
|
||||
object graph. This XML can take the form of a DOM document, an input or output stream, or a SAX handler.
|
||||
</para>
|
||||
<para>Some of the benefits of using Spring for your O/X mapping needs are:</para>
|
||||
<formalpara>
|
||||
<title>Ease of configuration</title>
|
||||
<para>
|
||||
Spring's bean factory makes it easy to configure marshallers, without needing to construct JAXB context,
|
||||
JiBX binding factories, etc. The marshallers can be configured as any other bean in your application
|
||||
context. Additionally, XML Schema-based configuration is available for a number of marshallers, making
|
||||
the configuration even simpler.
|
||||
</para>
|
||||
</formalpara>
|
||||
<formalpara>
|
||||
<title>Consistent Interfaces</title>
|
||||
<para>
|
||||
Spring's O/X mapping operates through two global interfaces: the
|
||||
<interfacename>Marshaller</interfacename> and <interfacename>Unmarshaller</interfacename> interface.
|
||||
These abstractions allow you to switch O/X mapping
|
||||
frameworks with relative ease, with little or no changes required on the classes that do the
|
||||
marshalling. This approach has the additional benefit of making it possible to do XML marshalling with
|
||||
a mix-and-match approach (e.g. some marshalling performed using JAXB, other using XMLBeans) in a
|
||||
non-intrusive fashion, leveraging the strength of each technology.
|
||||
</para>
|
||||
</formalpara>
|
||||
<formalpara>
|
||||
<title>Consistent Exception Hierarchy</title>
|
||||
<para>
|
||||
Spring provides a conversion from exceptions from the underlying O/X mapping tool to its own exception
|
||||
hierarchy with the <classname>XmlMappingException</classname> as the root exception. As can be expected,
|
||||
these runtime exceptions wrap the original exception so no information is lost.
|
||||
</para>
|
||||
</formalpara>
|
||||
</section>
|
||||
<section id="oxm-marshaller-unmarshaller">
|
||||
<title>Marshaller and Unmarshaller</title>
|
||||
<para>
|
||||
As stated in the introduction, a <emphasis>marshaller</emphasis> serializes an object to XML, and an
|
||||
<emphasis>unmarshaller</emphasis> deserializes XML stream to an object. In this section, we will describe
|
||||
the two Spring interfaces used for this purpose.
|
||||
</para>
|
||||
<section>
|
||||
<title>Marshaller</title>
|
||||
<para>
|
||||
Spring abstracts all marshalling operations behind the
|
||||
<interfacename>org.springframework.oxm.Marshaller</interfacename> interface, the main methods of which
|
||||
is listed below.
|
||||
<programlisting language="java"><![CDATA[
|
||||
public interface Marshaller {
|
||||
|
||||
/**
|
||||
* Marshals the object graph with the given root into the provided Result.
|
||||
*/
|
||||
void marshal(Object graph, Result result)
|
||||
throws XmlMappingException, IOException;
|
||||
}]]></programlisting>
|
||||
The <interfacename>Marshaller</interfacename> interface has one main method, which marshals the given
|
||||
object to a given <interfacename>javax.xml.transform.Result</interfacename>. Result is a tagging
|
||||
interface that basically represents an XML output abstraction: concrete implementations wrap various XML
|
||||
representations, as indicated in the table below.
|
||||
<informaltable>
|
||||
<tgroup cols="2">
|
||||
<thead>
|
||||
<row>
|
||||
<entry><interfacename>Result</interfacename> implementation</entry>
|
||||
<entry>Wraps XML representation</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><classname>DOMResult</classname></entry>
|
||||
<entry><interfacename>org.w3c.dom.Node</interfacename></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><classname>SAXResult</classname></entry>
|
||||
<entry><interfacename>org.xml.sax.ContentHandler</interfacename></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><interfacename>StreamResult</interfacename></entry>
|
||||
<entry>
|
||||
<classname>java.io.File</classname>,
|
||||
<classname>java.io.OutputStream</classname>, or
|
||||
<classname>java.io.Writer</classname>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
<note>
|
||||
<para>
|
||||
Although the <methodname>marshal()</methodname> method accepts a plain object as its first
|
||||
parameter, most <classname>Marshaller</classname> implementations cannot handle arbitrary
|
||||
objects. Instead, an object class must be mapped in a mapping file, marked with an annotation,
|
||||
registered with the marshaller, or have a common base class. Refer to the further sections
|
||||
in this chapter to determine how your O/X technology of choice manages this.
|
||||
</para>
|
||||
</note>
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Unmarshaller</title>
|
||||
<para>
|
||||
Similar to the <interfacename>Marshaller</interfacename>, there is the
|
||||
<interfacename>org.springframework.oxm.Unmarshaller</interfacename> interface.
|
||||
<programlisting language="java"><![CDATA[
|
||||
public interface Unmarshaller {
|
||||
|
||||
/**
|
||||
* Unmarshals the given provided Source into an object graph.
|
||||
*/
|
||||
Object unmarshal(Source source)
|
||||
throws XmlMappingException, IOException;
|
||||
}]]></programlisting>
|
||||
This interface also has one method, which reads from the given
|
||||
<interfacename>javax.xml.transform.Source</interfacename> (an XML input abstraction), and returns the
|
||||
object read. As with Result, Source is a tagging interface that has three concrete implementations. Each
|
||||
wraps a different XML representation, as indicated in the table below.
|
||||
<informaltable>
|
||||
<tgroup cols="2">
|
||||
<thead>
|
||||
<row>
|
||||
<entry><interfacename>Source</interfacename> implementation</entry>
|
||||
<entry>Wraps XML representation</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><classname>DOMSource</classname></entry>
|
||||
<entry><interfacename>org.w3c.dom.Node</interfacename></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><classname>SAXSource</classname></entry>
|
||||
<entry>
|
||||
<classname>org.xml.sax.InputSource</classname>, and
|
||||
<interfacename>org.xml.sax.XMLReader</interfacename>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><classname>StreamSource</classname></entry>
|
||||
<entry>
|
||||
<classname>java.io.File</classname>,
|
||||
<classname>java.io.InputStream</classname>, or
|
||||
<classname>java.io.Reader</classname>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
</para>
|
||||
</section>
|
||||
<para>
|
||||
Even though there are two separate marshalling interfaces (<interfacename>Marshaller</interfacename>
|
||||
and <interfacename>Unmarshaller</interfacename>), all implementations found in Spring-WS implement both in
|
||||
one class. This means that you can wire up one marshaller class and refer to it both as a marshaller and an
|
||||
unmarshaller in your <filename>applicationContext.xml</filename>.
|
||||
</para>
|
||||
<section>
|
||||
<title>XmlMappingException</title>
|
||||
<para>
|
||||
Spring converts exceptions from the underlying O/X mapping tool to its own exception hierarchy with the
|
||||
<classname>XmlMappingException</classname> as the root exception. As can be expected, these runtime
|
||||
exceptions wrap the original exception so no information will be lost.
|
||||
</para>
|
||||
<para>
|
||||
Additionally, the <classname>MarshallingFailureException</classname> and
|
||||
<classname>UnmarshallingFailureException</classname> provide a distinction between marshalling and
|
||||
unmarshalling operations, even though the underlying O/X mapping tool does not do so.
|
||||
</para>
|
||||
<para>
|
||||
The O/X Mapping exception hierarchy is shown in the following figure:
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata fileref="images/oxm-exceptions.png" align="center"/>
|
||||
</imageobject>
|
||||
<caption>
|
||||
<para>
|
||||
O/X Mapping exception hierarchy
|
||||
</para>
|
||||
</caption>
|
||||
</mediaobject>
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
<section id="oxm-usage">
|
||||
<title>Using Marshaller and Unmarshaller</title>
|
||||
<para>
|
||||
Spring's OXM can be used for a wide variety of situations. In the following example, we will use it to
|
||||
marshal the settings of a Spring-managed application as an XML file. We will use a simple JavaBean to
|
||||
represent the settings:
|
||||
<programlisting language="java"><![CDATA[
|
||||
public class Settings {
|
||||
private boolean fooEnabled;
|
||||
|
||||
public boolean isFooEnabled() {
|
||||
return fooEnabled;
|
||||
}
|
||||
|
||||
public void setFooEnabled(boolean fooEnabled) {
|
||||
this.fooEnabled = fooEnabled;
|
||||
}
|
||||
}]]></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
The application class uses this bean to store its settings. Besides a main method, the class has two
|
||||
methods: <methodname>saveSettings()</methodname> saves the settings bean to a file named
|
||||
<filename>settings.xml</filename>, and <methodname>loadSettings()</methodname> loads these settings again. A
|
||||
<methodname>main()</methodname> method constructs a Spring application context, and calls these two methods.
|
||||
<programlisting language="java"><![CDATA[
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.oxm.Marshaller;
|
||||
import org.springframework.oxm.Unmarshaller;
|
||||
|
||||
public class Application {
|
||||
private static final String FILE_NAME = "settings.xml";
|
||||
private Settings settings = new Settings();
|
||||
private Marshaller marshaller;
|
||||
private Unmarshaller unmarshaller;
|
||||
|
||||
public void setMarshaller(Marshaller marshaller) {
|
||||
this.marshaller = marshaller;
|
||||
}
|
||||
|
||||
public void setUnmarshaller(Unmarshaller unmarshaller) {
|
||||
this.unmarshaller = unmarshaller;
|
||||
}
|
||||
|
||||
public void saveSettings() throws IOException {
|
||||
FileOutputStream os = null;
|
||||
try {
|
||||
os = new FileOutputStream(FILE_NAME);
|
||||
this.marshaller.marshal(settings, new StreamResult(os));
|
||||
} finally {
|
||||
if (os != null) {
|
||||
os.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void loadSettings() throws IOException {
|
||||
FileInputStream is = null;
|
||||
try {
|
||||
is = new FileInputStream(FILE_NAME);
|
||||
this.settings = (Settings) this.unmarshaller.unmarshal(new StreamSource(is));
|
||||
} finally {
|
||||
if (is != null) {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
ApplicationContext appContext =
|
||||
new ClassPathXmlApplicationContext("applicationContext.xml");
|
||||
Application application = (Application) appContext.getBean("application");
|
||||
application.saveSettings();
|
||||
application.loadSettings();
|
||||
}
|
||||
}]]></programlisting>
|
||||
The <classname>Application</classname> requires both a <property>marshaller</property>
|
||||
and <property>unmarshaller</property> property to be set. We can do so using the following
|
||||
<filename>applicationContext.xml</filename>:
|
||||
<programlisting language="xml"><![CDATA[
|
||||
<beans>
|
||||
<bean id="application" class="Application">
|
||||
<property name="marshaller" ref="castorMarshaller" />
|
||||
<property name="unmarshaller" ref="castorMarshaller" />
|
||||
</bean>
|
||||
<bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller"/>
|
||||
</beans>
|
||||
]]></programlisting>
|
||||
This application context uses Castor, but we could have used any of the other marshaller instances described
|
||||
later in this chapter. Note that Castor does not require any further configuration by default, so the bean
|
||||
definition is rather simple. Also note that the <classname>CastorMarshaller</classname> implements both
|
||||
<interfacename>Marshaller</interfacename> and <interfacename>Unmarshaller</interfacename>, so we can refer
|
||||
to the <varname>castorMarshaller</varname> bean in both the <property>marshaller</property> and
|
||||
<property>unmarshaller</property> property of the application.
|
||||
</para>
|
||||
<para>
|
||||
This sample application produces the following <filename>settings.xml</filename> file:
|
||||
<programlisting language="xml"><![CDATA[
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<settings foo-enabled="false"/>
|
||||
]]></programlisting>
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>XML Schema-based Configuration</title>
|
||||
<para>
|
||||
Marshallers could be configured more concisely using tags from the OXM namespace.
|
||||
To make these tags available, the appropriate schema has to be referenced first in the preamble of the XML configuration file.
|
||||
Note the 'oxm' related text below:
|
||||
</para>
|
||||
<programlisting language="xml"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
]]><emphasis role="bold"><![CDATA[xmlns:oxm="http://www.springframework.org/schema/oxm"]]></emphasis>
|
||||
<![CDATA[xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
]]><![CDATA[http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
]]><emphasis role="bold"><![CDATA[http://www.springframework.org/schema/oxm
|
||||
]]><![CDATA[http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd"]]></emphasis><![CDATA[>
|
||||
]]></programlisting>
|
||||
<para>
|
||||
Currently, the following tags are available:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><link linkend="oxm-jaxb2-xsd"><literal>jaxb2-marshaller</literal></link></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><link linkend="oxm-xmlbeans-xsd"><literal>xmlbeans-marshaller</literal></link></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><link linkend="oxm-jibx-xsd"><literal>jibx-marshaller</literal></link></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<para>
|
||||
Each tag will be explained in its respective marshaller's section. As an example though, here is how
|
||||
the configuration of a JAXB2 marshaller might look like:
|
||||
</para>
|
||||
<programlisting language="xml"><![CDATA[<oxm:jaxb2-marshaller id="marshaller" contextPath="org.springframework.ws.samples.airline.schema"/>]]></programlisting>
|
||||
</section>
|
||||
<section id="oxm-jaxb">
|
||||
<title>JAXB</title>
|
||||
<para>
|
||||
The JAXB binding compiler translates a W3C XML Schema into one or more Java classes, a
|
||||
<filename>jaxb.properties</filename> file, and possibly some resource files. JAXB also offers a
|
||||
way to generate a schema from annotated Java classes.
|
||||
</para>
|
||||
<para>
|
||||
Spring supports the JAXB 2.0 API as XML marshalling strategies, following the
|
||||
<interfacename>Marshaller</interfacename> and <interfacename>Unmarshaller</interfacename>
|
||||
interfaces described in <xref linkend="oxm-marshaller-unmarshaller"/>. The corresponding integration
|
||||
classes reside in the <package>org.springframework.oxm.jaxb</package> package.
|
||||
</para>
|
||||
<section id="oxm-jaxb2">
|
||||
<title>Jaxb2Marshaller</title>
|
||||
<para>
|
||||
The <classname>Jaxb2Marshaller</classname> class implements both the Spring
|
||||
<interfacename>Marshaller</interfacename> and <interfacename>Unmarshaller</interfacename>interface. It
|
||||
requires a context path to operate, which you can set using the <property>contextPath</property>
|
||||
property. The context path is a list of colon (:) separated Java package names that contain schema
|
||||
derived classes. It also offers a <property>classesToBeBound</property> property, which allows you to set an array of
|
||||
classes to be supported by the marshaller. Schema validation is performed by specifying one or more
|
||||
schema resource to the bean, like so:
|
||||
</para>
|
||||
<programlisting language="xml"><![CDATA[
|
||||
<beans>
|
||||
|
||||
<bean id="jaxb2Marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
|
||||
<property name="classesToBeBound">
|
||||
<list>
|
||||
<value>org.springframework.oxm.jaxb.Flight</value>
|
||||
<value>org.springframework.oxm.jaxb.Flights</value>
|
||||
</list>
|
||||
</property>
|
||||
<property name="schema" value="classpath:org/springframework/oxm/schema.xsd"/>
|
||||
</bean>
|
||||
...
|
||||
|
||||
</beans>]]></programlisting>
|
||||
<section id="oxm-jaxb2-xsd">
|
||||
<title>XML Schema-based Configuration</title>
|
||||
<para>
|
||||
The <literal>jaxb2-marshaller</literal> tag configures a <classname>org.springframework.oxm.jaxb.Jaxb2Marshaller</classname>.
|
||||
Here is an example:
|
||||
</para>
|
||||
<programlisting language="xml"><![CDATA[<oxm:jaxb2-marshaller id="marshaller" contextPath="org.springframework.ws.samples.airline.schema"/>]]></programlisting>
|
||||
<para>
|
||||
Alternatively, the list of classes to bind can be provided to the marshaller via the <literal>class-to-be-bound</literal> child tag:
|
||||
</para>
|
||||
<programlisting language="xml"><![CDATA[<oxm:jaxb2-marshaller id="marshaller">
|
||||
<oxm:class-to-be-bound name="org.springframework.ws.samples.airline.schema.Airport"/>
|
||||
<oxm:class-to-be-bound name="org.springframework.ws.samples.airline.schema.Flight"/>
|
||||
...
|
||||
</oxm:jaxb2-marshaller>
|
||||
]]></programlisting>
|
||||
<para>
|
||||
Available attributes are:
|
||||
<informaltable>
|
||||
<tgroup cols="3">
|
||||
<colspec colwidth="1.5*"/>
|
||||
<colspec colwidth="4*"/>
|
||||
<colspec colwidth="1*"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Attribute</entry>
|
||||
<entry>Description</entry>
|
||||
<entry>Required</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><literal>id</literal></entry>
|
||||
<entry>the id of the marshaller</entry>
|
||||
<entry>no</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>contextPath</literal></entry>
|
||||
<entry>the JAXB Context path</entry>
|
||||
<entry>no</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
<section id="oxm-castor">
|
||||
<title>Castor</title>
|
||||
<para>
|
||||
Castor XML mapping is an open source XML binding framework. It allows you to transform the data contained in
|
||||
a java object model into/from an XML document. By default, it does not require any further configuration,
|
||||
though a mapping file can be used to have more control over the behavior of Castor.
|
||||
</para>
|
||||
<para>
|
||||
For more information on Castor, refer to the <ulink url="http://castor.org/xml-framework.html">
|
||||
<citetitle>Castor web site</citetitle></ulink>. The Spring integration classes reside in the
|
||||
<package>org.springframework.oxm.castor</package> package.
|
||||
</para>
|
||||
<section>
|
||||
<title>CastorMarshaller</title>
|
||||
<para>
|
||||
As with JAXB, the <classname>CastorMarshaller</classname> implements both the
|
||||
<interfacename>Marshaller</interfacename> and <interfacename>Unmarshaller</interfacename> interface.
|
||||
It can be wired up as follows:
|
||||
</para>
|
||||
<programlisting language="xml"><![CDATA[
|
||||
<beans>
|
||||
|
||||
<bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller" />
|
||||
...
|
||||
|
||||
</beans>]]></programlisting>
|
||||
</section>
|
||||
<section>
|
||||
<title>Mapping</title>
|
||||
<para>
|
||||
Although it is possible to rely on Castor's default marshalling behavior, it might be necessary to have
|
||||
more control over it. This can be accomplished using a Castor mapping file. For more information, refer
|
||||
to <ulink url="http://castor.org/xml-mapping.html">Castor XML Mapping</ulink>.
|
||||
</para>
|
||||
<para>
|
||||
The mapping can be set using the <property>mappingLocation</property> resource property, indicated
|
||||
below with a classpath resource.
|
||||
</para>
|
||||
<programlisting language="xml"><![CDATA[
|
||||
<beans>
|
||||
<bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller" >
|
||||
<property name="mappingLocation" value="classpath:mapping.xml" />
|
||||
</bean>
|
||||
</beans>
|
||||
]]></programlisting>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="oxm-xmlbeans">
|
||||
<title>XMLBeans</title>
|
||||
<para>
|
||||
XMLBeans is an XML binding tool that has full XML Schema support, and offers full XML Infoset
|
||||
fidelity. It takes a different approach to that of most other O/X mapping frameworks, in that
|
||||
all classes that are generated from an XML Schema are all derived from
|
||||
<interfacename>XmlObject</interfacename>, and contain XML binding information in them.
|
||||
</para>
|
||||
<para>
|
||||
For more information on XMLBeans, refer to the <ulink url="http://xmlbeans.apache.org/">
|
||||
<citetitle>XMLBeans web site </citetitle></ulink>. The Spring-WS integration classes reside
|
||||
in the <package>org.springframework.oxm.xmlbeans</package> package.
|
||||
</para>
|
||||
<section>
|
||||
<title>XmlBeansMarshaller</title>
|
||||
<para>
|
||||
The <classname>XmlBeansMarshaller</classname>
|
||||
implements both the <interfacename>Marshaller</interfacename>
|
||||
and <interfacename>Unmarshaller</interfacename>
|
||||
interfaces. It can be configured as follows:
|
||||
</para>
|
||||
<programlisting language="xml"><![CDATA[
|
||||
<beans>
|
||||
|
||||
<bean id="xmlBeansMarshaller" class="org.springframework.oxm.xmlbeans.XmlBeansMarshaller" />
|
||||
...
|
||||
|
||||
</beans>]]></programlisting>
|
||||
<note>
|
||||
<para>
|
||||
Note that the <classname>XmlBeansMarshaller</classname>
|
||||
can only marshal objects of type <interfacename>XmlObject</interfacename>,
|
||||
and not every <classname>java.lang.Object</classname>.
|
||||
</para>
|
||||
</note>
|
||||
<section id="oxm-xmlbeans-xsd">
|
||||
<title>XML Schema-based Configuration</title>
|
||||
<para>
|
||||
The <literal>xmlbeans-marshaller</literal> tag configures a <classname>org.springframework.oxm.xmlbeans.XmlBeansMarshaller</classname>.
|
||||
Here is an example:
|
||||
</para>
|
||||
<programlisting language="xml"><![CDATA[<oxm:xmlbeans-marshaller id="marshaller"/>]]></programlisting>
|
||||
<para>
|
||||
Available attributes are:
|
||||
<informaltable>
|
||||
<tgroup cols="3">
|
||||
<colspec colwidth="1.5*"/>
|
||||
<colspec colwidth="4*"/>
|
||||
<colspec colwidth="1*"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Attribute</entry>
|
||||
<entry>Description</entry>
|
||||
<entry>Required</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><literal>id</literal></entry>
|
||||
<entry>the id of the marshaller</entry>
|
||||
<entry>no</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>options</literal></entry>
|
||||
<entry>the bean name of the XmlOptions that is to be used for this marshaller. Typically a
|
||||
<classname>XmlOptionsFactoryBean</classname> definition</entry>
|
||||
<entry>no</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
<section id="oxm-jibx">
|
||||
<title>JiBX</title>
|
||||
<para>
|
||||
The JiBX framework offers a solution similar to that which JDO provides for ORM: a binding definition defines the
|
||||
rules for how your Java objects are converted to or from XML. After preparing the binding and compiling the
|
||||
classes, a JiBX binding compiler enhances the class files, and adds code to handle converting instances of
|
||||
the classes from or to XML.
|
||||
</para>
|
||||
<para>
|
||||
For more information on JiBX, refer to the <ulink url="http://jibx.sourceforge.net/">
|
||||
<citetitle>JiBX web site</citetitle></ulink>. The Spring integration classes reside in the
|
||||
<package>org.springframework.oxm.jibx</package> package.
|
||||
</para>
|
||||
<section>
|
||||
<title>JibxMarshaller</title>
|
||||
<para>
|
||||
The <classname>JibxMarshaller</classname> class implements both the
|
||||
<interfacename>Marshaller</interfacename> and <interfacename>Unmarshaller</interfacename> interface.
|
||||
To operate, it requires the name of the class to marshal in, which you can set using the
|
||||
<property>targetClass</property> property. Optionally, you can set the binding name using the
|
||||
<property>bindingName</property> property. In the next sample, we bind the
|
||||
<classname>Flights</classname> class:
|
||||
</para>
|
||||
<programlisting language="xml"><![CDATA[
|
||||
<beans>
|
||||
|
||||
<bean id="jibxFlightsMarshaller" class="org.springframework.oxm.jibx.JibxMarshaller">
|
||||
<property name="targetClass">org.springframework.oxm.jibx.Flights</property>
|
||||
</bean>
|
||||
|
||||
...
|
||||
]]></programlisting>
|
||||
<para>
|
||||
A <classname>JibxMarshaller</classname> is configured for a single class. If you want to marshal
|
||||
multiple classes, you have to configure multiple <classname>JibxMarshaller</classname>s with
|
||||
different <property>targetClass</property> property values.
|
||||
</para>
|
||||
<section id="oxm-jibx-xsd">
|
||||
<title>XML Schema-based Configuration</title>
|
||||
<para>
|
||||
The <literal>jibx-marshaller</literal> tag configures a <classname>org.springframework.oxm.jibx.JibxMarshaller</classname>.
|
||||
Here is an example:
|
||||
</para>
|
||||
<programlisting language="xml"><![CDATA[<oxm:jibx-marshaller id="marshaller" target-class="org.springframework.ws.samples.airline.schema.Flight"/>]]></programlisting>
|
||||
<para>
|
||||
Available attributes are:
|
||||
<informaltable>
|
||||
<tgroup cols="3">
|
||||
<colspec colwidth="1.5*"/>
|
||||
<colspec colwidth="4*"/>
|
||||
<colspec colwidth="1*"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Attribute</entry>
|
||||
<entry>Description</entry>
|
||||
<entry>Required</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><literal>id</literal></entry>
|
||||
<entry>the id of the marshaller</entry>
|
||||
<entry>no</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>target-class</literal></entry>
|
||||
<entry>the target class for this marshaller</entry>
|
||||
<entry>yes</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>bindingName</literal></entry>
|
||||
<entry>the binding name used by this marshaller</entry>
|
||||
<entry>no</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
<section id="oxm-xstream">
|
||||
<title>XStream</title>
|
||||
<para>
|
||||
XStream is a simple library to serialize objects to XML and back again. It does not require any mapping, and
|
||||
generates clean XML.
|
||||
</para>
|
||||
<para>
|
||||
For more information on XStream, refer to the <ulink url="http://xstream.codehaus.org/">
|
||||
<citetitle>XStream web site</citetitle></ulink>. The Spring integration classes reside in the
|
||||
<package>org.springframework.oxm.xstream</package> package.
|
||||
</para>
|
||||
<section>
|
||||
<title>XStreamMarshaller</title>
|
||||
<para>
|
||||
The <classname>XStreamMarshaller</classname> does not require any configuration, and can be configured
|
||||
in an application context directly. To further customize the XML, you can set an
|
||||
<emphasis>alias map</emphasis>, which consists of string aliases mapped to classes:
|
||||
</para>
|
||||
<programlisting language="xml"><![CDATA[
|
||||
<beans>
|
||||
|
||||
<bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
|
||||
<property name="aliases">
|
||||
<props>
|
||||
<prop key="Flight">org.springframework.oxm.xstream.Flight</prop>
|
||||
</props>
|
||||
</property>
|
||||
</bean>
|
||||
...
|
||||
|
||||
</beans>]]></programlisting>
|
||||
<warning>
|
||||
<para>
|
||||
By default, XStream allows for arbitrary classes to be unmarshalled, which can result in security
|
||||
vulnerabilities.
|
||||
As such, it is recommended to set the <property>supportedClasses</property> property on the
|
||||
<classname>XStreamMarshaller</classname>, like so:
|
||||
<programlisting language="xml"><![CDATA[<bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
|
||||
<property name="supportedClasses" value="org.springframework.oxm.xstream.Flight"/>
|
||||
...
|
||||
</bean>]]></programlisting>
|
||||
This will make sure that only the registered classes are eligible for unmarshalling.
|
||||
</para>
|
||||
<para>
|
||||
Additionally, you can register <ulink url="http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/oxm/xstream/XStreamMarshaller.html#setConverters(com.thoughtworks.xstream.converters.ConverterMatcher[])">
|
||||
custom converters</ulink> to make sure that only your supported classes can be unmarshalled.
|
||||
</para>
|
||||
</warning>
|
||||
<note>
|
||||
<para>
|
||||
Note that XStream is an XML serialization library, not a data binding library. Therefore, it has
|
||||
limited namespace support. As such, it is rather unsuitable for usage within Web services.
|
||||
</para>
|
||||
</note>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
||||
1816
src/reference/docbook/portlet.xml
Normal file
39
src/reference/docbook/preface.xml
Normal file
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
|
||||
<preface id="preface">
|
||||
<title>Preface</title>
|
||||
|
||||
<para>Developing software applications is hard enough even with good tools
|
||||
and technologies. Implementing applications using platforms which promise
|
||||
everything but turn out to be heavy-weight, hard to control and not very
|
||||
efficient during the development cycle makes it even harder. Spring provides
|
||||
a light-weight solution for building enterprise-ready applications, while
|
||||
still supporting the possibility of using declarative transaction
|
||||
management, remote access to your logic using RMI or web services, and
|
||||
various options for persisting your data to a database. Spring provides a
|
||||
full-featured <link linkend="mvc-introduction">MVC framework</link>, and
|
||||
transparent ways of integrating <link linkend="aop-introduction">AOP</link>
|
||||
into your software.</para>
|
||||
|
||||
<para>Spring could potentially be a one-stop-shop for all your enterprise
|
||||
applications; however, Spring is modular, allowing you to use just those
|
||||
parts of it that you need, without having to bring in the rest. You can use
|
||||
the IoC container, with Struts on top, but you could also choose to use just
|
||||
the <link linkend="orm-hibernate">Hibernate integration code</link> or the
|
||||
<link linkend="jdbc-introduction">JDBC abstraction layer</link></para>
|
||||
|
||||
<para>Spring has been (and continues to be) designed to be non-intrusive,
|
||||
meaning dependencies, from your domain logic code, on the framework itself
|
||||
are generally none. For your integration layer like the data access layer
|
||||
there will of course be some dependencies on the data access technology in
|
||||
use and also on the Spring libraries, but these dependencies should be easy
|
||||
to isolate from the rest of your code base.</para>
|
||||
|
||||
<para>This document provides a reference guide to Spring's features. Since
|
||||
this document is still to be considered very much work-in-progress, if you
|
||||
have any requests or comments, please post them on the user mailing list or
|
||||
on the support forums at <ulink url="http://forum.springsource.org/" />.
|
||||
</para>
|
||||
</preface>
|
||||
1647
src/reference/docbook/remoting.xml
Normal file
742
src/reference/docbook/resources.xml
Normal file
@@ -0,0 +1,742 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
|
||||
<chapter id="resources">
|
||||
<title>Resources</title>
|
||||
|
||||
<section id="resources-introduction">
|
||||
<title>Introduction</title>
|
||||
|
||||
<para>Java's standard <classname>java.net.URL</classname> class and
|
||||
standard handlers for various URL prefixes unfortunately are not quite
|
||||
adequate enough for all access to low-level resources. For example,
|
||||
there is no standardized <classname>URL</classname> implementation
|
||||
that may be used to access a resource that needs to be obtained from
|
||||
the classpath, or relative to a
|
||||
<interfacename>ServletContext</interfacename>. While it is possible
|
||||
to register new handlers for specialized <classname>URL</classname>
|
||||
prefixes (similar to existing handlers for prefixes such as
|
||||
<literal>http:</literal>), this is generally quite complicated, and the
|
||||
<classname>URL</classname> interface still lacks some desirable
|
||||
functionality, such as a method to check for the existence of the
|
||||
resource being pointed to.</para>
|
||||
</section>
|
||||
|
||||
<section id="resources-resource">
|
||||
<title>The <interfacename>Resource</interfacename> interface</title>
|
||||
|
||||
<para>Spring's <interfacename>Resource</interfacename> interface is meant
|
||||
to be a more capable interface for abstracting access to low-level
|
||||
resources.</para>
|
||||
|
||||
<programlisting language="java"><![CDATA[public interface Resource extends InputStreamSource {
|
||||
|
||||
boolean exists();
|
||||
|
||||
boolean isOpen();
|
||||
|
||||
URL getURL() throws IOException;
|
||||
|
||||
File getFile() throws IOException;
|
||||
|
||||
Resource createRelative(String relativePath) throws IOException;
|
||||
|
||||
String getFilename();
|
||||
|
||||
String getDescription();
|
||||
}]]></programlisting>
|
||||
|
||||
<programlisting language="java"><![CDATA[public interface InputStreamSource {
|
||||
|
||||
InputStream getInputStream() throws IOException;
|
||||
}]]></programlisting>
|
||||
|
||||
<para>Some of the most important methods from the
|
||||
<interfacename>Resource</interfacename> interface are:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><methodname>getInputStream()</methodname>: locates and opens the
|
||||
resource, returning an <classname>InputStream</classname> for reading
|
||||
from the resource. It is expected that each invocation returns a
|
||||
fresh <classname>InputStream</classname>. It is the responsibility of
|
||||
the caller to close the stream.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><methodname>exists()</methodname>: returns a
|
||||
<literal>boolean</literal> indicating whether this resource actually
|
||||
exists in physical form.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><methodname>isOpen()</methodname>: returns a
|
||||
<literal>boolean</literal> indicating whether this resource represents
|
||||
a handle with an open stream. If <literal>true</literal>, the
|
||||
<classname>InputStream</classname> cannot be read multiple times, and
|
||||
must be read once only and then closed to avoid resource leaks. Will
|
||||
be <literal>false</literal> for all usual resource implementations,
|
||||
with the exception of
|
||||
<classname>InputStreamResource</classname>.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><methodname>getDescription()</methodname>: returns a description
|
||||
for this resource, to be used for error output when working with the
|
||||
resource. This is often the fully qualified file name or the actual
|
||||
URL of the resource.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>Other methods allow you to obtain an actual
|
||||
<classname>URL</classname> or <classname>File</classname> object
|
||||
representing the resource (if the underlying implementation is compatible,
|
||||
and supports that functionality).</para>
|
||||
|
||||
<para>The <interfacename>Resource</interfacename> abstraction is used
|
||||
extensively in Spring itself, as an argument type in many method
|
||||
signatures when a resource is needed. Other methods in some Spring APIs
|
||||
(such as the constructors to various
|
||||
<interfacename>ApplicationContext</interfacename> implementations), take a
|
||||
<classname>String</classname> which in unadorned or simple form is used to
|
||||
create a <interfacename>Resource</interfacename> appropriate to that
|
||||
context implementation, or via special prefixes on the
|
||||
<classname>String</classname> path, allow the caller to specify that a
|
||||
specific <interfacename>Resource</interfacename> implementation must be
|
||||
created and used.</para>
|
||||
|
||||
<para>While the <interfacename>Resource</interfacename> interface is used
|
||||
a lot with Spring and by Spring, it's actually very useful to use as a
|
||||
general utility class by itself in your own code, for access to resources,
|
||||
even when your code doesn't know or care about any other parts of Spring.
|
||||
While this couples your code to Spring, it really only couples it to this
|
||||
small set of utility classes, which are serving as a more capable
|
||||
replacement for <classname>URL</classname>, and can be considered
|
||||
equivalent to any other library you would use for this purpose.</para>
|
||||
|
||||
<para>It is important to note that the
|
||||
<interfacename>Resource</interfacename> abstraction does not replace
|
||||
functionality: it wraps it where possible. For example, a
|
||||
<classname>UrlResource</classname> wraps a URL, and uses the wrapped
|
||||
<classname>URL</classname> to do its work.</para>
|
||||
</section>
|
||||
|
||||
<section id="resources-implementations">
|
||||
<title>Built-in <interfacename>Resource</interfacename> implementations</title>
|
||||
|
||||
<para>There are a number of <interfacename>Resource</interfacename>
|
||||
implementations that come supplied straight out of the box in
|
||||
Spring:</para>
|
||||
|
||||
<section id="resources-implementations-urlresource">
|
||||
<title><classname>UrlResource</classname></title>
|
||||
|
||||
<para>The <classname>UrlResource</classname> wraps a
|
||||
<classname>java.net.URL</classname>, and may be used to access any
|
||||
object that is normally accessible via a URL, such as files, an HTTP
|
||||
target, an FTP target, etc. All URLs have a standardized
|
||||
<classname>String</classname> representation, such that appropriate
|
||||
standardized prefixes are used to indicate one URL type from another.
|
||||
This includes <literal>file:</literal> for accessing filesystem paths,
|
||||
<literal>http:</literal> for accessing resources via the HTTP protocol,
|
||||
<literal>ftp:</literal> for accessing resources via FTP, etc.</para>
|
||||
|
||||
<para>A <classname>UrlResource</classname> is created by Java code
|
||||
explicitly using the <classname>UrlResource</classname> constructor, but
|
||||
will often be created implicitly when you call an API method which takes
|
||||
a <classname>String</classname> argument which is meant to represent a
|
||||
path. For the latter case, a JavaBeans
|
||||
<interfacename>PropertyEditor</interfacename> will ultimately decide
|
||||
which type of <interfacename>Resource</interfacename> to create. If the
|
||||
path string contains a few well-known (to it, that is) prefixes such as
|
||||
<literal>classpath:</literal>, it will create an appropriate specialized
|
||||
<interfacename>Resource</interfacename> for that prefix. However, if it
|
||||
doesn't recognize the prefix, it will assume the this is just a standard
|
||||
URL string, and will create a <classname>UrlResource</classname>.</para>
|
||||
</section>
|
||||
|
||||
<section id="resources-implementations-classpathresource">
|
||||
<title><classname>ClassPathResource</classname></title>
|
||||
|
||||
<para>This class represents a resource which should be obtained from the
|
||||
classpath. This uses either the thread context class loader, a given
|
||||
class loader, or a given class for loading resources.</para>
|
||||
|
||||
<para>This <interfacename>Resource</interfacename> implementation
|
||||
supports resolution as <classname>java.io.File</classname> if the class
|
||||
path resource resides in the file system, but not for classpath
|
||||
resources which reside in a jar and have not been expanded (by the
|
||||
servlet engine, or whatever the environment is) to the filesystem. To
|
||||
address this the various <interfacename>Resource</interfacename>
|
||||
implementations always support resolution as a
|
||||
<classname>java.net.URL</classname>.</para>
|
||||
|
||||
<para>A <classname>ClassPathResource</classname> is created by Java code
|
||||
explicitly using the <classname>ClassPathResource</classname>
|
||||
constructor, but will often be created implicitly when you call an API
|
||||
method which takes a <classname>String</classname> argument which is
|
||||
meant to represent a path. For the latter case, a JavaBeans
|
||||
<interfacename>PropertyEditor</interfacename> will recognize the special
|
||||
prefix <literal>classpath:</literal>on the string path, and create a
|
||||
<classname>ClassPathResource</classname> in that case.</para>
|
||||
</section>
|
||||
|
||||
<section id="resources-implementations-filesystemresource">
|
||||
<title><classname>FileSystemResource</classname></title>
|
||||
|
||||
<para>This is a <interfacename>Resource</interfacename> implementation
|
||||
for <classname>java.io.File</classname> handles. It obviously supports
|
||||
resolution as a <classname>File</classname>, and as a
|
||||
<classname>URL</classname>.</para>
|
||||
</section>
|
||||
|
||||
<section id="resources-implementations-servletcontextresource">
|
||||
<title><classname>ServletContextResource</classname></title>
|
||||
|
||||
<para>This is a <interfacename>Resource</interfacename> implementation
|
||||
for <interfacename>ServletContext</interfacename> resources,
|
||||
interpreting relative paths within the relevant web application's root
|
||||
directory.</para>
|
||||
|
||||
<para>This always supports stream access and URL access, but only allows
|
||||
<classname>java.io.File</classname> access when the web application
|
||||
archive is expanded and the resource is physically on the filesystem.
|
||||
Whether or not it's expanded and on the filesystem like this, or
|
||||
accessed directly from the JAR or somewhere else like a DB (it's
|
||||
conceivable) is actually dependent on the Servlet container.</para>
|
||||
</section>
|
||||
|
||||
<section id="resources-implementations-inputstreamresource">
|
||||
<title><classname>InputStreamResource</classname></title>
|
||||
|
||||
<para>A <interfacename>Resource</interfacename> implementation for a
|
||||
given <interfacename>InputStream</interfacename>. This should only be
|
||||
used if no specific <interfacename>Resource</interfacename>
|
||||
implementation is applicable. In particular, prefer
|
||||
<classname>ByteArrayResource</classname> or any of the file-based
|
||||
<interfacename>Resource</interfacename> implementations where
|
||||
possible.</para>
|
||||
|
||||
<para>In contrast to other <interfacename>Resource</interfacename>
|
||||
implementations, this is a descriptor for an
|
||||
<emphasis>already</emphasis> opened resource - therefore returning
|
||||
<literal>true</literal> from <methodname>isOpen()</methodname>. Do not
|
||||
use it if you need to keep the resource descriptor somewhere, or if you
|
||||
need to read a stream multiple times.</para>
|
||||
</section>
|
||||
|
||||
<section id="resources-implementations-bytearrayresource">
|
||||
<title><classname>ByteArrayResource</classname></title>
|
||||
|
||||
<para>This is a <interfacename>Resource</interfacename> implementation
|
||||
for a given byte array. It creates a
|
||||
<classname>ByteArrayInputStream</classname> for the given byte
|
||||
array.</para>
|
||||
|
||||
<para>It's useful for loading content from any given byte array, without
|
||||
having to resort to a single-use
|
||||
<classname>InputStreamResource</classname>.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="resources-resourceloader">
|
||||
<title>The <interfacename>ResourceLoader</interfacename></title>
|
||||
|
||||
<para>The <interfacename>ResourceLoader</interfacename> interface is meant
|
||||
to be implemented by objects that can return (i.e. load)
|
||||
<interfacename>Resource</interfacename> instances.</para>
|
||||
|
||||
<programlisting language="java">public interface ResourceLoader {
|
||||
Resource getResource(String location);
|
||||
}</programlisting>
|
||||
|
||||
<para>All application contexts implement the
|
||||
<interfacename>ResourceLoader</interfacename> interface, and therefore all
|
||||
application contexts may be used to obtain
|
||||
<interfacename>Resource</interfacename> instances.</para>
|
||||
|
||||
<para>When you call <methodname>getResource()</methodname> on a specific
|
||||
application context, and the location path specified doesn't have a
|
||||
specific prefix, you will get back a
|
||||
<interfacename>Resource</interfacename> type that is appropriate to that
|
||||
particular application context. For example, assume the following snippet
|
||||
of code was executed against a
|
||||
<classname>ClassPathXmlApplicationContext</classname> instance:</para>
|
||||
|
||||
<programlisting language="java">Resource template = ctx.getResource("some/resource/path/myTemplate.txt");</programlisting>
|
||||
|
||||
<para>What would be returned would be a
|
||||
<classname>ClassPathResource</classname>; if the same method was executed
|
||||
against a <classname>FileSystemXmlApplicationContext</classname> instance,
|
||||
you'd get back a <classname>FileSystemResource</classname>. For a
|
||||
<classname>WebApplicationContext</classname>, you'd get back a
|
||||
<classname>ServletContextResource</classname>, and so on.</para>
|
||||
|
||||
<para>As such, you can load resources in a fashion appropriate to the
|
||||
particular application context.</para>
|
||||
|
||||
<para>On the other hand, you may also force
|
||||
<classname>ClassPathResource</classname> to be used, regardless of the
|
||||
application context type, by specifying the special
|
||||
<literal>classpath:</literal> prefix:</para>
|
||||
|
||||
<programlisting language="java">Resource template = ctx.getResource("classpath:some/resource/path/myTemplate.txt");</programlisting>
|
||||
|
||||
<para>Similarly, one can force a <classname>UrlResource</classname> to be
|
||||
used by specifying any of the standard <classname>java.net.URL</classname>
|
||||
prefixes:</para>
|
||||
|
||||
<programlisting language="java">Resource template = ctx.getResource("file:/some/resource/path/myTemplate.txt");</programlisting>
|
||||
|
||||
<programlisting language="java">Resource template = ctx.getResource("http://myhost.com/resource/path/myTemplate.txt");</programlisting>
|
||||
|
||||
<para>The following table summarizes the strategy for converting
|
||||
<classname>String</classname>s to
|
||||
<interfacename>Resource</interfacename>s:</para>
|
||||
|
||||
<table pgwide="1" id="resources-resource-strings">
|
||||
<title>Resource strings</title>
|
||||
|
||||
<tgroup cols="3">
|
||||
<colspec align="left" />
|
||||
|
||||
<thead>
|
||||
<row>
|
||||
<entry align="center">Prefix</entry>
|
||||
|
||||
<entry align="center">Example</entry>
|
||||
|
||||
<entry align="center">Explanation</entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><para>classpath:</para></entry>
|
||||
|
||||
<entry><para> <literal>classpath:com/myapp/config.xml</literal>
|
||||
</para></entry>
|
||||
|
||||
<entry><para>Loaded from the classpath.</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para>file:</para></entry>
|
||||
|
||||
<entry><para> <literal>file:/data/config.xml</literal>
|
||||
</para></entry>
|
||||
|
||||
<entry><para> Loaded as a <classname>URL</classname>, from the
|
||||
filesystem. <footnote>
|
||||
<para>But see also
|
||||
<xref linkend="resources-filesystemresource-caveats" />.</para>
|
||||
</footnote> </para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para>http:</para></entry>
|
||||
|
||||
<entry><para> <literal>http://myserver/logo.png</literal>
|
||||
</para></entry>
|
||||
|
||||
<entry><para>Loaded as a
|
||||
<classname>URL</classname>.</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para>(none)</para></entry>
|
||||
|
||||
<entry><para> <literal>/data/config.xml</literal> </para></entry>
|
||||
|
||||
<entry><para> Depends on the underlying
|
||||
<interfacename>ApplicationContext</interfacename>. </para></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<section id="resources-resourceloaderaware">
|
||||
<title>The <interfacename>ResourceLoaderAware</interfacename> interface</title>
|
||||
|
||||
<para>The <interfacename>ResourceLoaderAware</interfacename> interface is
|
||||
a special marker interface, identifying objects that expect to be provided
|
||||
with a <interfacename>ResourceLoader</interfacename> reference.</para>
|
||||
|
||||
<programlisting language="java"><![CDATA[public interface ResourceLoaderAware {
|
||||
|
||||
void setResourceLoader(ResourceLoader resourceLoader);
|
||||
}]]></programlisting>
|
||||
|
||||
<para>When a class implements
|
||||
<interfacename>ResourceLoaderAware</interfacename> and is deployed into an
|
||||
application context (as a Spring-managed bean), it is recognized as
|
||||
<interfacename>ResourceLoaderAware</interfacename> by the application
|
||||
context. The application context will then invoke the
|
||||
<methodname>setResourceLoader(ResourceLoader)</methodname>, supplying
|
||||
itself as the argument (remember, all application contexts in Spring
|
||||
implement the <interfacename>ResourceLoader</interfacename>
|
||||
interface).</para>
|
||||
|
||||
<para>Of course, since an
|
||||
<interfacename>ApplicationContext</interfacename> is a
|
||||
<interfacename>ResourceLoader</interfacename>, the bean could also
|
||||
implement the <interfacename>ApplicationContextAware</interfacename>
|
||||
interface and use the supplied application context directly to load
|
||||
resources, but in general, it's better to use the specialized
|
||||
<interfacename>ResourceLoader</interfacename> interface if that's all
|
||||
that's needed. The code would just be coupled to the resource loading
|
||||
interface, which can be considered a utility interface, and not the whole
|
||||
Spring <interfacename>ApplicationContext</interfacename> interface.</para>
|
||||
|
||||
<para>As of Spring 2.5, you can rely upon autowiring of the
|
||||
<interfacename>ResourceLoader</interfacename> as an alternative to
|
||||
implementing the <interfacename>ResourceLoaderAware</interfacename> interface.
|
||||
The "traditional" <literal>constructor</literal> and <literal>byType</literal>
|
||||
autowiring modes (as described in <xref linkend="beans-factory-autowire"/>)
|
||||
are now capable of providing a dependency of type
|
||||
<interfacename>ResourceLoader</interfacename> for either a
|
||||
constructor argument or setter method parameter respectively. For more flexibility
|
||||
(including the ability to autowire fields and multiple parameter methods), consider
|
||||
using the new annotation-based autowiring features. In that case, the
|
||||
<interfacename>ResourceLoader</interfacename> will be autowired into a field,
|
||||
constructor argument, or method parameter that is expecting the
|
||||
<interfacename>ResourceLoader</interfacename> type as long as the field,
|
||||
constructor, or method in question carries the
|
||||
<interfacename>@Autowired</interfacename> annotation. For more information,
|
||||
see <xref linkend="beans-autowired-annotation"/>.</para>
|
||||
</section>
|
||||
|
||||
<section id="resources-as-dependencies">
|
||||
<title><literal>Resources</literal> as dependencies</title>
|
||||
|
||||
<para>If the bean itself is going to determine and supply the resource
|
||||
path through some sort of dynamic process, it probably makes sense for the
|
||||
bean to use the <interfacename>ResourceLoader</interfacename> interface to
|
||||
load resources. Consider as an example the loading of a template of some
|
||||
sort, where the specific resource that is needed depends on the role of
|
||||
the user. If the resources are static, it makes sense to eliminate the use
|
||||
of the <interfacename>ResourceLoader</interfacename> interface completely,
|
||||
and just have the bean expose the <interfacename>Resource</interfacename>
|
||||
properties it needs, and expect that they will be injected into it.</para>
|
||||
|
||||
<para>What makes it trivial to then inject these properties, is that all
|
||||
application contexts register and use a special JavaBeans
|
||||
<interfacename>PropertyEditor</interfacename> which can convert
|
||||
<classname>String</classname> paths to
|
||||
<interfacename>Resource</interfacename> objects. So if
|
||||
<literal>myBean</literal> has a template property of type
|
||||
<interfacename>Resource</interfacename>, it can be configured with a
|
||||
simple string for that resource, as follows:</para>
|
||||
|
||||
<programlisting language="xml"><![CDATA[<bean id="myBean" class="...">
|
||||
<property name="template" value="some/resource/path/myTemplate.txt"/>
|
||||
</bean>]]></programlisting>
|
||||
|
||||
<para>Note that the resource path has no prefix, so because the
|
||||
application context itself is going to be used as the
|
||||
<interfacename>ResourceLoader</interfacename>, the resource itself will be
|
||||
loaded via a <classname>ClassPathResource</classname>,
|
||||
<literal>FileSystemResource</literal>, or
|
||||
<classname>ServletContextResource</classname> (as appropriate)
|
||||
depending on the exact type of the context.</para>
|
||||
|
||||
<para>If there is a need to force a specific
|
||||
<interfacename>Resource</interfacename> type to be used, then a prefix may
|
||||
be used. The following two examples show how to force a
|
||||
<classname>ClassPathResource</classname> and a
|
||||
<classname>UrlResource</classname> (the latter being used to access a
|
||||
filesystem file).</para>
|
||||
|
||||
<programlisting language="xml"><![CDATA[<property name="template" value="classpath:some/resource/path/myTemplate.txt">]]></programlisting>
|
||||
|
||||
<programlisting language="xml"><![CDATA[<property name="template" value="file:/some/resource/path/myTemplate.txt"/>]]></programlisting>
|
||||
</section>
|
||||
|
||||
<section id="resources-app-ctx">
|
||||
<title>Application contexts and <interfacename>Resource</interfacename> paths</title>
|
||||
|
||||
<section id="resources-app-ctx-construction">
|
||||
<title>Constructing application contexts</title>
|
||||
|
||||
<para>An application context constructor (for a specific application
|
||||
context type) generally takes a string or array of strings as the
|
||||
location path(s) of the resource(s) such as XML files that make up the
|
||||
definition of the context.</para>
|
||||
|
||||
<para>When such a location path doesn't have a prefix, the specific
|
||||
<interfacename>Resource</interfacename> type built from that path and
|
||||
used to load the bean definitions, depends on and is appropriate to the
|
||||
specific application context. For example, if you create a
|
||||
<classname>ClassPathXmlApplicationContext</classname> as follows:</para>
|
||||
|
||||
<programlisting language="java"><![CDATA[ApplicationContext ctx = new ClassPathXmlApplicationContext("conf/appContext.xml");]]></programlisting>
|
||||
|
||||
<para>The bean definitions will be loaded from the classpath, as a
|
||||
<classname></classname><classname>ClassPathResource</classname> will be
|
||||
used. But if you create a
|
||||
<classname>FileSystemXmlApplicationContext</classname> as
|
||||
follows:</para>
|
||||
|
||||
<programlisting language="java"><![CDATA[ApplicationContext ctx =
|
||||
new FileSystemXmlApplicationContext("conf/appContext.xml");]]></programlisting>
|
||||
|
||||
<para>The bean definition will be loaded from a filesystem location, in
|
||||
this case relative to the current working directory.</para>
|
||||
|
||||
<para>Note that the use of the special classpath prefix or a standard
|
||||
URL prefix on the location path will override the default type of
|
||||
<interfacename>Resource</interfacename> created to load the definition.
|
||||
So this <classname>FileSystemXmlApplicationContext</classname>...</para>
|
||||
|
||||
<programlisting language="java"><![CDATA[ApplicationContext ctx =
|
||||
new FileSystemXmlApplicationContext("classpath:conf/appContext.xml");]]></programlisting>
|
||||
|
||||
<para>... will actually load its bean definitions from the classpath.
|
||||
However, it is still a <classname>FileSystemXmlApplicationContext</classname>. If it is
|
||||
subsequently used as a <interfacename>ResourceLoader</interfacename>,
|
||||
any unprefixed paths will still be treated as filesystem paths.</para>
|
||||
|
||||
<section id="resources-app-ctx-classpathxml">
|
||||
<title>Constructing <classname>ClassPathXmlApplicationContext</classname> instances - shortcuts</title>
|
||||
|
||||
<para>The <classname>ClassPathXmlApplicationContext</classname>
|
||||
exposes a number of constructors to enable convenient instantiation.
|
||||
The basic idea is that one supplies merely a string array containing
|
||||
just the filenames of the XML files themselves (without the leading
|
||||
path information), and one <emphasis>also</emphasis> supplies a
|
||||
<classname>Class</classname>; the
|
||||
<classname>ClassPathXmlApplicationContext</classname> will derive the
|
||||
path information from the supplied class.</para>
|
||||
|
||||
<para>An example will hopefully make this clear. Consider a directory
|
||||
layout that looks like this:</para>
|
||||
|
||||
<programlisting><![CDATA[com/
|
||||
foo/
|
||||
services.xml
|
||||
daos.xml
|
||||
MessengerService.class]]></programlisting>
|
||||
|
||||
<para>A <classname>ClassPathXmlApplicationContext</classname> instance
|
||||
composed of the beans defined in the <literal>'services.xml'</literal>
|
||||
and <literal>'daos.xml'</literal> could be instantiated like
|
||||
so...</para>
|
||||
|
||||
<programlisting language="java"><![CDATA[ApplicationContext ctx = new ClassPathXmlApplicationContext(
|
||||
new String[] {"services.xml", "daos.xml"}, MessengerService.class);]]></programlisting>
|
||||
|
||||
<para>Please do consult the Javadocs for the
|
||||
<classname>ClassPathXmlApplicationContext</classname> class for
|
||||
details of the various constructors.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="resources-app-ctx-wildcards-in-resource-paths">
|
||||
<title>Wildcards in application context constructor resource paths</title>
|
||||
|
||||
<para>The resource paths in application context constructor values may
|
||||
be a simple path (as shown above) which has a one-to-one mapping to a
|
||||
target Resource, or alternately may contain the special "classpath*:"
|
||||
prefix and/or internal Ant-style regular expressions (matched using
|
||||
Spring's <classname>PathMatcher</classname> utility). Both of the latter
|
||||
are effectively wildcards</para>
|
||||
|
||||
<para>One use for this mechanism is when doing component-style
|
||||
application assembly. All components can 'publish' context definition
|
||||
fragments to a well-known location path, and when the final application
|
||||
context is created using the same path prefixed via
|
||||
<literal>classpath*:</literal>, all component fragments will be picked
|
||||
up automatically.</para>
|
||||
|
||||
<para>Note that this wildcarding is specific to use of resource paths in
|
||||
application context constructors (or when using the
|
||||
<classname>PathMatcher</classname> utility class hierarchy directly),
|
||||
and is resolved at construction time. It has nothing to do with the
|
||||
<interfacename>Resource</interfacename> type itself. It's not possible
|
||||
to use the <literal>classpath*:</literal> prefix to construct an actual
|
||||
<interfacename>Resource</interfacename>, as a resource points to just
|
||||
one resource at a time.</para>
|
||||
|
||||
<section id="resources-app-ctx-ant-patterns-in-paths">
|
||||
<title>Ant-style Patterns</title>
|
||||
|
||||
<para>When the path location contains an Ant-style pattern, for example:</para>
|
||||
|
||||
<programlisting><![CDATA[ /WEB-INF/*-context.xml
|
||||
com/mycompany/**/applicationContext.xml
|
||||
file:C:/some/path/*-context.xml
|
||||
classpath:com/mycompany/**/applicationContext.xml]]></programlisting>
|
||||
|
||||
<para>... the resolver follows a more complex but defined procedure to
|
||||
try to resolve the wildcard. It produces a Resource for the path up to
|
||||
the last non-wildcard segment and obtains a URL from it. If this URL
|
||||
is not a "jar:" URL or container-specific variant (e.g.
|
||||
"<literal>zip:</literal>" in WebLogic, "<literal>wsjar</literal>" in
|
||||
WebSphere, etc.), then a <classname>java.io.File</classname> is
|
||||
obtained from it and used to resolve the wildcard by traversing the
|
||||
filesystem. In the case of a jar URL, the resolver either gets a
|
||||
<classname>java.net.JarURLConnection</classname> from it or manually
|
||||
parses the jar URL and then traverses the contents of the jar file
|
||||
to resolve the wildcards.</para>
|
||||
|
||||
<section id="resources-app-ctx-portability">
|
||||
<title>Implications on portability</title>
|
||||
|
||||
<para>If the specified path is already a file URL (either
|
||||
explicitly, or implicitly because the base
|
||||
<interfacename>ResourceLoader</interfacename> is a
|
||||
filesystem one, then wildcarding is guaranteed to work in a
|
||||
completely portable fashion.</para>
|
||||
|
||||
<para>If the specified path is a classpath location, then the
|
||||
resolver must obtain the last non-wildcard path segment URL via a
|
||||
<methodname>Classloader.getResource()</methodname> call. Since this
|
||||
is just a node of the path (not the file at the end) it is actually
|
||||
undefined (in the <classname>ClassLoader</classname> Javadocs)
|
||||
exactly what sort of a URL is returned in this case. In practice, it
|
||||
is always a <classname>java.io.File</classname> representing the
|
||||
directory, where the classpath resource resolves to a filesystem
|
||||
location, or a jar URL of some sort, where the classpath resource
|
||||
resolves to a jar location. Still, there is a portability concern on
|
||||
this operation.</para>
|
||||
|
||||
<para>If a jar URL is obtained for the last non-wildcard segment,
|
||||
the resolver must be able to get a
|
||||
<classname>java.net.JarURLConnection</classname> from it, or
|
||||
manually parse the jar URL, to be able to walk the contents of the
|
||||
jar, and resolve the wildcard. This will work in most environments,
|
||||
but will fail in others, and it is strongly recommended that the
|
||||
wildcard resolution of resources coming from jars be thoroughly
|
||||
tested in your specific environment before you rely on it.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="resources-classpath-wildcards">
|
||||
<title>The <literal>classpath*:</literal> prefix</title>
|
||||
|
||||
<para>When constructing an XML-based application context, a location
|
||||
string may use the special <literal>classpath*:</literal>
|
||||
prefix:</para>
|
||||
|
||||
<programlisting language="java"><![CDATA[ApplicationContext ctx =
|
||||
new ClassPathXmlApplicationContext("classpath*:conf/appContext.xml");]]></programlisting>
|
||||
|
||||
<para>This special prefix specifies that all classpath resources that
|
||||
match the given name must be obtained (internally, this essentially
|
||||
happens via a <methodname>ClassLoader.getResources(...)</methodname>
|
||||
call), and then merged to form the final application context
|
||||
definition.</para>
|
||||
|
||||
<note>
|
||||
<title>Classpath*: portability</title>
|
||||
|
||||
<para>The wildcard classpath relies on the <literal>getResources()</literal> method of the
|
||||
underlying classloader. As most application servers nowadays supply
|
||||
their own classloader implementation, the behavior might differ
|
||||
especially when dealing with jar files. A simple test to check if
|
||||
<literal>classpath*</literal> works is to use the classloader to load a file from
|
||||
within a jar on the classpath:
|
||||
<literal>getClass().getClassLoader().getResources("<someFileInsideTheJar>")</literal>.
|
||||
Try this test with files that have the same name but are placed
|
||||
inside two different locations. In case an inappropriate result is
|
||||
returned, check the application server documentation for settings
|
||||
that might affect the classloader behavior.</para>
|
||||
</note>
|
||||
|
||||
<para>The "<literal>classpath*:</literal>" prefix can also be combined
|
||||
with a <literal>PathMatcher</literal> pattern in the rest of the location path, for
|
||||
example "<literal>classpath*:META-INF/*-beans.xml</literal>". In this
|
||||
case, the resolution strategy is fairly simple: a
|
||||
ClassLoader.getResources() call is used on the last non-wildcard path
|
||||
segment to get all the matching resources in the class loader
|
||||
hierarchy, and then off each resource the same PathMatcher resoltion
|
||||
strategy described above is used for the wildcard subpath.</para>
|
||||
</section>
|
||||
|
||||
<section id="resources-wildcards-in-path-other-stuff">
|
||||
<title>Other notes relating to wildcards</title>
|
||||
|
||||
<para>Please note that "<literal>classpath*:</literal>" when
|
||||
combined with Ant-style patterns will only work reliably with at least
|
||||
one root directory before the pattern starts, unless the actual target
|
||||
files reside in the file system. This means that a pattern like
|
||||
"<literal>classpath*:*.xml</literal>" will not retrieve files from the
|
||||
root of jar files but rather only from the root of expanded
|
||||
directories. This originates from a limitation in the JDK's
|
||||
<methodname>ClassLoader.getResources()</methodname> method which only
|
||||
returns file system locations for a passed-in empty string (indicating
|
||||
potential roots to search).</para>
|
||||
|
||||
<para>Ant-style patterns with "<literal>classpath:</literal>"
|
||||
resources are not guaranteed to find matching resources if the root
|
||||
package to search is available in multiple class path locations. This
|
||||
is because a resource such as</para>
|
||||
|
||||
<programlisting><![CDATA[ com/mycompany/package1/service-context.xml]]></programlisting>
|
||||
|
||||
<para>may be in only one location, but when a path such as</para>
|
||||
|
||||
<programlisting><![CDATA[ classpath:com/mycompany/**/service-context.xml]]></programlisting>
|
||||
|
||||
<para>is used to try to resolve it, the resolver will work off the (first) URL
|
||||
returned by <methodname>getResource("com/mycompany")</methodname>;. If
|
||||
this base package node exists in multiple classloader locations, the
|
||||
actual end resource may not be underneath. Therefore, preferably, use
|
||||
"<literal>classpath*:</literal>" with the same Ant-style pattern in
|
||||
such a case, which will search all class path locations that contain
|
||||
the root package.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="resources-filesystemresource-caveats">
|
||||
<title><classname>FileSystemResource</classname> caveats</title>
|
||||
|
||||
<para>A <classname>FileSystemResource</classname> that is not attached
|
||||
to a <classname>FileSystemApplicationContext</classname> (that is, a
|
||||
<classname>FileSystemApplicationContext</classname> is not the actual
|
||||
<interfacename>ResourceLoader</interfacename>) will treat absolute vs.
|
||||
relative paths as you would expect. Relative paths are relative to the
|
||||
current working directory, while absolute paths are relative to the root
|
||||
of the filesystem.</para>
|
||||
|
||||
<para>For backwards compatibility (historical) reasons however, this
|
||||
changes when the <classname>FileSystemApplicationContext</classname> is
|
||||
the <literal>ResourceLoader</literal>. The
|
||||
<classname>FileSystemApplicationContext</classname> simply forces all
|
||||
attached <classname>FileSystemResource</classname> instances to treat
|
||||
all location paths as relative, whether they start with a leading slash
|
||||
or not. In practice, this means the following are equivalent:</para>
|
||||
|
||||
<programlisting language="java"><![CDATA[ApplicationContext ctx =
|
||||
new FileSystemXmlApplicationContext("conf/context.xml");]]></programlisting>
|
||||
|
||||
<programlisting language="java"><![CDATA[ApplicationContext ctx =
|
||||
new FileSystemXmlApplicationContext("/conf/context.xml");]]></programlisting>
|
||||
|
||||
<para>As are the following: (Even though it would make sense for them to
|
||||
be different, as one case is relative and the other absolute.)</para>
|
||||
|
||||
<programlisting language="java"><![CDATA[FileSystemXmlApplicationContext ctx = ...;
|
||||
ctx.getResource("some/resource/path/myTemplate.txt");]]></programlisting>
|
||||
|
||||
<programlisting language="java"><![CDATA[FileSystemXmlApplicationContext ctx = ...;
|
||||
ctx.getResource("/some/resource/path/myTemplate.txt");]]></programlisting>
|
||||
|
||||
<para>In practice, if true absolute filesystem paths are needed, it is
|
||||
better to forgo the use of absolute paths with
|
||||
<classname>FileSystemResource</classname> /
|
||||
<classname>FileSystemXmlApplicationContext</classname>, and just force
|
||||
the use of a <classname>UrlResource</classname>, by using the
|
||||
<literal>file:</literal> URL prefix.</para>
|
||||
|
||||
<programlisting language="java"><lineannotation>// actual context type doesn't matter, the <interfacename>Resource</interfacename> will always be <classname>UrlResource</classname></lineannotation><![CDATA[
|
||||
ctx.getResource("file:/some/resource/path/myTemplate.txt");]]></programlisting>
|
||||
|
||||
<programlisting language="java"><lineannotation>// force this FileSystemXmlApplicationContext to load its definition via a <classname>UrlResource</classname></lineannotation><![CDATA[
|
||||
ApplicationContext ctx =
|
||||
new FileSystemXmlApplicationContext("file:/conf/context.xml");]]></programlisting>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
||||