Poish asciidoctor
Issues: SPR-10960 grate documentation to # deleted: src/reference/docbook/index.xml
This commit is contained in:
parent
2e57cf8bfc
commit
3476d11fb8
|
|
@ -1,7 +1,7 @@
|
|||
= Spring Framework Reference Documentation
|
||||
Rod Johnson; Juergen Hoeller; Keith Donald; Colin Sampaleanu; Rob Harrop; Thomas Risberg; Alef Arendsen; 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; Phillip Webb; Rob Winch
|
||||
|
||||
Core support for dependency injection, transaction management, web applications, data access, messaging, testing and more.
|
||||
rCore support for dependency injection, transaction management, web applications, data access, messaging, testing and more.
|
||||
|
||||
__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.__
|
||||
|
||||
|
|
@ -17,7 +17,7 @@ This document is a reference guide to Spring Framework features. If you have any
|
|||
== Introduction to Spring Framework
|
||||
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.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
Examples of how you, as an application developer, can use the Spring platform advantage:
|
||||
|
||||
|
|
@ -1005,7 +1005,7 @@ Finally, the adoption of the test-driven-development (TDD) approach to software
|
|||
=== Introduction to the Spring IoC container and beans
|
||||
This chapter covers the Spring Framework implementation of the Inversion of Control (IoC) footnote:[See pass:specialcharacters,macros[<<background-ioc>>] ] principle. IoC is also known as __dependency injection__ (DI). It is a process whereby objects define their dependencies, that is, the other objects they work with, only through constructor arguments, arguments to a factory method, or properties that are set on the object instance after it is constructed or returned from a factory method. The container then __injects__ those dependencies when it creates the bean. This process is fundamentally the inverse, hence the name __Inversion of Control__ (IoC), of the bean itself controlling the instantiation or location of its dependencies by using direct construction of classes, or a mechanism such as the __Service Locator__ pattern.
|
||||
|
||||
The `org.springframework.beans` and `org.springframework.context` packages are the basis for Spring Framework's IoC container. The `http://static.springsource.org/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/BeanFactory.html[BeanFactory]` interface provides an advanced configuration mechanism capable of managing any type of object. `http://static.springsource.org/spring-framework/docs/current/javadoc-api/org/springframework/context/ApplicationContext.html[ApplicationContext]` is a sub-interface of `BeanFactory`. It adds easier integration with Spring's AOP features; message resource handling (for use in internationalization), event publication; and application-layer specific contexts such as the `WebApplicationContext` for use in web applications.
|
||||
The `org.springframework.beans` and `org.springframework.context` packages are the basis for Spring Framework's IoC container. The http://static.springsource.org/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/BeanFactory.html[BeanFactory] interface provides an advanced configuration mechanism capable of managing any type of object. http://static.springsource.org/spring-framework/docs/current/javadoc-api/org/springframework/context/ApplicationContext.html[ApplicationContext] is a sub-interface of `BeanFactory`. It adds easier integration with Spring's AOP features; message resource handling (for use in internationalization), event publication; and application-layer specific contexts such as the `WebApplicationContext` for use in web applications.
|
||||
|
||||
In short, the `BeanFactory` provides the configuration framework and basic functionality, and the `ApplicationContext` adds more enterprise-specific functionality. The `ApplicationContext` is a complete superset of the `BeanFactory`, and is used exclusively in this chapter in descriptions of Spring's IoC container.For more information on using the `BeanFactory` instead of the `ApplicationContext,` refer to <<beans-beanfactory>>.
|
||||
|
||||
|
|
@ -1410,7 +1410,7 @@ public class DefaultServiceLocator {
|
|||
}
|
||||
----
|
||||
|
||||
This approach shows that the factory bean itself can be managed and configured through dependency injection (DI). See <<beans-factory-properties-detailed,<<beans-factory-properties-detailed,Dependencies and configuration in detail>>.>>
|
||||
This approach shows that the factory bean itself can be managed and configured through dependency injection (DI). See <<beans-factory-properties-detailed,Dependencies and configuration in detail>>.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
|
|
@ -1549,7 +1549,7 @@ As of Spring 3.0 you can also use the constructor parameter name for value disam
|
|||
</bean>
|
||||
----
|
||||
|
||||
Keep in mind that to make this work out of the box your code must be compiled with the debug flag enabled so that Spring can look up the parameter name from the constructor. If you can't compile your code with debug flag (or don't want to) you can use `http://download.oracle.com/javase/6/docs/api/java/beans/ConstructorProperties.html[@ConstructorProperties]` JDK annotation to explicitly name your constructor arguments. The sample class would then have to look as follows:
|
||||
Keep in mind that to make this work out of the box your code must be compiled with the debug flag enabled so that Spring can look up the parameter name from the constructor. If you can't compile your code with debug flag (or don't want to) you can use http://download.oracle.com/javase/6/docs/api/java/beans/ConstructorProperties.html[@ConstructorProperties] JDK annotation to explicitly name your constructor arguments. The sample class would then have to look as follows:
|
||||
|
||||
[source,java]
|
||||
[subs="verbatim,quotes"]
|
||||
|
|
@ -4896,7 +4896,7 @@ A `WebApplicationContext` variant of `AnnotationConfigApplicationContext` is ava
|
|||
[[beans-java-bean-annotation]]
|
||||
==== Using the @Bean annotation
|
||||
|
||||
`@Bean` is a method-level annotation and a direct analog of the XML `<bean/>` element. The annotation supports some of the attributes offered by `<bean/>`, such as: `<<beans-factory-lifecycle-initializingbean,init-method>>`, `<<beans-factory-lifecycle-disposablebean,destroy-method>>`, `<<beans-factory-autowire,autowiring>>` and `name`.
|
||||
`@Bean` is a method-level annotation and a direct analog of the XML `<bean/>` element. The annotation supports some of the attributes offered by `<bean/>`, such as: <<beans-factory-lifecycle-initializingbean,init-method>>, <<beans-factory-lifecycle-disposablebean,destroy-method>>, <<beans-factory-autowire,autowiring>> and `name`.
|
||||
|
||||
You can use the `@Bean` annotation in a `@Configuration`-annotated or in a `@Component`-annotated class.
|
||||
|
||||
|
|
@ -4942,7 +4942,7 @@ Any classes defined with the `@Bean` annotation support the regular lifecycle ca
|
|||
|
||||
The regular Spring <<beans-factory-nature,lifecycle>> callbacks are fully supported as well. If a bean implements `InitializingBean`, `DisposableBean`, or `Lifecycle`, their respective methods are called by the container.
|
||||
|
||||
The standard set of `*Aware` interfaces such as `<<beans-beanfactory,BeanFactoryAware>>`, `<<beans-factory-aware,BeanNameAware>>`, `<<context-functionality-messagesource,MessageSourceAware>>`, `<<beans-factory-aware,ApplicationContextAware>>`, and so on are also fully supported.
|
||||
The standard set of `*Aware` interfaces such as <<beans-beanfactory,BeanFactoryAware>>, <<beans-factory-aware,BeanNameAware>>, <<context-functionality-messagesource,MessageSourceAware>>, <<beans-factory-aware,ApplicationContextAware>>, and so on are also fully supported.
|
||||
|
||||
The `@Bean` annotation supports specifying arbitrary initialization and destruction callback methods, much like Spring XML's `init-method` and `destroy-method` attributes on the `bean` element:
|
||||
|
||||
|
|
@ -15257,15 +15257,15 @@ The `@Transactional` annotation is metadata that specifies that an interface, cl
|
|||
These default settings can be changed; the various properties of the `@Transactional` annotation are summarized in the following table:
|
||||
|
||||
[[tx-attransactional-properties]]
|
||||
.@Transactional properties
|
||||
.@
|
||||
|===
|
||||
| Property| Type| Description
|
||||
|
||||
a| `<<tx-multiple-tx-mgrs-with-attransactional,value>>`
|
||||
a| <<tx-multiple-tx-mgrs-with-attransactional,value>>
|
||||
| String
|
||||
| Optional qualifier specifying the transaction manager to be used.
|
||||
|
||||
a| `<<tx-propagation,propagation>>`
|
||||
a| <<tx-propagation,propagation>>
|
||||
| enum: `Propagation`
|
||||
| Optional propagation setting.
|
||||
|
||||
|
|
@ -25256,7 +25256,7 @@ This can be very valuable since you can then use interceptors to pre-process and
|
|||
=== Handler mappings
|
||||
Using a handler mapping you can map incoming portlet requests to appropriate handlers. There are some handler mappings you can use out of the box, for example, the `PortletModeHandlerMapping`, but let's first examine the general concept of a `HandlerMapping`.
|
||||
|
||||
Note: We are intentionally using the term “Handler” here instead of “Controller”. `DispatcherPortlet` is designed to be used with other ways to process requests than just Spring Portlet MVC’s own Controllers. A Handler is any Object that can handle portlet requests. Controllers are an example of Handlers, and they are of course the default. To use some other framework with `DispatcherPortlet`, a corresponding implementation of `HandlerAdapter` is all that is needed.
|
||||
Note: We are intentionally using the term "Handler" here instead of "Controller". `DispatcherPortlet` is designed to be used with other ways to process requests than just Spring Portlet MVC’s own Controllers. A Handler is any Object that can handle portlet requests. Controllers are an example of Handlers, and they are of course the default. To use some other framework with `DispatcherPortlet`, a corresponding implementation of `HandlerAdapter` is all that is needed.
|
||||
|
||||
The functionality a basic `HandlerMapping` provides is the delivering of a `HandlerExecutionChain`, which must contain the handler that matches the incoming request, and may also contain a list of handler interceptors that are applied to the request. When a request comes in, the `DispatcherPortlet` will hand it over to the handler mapping to let it inspect the request and come up with an appropriate `HandlerExecutionChain`. Then the `DispatcherPortlet` will execute the handler and interceptors in the chain (if any). These concepts are all exactly the same as in Spring Web MVC.
|
||||
|
||||
|
|
@ -25302,7 +25302,7 @@ The bean configuration for this mapping will look something like this:
|
|||
[source,xml]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
<bean class="org.springframework.web.portlet.handler.ParameterHandlerMapping”>
|
||||
<bean class="org.springframework.web.portlet.handler.ParameterHandlerMapping">
|
||||
<property name="parameterMap">
|
||||
<map>
|
||||
<entry key="add" value-ref="addItemHandler"/>
|
||||
|
|
@ -25432,7 +25432,7 @@ After the `PortletMultipartResolver` has finished doing its job, the request wil
|
|||
</form>
|
||||
----
|
||||
|
||||
As you can see, we've created a field named “file” that matches the property of the bean that holds the `byte[]` array. Furthermore we've added the encoding attribute ( `enctype="multipart/form-data"`), which is necessary to let the browser know how to encode the multipart fields (do not forget this!).
|
||||
As you can see, we've created a field named "file" that matches the property of the bean that holds the `byte[]` array. Furthermore we've added the encoding attribute ( `enctype="multipart/form-data"`), which is necessary to let the browser know how to encode the multipart fields (do not forget this!).
|
||||
|
||||
Just as with any other property that's not automagically convertible to a string or primitive type, to be able to put binary data in your objects you have to register a custom editor with the `PortletRequestDataBinder`. There are a couple of editors available for handling files and setting the results on an object. There's a `StringMultipartFileEditor` capable of converting files to Strings (using a user-defined character set), and there is a `ByteArrayMultipartFileEditor` which converts files to byte arrays. They function analogous to the `CustomDateEditor`.
|
||||
|
||||
|
|
@ -25877,7 +25877,7 @@ The process of deploying a Spring Portlet MVC application is no different than d
|
|||
|
||||
Generally, the portal/portlet container runs in one webapp in your servlet container and your portlets run in another webapp in your servlet container. In order for the portlet container webapp to make calls into your portlet webapp it must make cross-context calls to a well-known servlet that provides access to the portlet services defined in your `portlet.xml` file.
|
||||
|
||||
The JSR-168 specification does not specify exactly how this should happen, so each portlet container has its own mechanism for this, which usually involves some kind of “deployment process” that makes changes to the portlet webapp itself and then registers the portlets within the portlet container.
|
||||
The JSR-168 specification does not specify exactly how this should happen, so each portlet container has its own mechanism for this, which usually involves some kind of "deployment process" that makes changes to the portlet webapp itself and then registers the portlets within the portlet container.
|
||||
|
||||
At a minimum, the `web.xml` file in your portlet webapp is modified to inject the well-known servlet that the portlet container will call. In some cases a single servlet will service all portlets in the webapp, in other cases there will be an instance of the servlet for each portlet.
|
||||
|
||||
|
|
@ -31256,7 +31256,7 @@ Please note that in order to effect the automatic 'pickup' of any changes to dyn
|
|||
|
||||
Find below an example of a Spring `org.springframework.validation.Validator` implemented using the Groovy dynamic language. (See <<validator>> for a discussion of the `Validator` interface.)
|
||||
|
||||
[source,grovy]
|
||||
[source,groovy]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
import org.springframework.validation.Validator
|
||||
|
|
@ -31628,7 +31628,7 @@ The caching abstraction allows one to use her own annotations to identify what m
|
|||
----
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.METHOD})
|
||||
@Cacheable(value=“books”, key="#isbn")
|
||||
@Cacheable(value="books", key="#isbn")
|
||||
public @interface SlowService {
|
||||
}
|
||||
----
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -1,806 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<section xml:id="beans-annotation-config"
|
||||
xmlns="http://docbook.org/ns/docbook" version="5.0"
|
||||
xmlns:xl="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
|
||||
http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd">
|
||||
<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 <link xl:href="http://www.springsource.com/products/sts"
|
||||
>SpringSource Tool Suite</link>.</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><para>Annotation injection is performed
|
||||
<emphasis>before</emphasis> XML injection, thus the latter configuration
|
||||
will override the former for properties wired through both approaches.
|
||||
</para></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.xsd
|
||||
http://www.springframework.org/schema/context
|
||||
http://www.springframework.org/schema/context/spring-context.xsd">
|
||||
|
||||
<lineannotation><context:annotation-config/></lineannotation>
|
||||
|
||||
</beans></programlisting>
|
||||
|
||||
<para>(The implicitly registered post-processors include <link
|
||||
xl:href="http://static.springsource.org/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.html"
|
||||
><classname>AutowiredAnnotationBeanPostProcessor</classname></link>, <link
|
||||
xl:href="http://static.springsource.org/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/CommonAnnotationBeanPostProcessor.html"
|
||||
><classname>CommonAnnotationBeanPostProcessor</classname></link>, <link
|
||||
xl:href="http://static.springsource.org/spring-framework/docs/current/javadoc-api/org/springframework/orm/jpa/support/PersistenceAnnotationBeanPostProcessor.html"
|
||||
><classname>PersistenceAnnotationBeanPostProcessor</classname></link>, as
|
||||
well as the aforementioned <link
|
||||
xl:href="http://static.springsource.org/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/annotation/RequiredAnnotationBeanPostProcessor.html"
|
||||
><classname>RequiredAnnotationBeanPostProcessor</classname></link>.)</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 xml: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 xml: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 xml: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.xsd
|
||||
http://www.springframework.org/schema/context
|
||||
http://www.springframework.org/schema/context/spring-context.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.xsd
|
||||
http://www.springframework.org/schema/context
|
||||
http://www.springframework.org/schema/context/spring-context.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.xsd
|
||||
http://www.springframework.org/schema/context
|
||||
http://www.springframework.org/schema/context/spring-context.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 xml:id="beans-custom-autowire-configurer">
|
||||
<title><classname>CustomAutowireConfigurer</classname></title>
|
||||
|
||||
<para>The <link
|
||||
xl:href="http://static.springsource.org/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/annotation/CustomAutowireConfigurer.html"
|
||||
><classname>CustomAutowireConfigurer</classname></link> 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 xml: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 <link
|
||||
xl:href="http://static.springsource.org/spring-framework/docs/current/javadoc-api/org/springframework/jndi/support/SimpleJndiBeanFactory.html"
|
||||
><classname>SimpleJndiBeanFactory</classname></link> 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 xml: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>
|
||||
|
|
@ -1,514 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<section xml:id="beans-classpath-scanning"
|
||||
xmlns="http://docbook.org/ns/docbook" version="5.0"
|
||||
xmlns:xl="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
|
||||
http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd">
|
||||
<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 <link
|
||||
xl:href="http://www.springsource.org/javaconfig">Spring JavaConfig
|
||||
project</link> 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 xml: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 xml: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.xsd
|
||||
http://www.springframework.org/schema/context
|
||||
http://www.springframework.org/schema/context/spring-context.xsd">
|
||||
|
||||
<context:component-scan base-package="org.example"/>
|
||||
|
||||
</beans></programlisting>
|
||||
|
||||
<tip>
|
||||
<para>The use of <literal><context:component-scan></literal> implicitly
|
||||
enables the functionality of <literal><context:annotation-config></literal>.
|
||||
There is usually no need to include the <literal><context:annotation-config></literal>
|
||||
element when using <literal><context:component-scan></literal>.
|
||||
</para>
|
||||
</tip>
|
||||
<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
|
||||
stereotype 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 xml: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 xml: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 xml: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 xml: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 <link
|
||||
xl:href="http://static.springsource.org/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/support/BeanNameGenerator.html"
|
||||
><interfacename>BeanNameGenerator</interfacename></link> 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 xml: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 <link
|
||||
xl:href="http://static.springsource.org/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/ScopeMetadataResolver.html"
|
||||
><interfacename>ScopeMetadataResolver</interfacename></link> 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 xml: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>
|
||||
|
|
@ -1,668 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<section xml:id="context-introduction"
|
||||
xmlns="http://docbook.org/ns/docbook" version="5.0"
|
||||
xmlns:xl="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
|
||||
http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd">
|
||||
<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 <link
|
||||
xl:href="http://static.springsource.org/spring-framework/docs/current/javadoc-api/org/springframework/context/ApplicationContext.html"
|
||||
><interfacename>ApplicationContext</interfacename></link> 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 xml: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 MessageSource is being used in a web application --></lineannotation>
|
||||
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
|
||||
<property name="basename" value="exceptions"/>
|
||||
</bean>
|
||||
|
||||
<lineannotation><!-- lets inject the above MessageSource 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 xml: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 xml: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 <link
|
||||
xl:href="http://springsource.org/spring-integration">Spring
|
||||
Integration</link> project provides complete support for building
|
||||
lightweight, <link xl:href="http://www.enterpriseintegrationpatterns.com"
|
||||
>pattern-oriented</link>, event-driven architectures that build upon
|
||||
the well-known Spring programming model.</para>
|
||||
</note>
|
||||
</section>
|
||||
|
||||
<section xml: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 xml: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 ContextLoaderServlet 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 xml:id="context-deploy-rar">
|
||||
<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 <link
|
||||
xl:href="http://static.springsource.org/spring-framework/docs/current/javadoc-api/org/springframework/jca/context/SpringContextResourceAdapter.html"
|
||||
>SpringContextResourceAdapter</link> 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>
|
||||
|
|
@ -1,682 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<section xml:id="beans-factory-nature"
|
||||
xmlns="http://docbook.org/ns/docbook" version="5.0"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xl="http://www.w3.org/1999/xlink"
|
||||
xsi:schemaLocation="
|
||||
http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
|
||||
http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd">
|
||||
<title>Customizing the nature of a bean</title>
|
||||
|
||||
<section xml:id="beans-factory-lifecycle">
|
||||
<title>Lifecycle callbacks</title>
|
||||
|
||||
<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.</para>
|
||||
|
||||
<tip>
|
||||
<para>The JSR-250 <interfacename>@PostConstruct</interfacename> and
|
||||
<interfacename>@PreDestroy</interfacename> annotations are generally
|
||||
considered best practice for receiving lifecycle callbacks in a modern
|
||||
Spring application. Using these annotations means that your beans are not
|
||||
coupled to Spring specific interfaces. For details see
|
||||
<xref linkend="beans-postconstruct-and-predestroy-annotations"/>.</para>
|
||||
<para>If you don't want to use the JSR-250 annotations but you are still
|
||||
looking to remove coupling consider the use of init-method and destroy-method
|
||||
object definition metadata.</para>
|
||||
</tip>
|
||||
|
||||
<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 xml: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, use the
|
||||
<link linkend="beans-postconstruct-and-predestroy-annotations">
|
||||
<interfacename>@PostConstruct</interfacename> annotation</link> or 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 xml: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, use the
|
||||
<link linkend="beans-postconstruct-and-predestroy-annotations">
|
||||
<interfacename>@PreDestroy</interfacename> annotation</link> or 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 xml: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 default-init-method="init">
|
||||
|
||||
<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 xml: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 xml: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 xml: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 xml: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>ApplicationContext</interfacename> is autowired into a
|
||||
field, constructor argument, or method parameter that is expecting the
|
||||
<interfacename>ApplicationContext</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 xml: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 xml:id="beans-factory-nature-aware-list" pgwide="1">
|
||||
<title><interfacename>Aware</interfacename> interfaces</title>
|
||||
|
||||
<tgroup cols="3">
|
||||
<colspec align="left"/>
|
||||
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Name</entry>
|
||||
|
||||
<entry>Injected Dependency</entry>
|
||||
|
||||
<entry>Explained in...</entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><para><classname>ApplicationContextAware</classname></para></entry>
|
||||
|
||||
<entry><para>Declaring
|
||||
<interfacename>ApplicationContext</interfacename></para></entry>
|
||||
|
||||
<entry><para><xref linkend="beans-factory-aware"/></para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><classname>ApplicationEventPublisherAware</classname></para></entry>
|
||||
|
||||
<entry><para>Event publisher of the enclosing
|
||||
<interfacename>ApplicationContext</interfacename></para></entry>
|
||||
|
||||
<entry><para><xref linkend="context-introduction"/></para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><classname>BeanClassLoaderAware</classname></para></entry>
|
||||
|
||||
<entry><para>Class loader used to load the bean
|
||||
classes.</para></entry>
|
||||
|
||||
<entry><para><xref linkend="beans-factory-class"/></para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><classname>BeanFactoryAware</classname></para></entry>
|
||||
|
||||
<entry><para>Declaring
|
||||
<interfacename>BeanFactory</interfacename></para></entry>
|
||||
|
||||
<entry><para><xref linkend="beans-factory-aware"/></para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><classname>BeanNameAware</classname></para></entry>
|
||||
|
||||
<entry><para>Name of the declaring bean</para></entry>
|
||||
|
||||
<entry><para><xref linkend="beans-factory-aware"/></para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><classname>BootstrapContextAware</classname></para></entry>
|
||||
|
||||
<entry><para>Resource adapter
|
||||
<interfacename>BootstrapContext</interfacename> the container runs
|
||||
in. Typically available only in JCA aware
|
||||
<interfacename>ApplicationContext</interfacename>s</para></entry>
|
||||
|
||||
<entry><para><xref linkend="cci"/></para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><classname>LoadTimeWeaverAware</classname></para></entry>
|
||||
|
||||
<entry><para>Defined <emphasis>weaver</emphasis> for processing
|
||||
class definition at load time</para></entry>
|
||||
|
||||
<entry><para><xref linkend="aop-aj-ltw"/></para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><classname>MessageSourceAware</classname></para></entry>
|
||||
|
||||
<entry><para>Configured strategy for resolving messages (with
|
||||
support for parametrization and
|
||||
internationalization)</para></entry>
|
||||
|
||||
<entry><para><xref linkend="context-introduction"/></para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><classname>NotificationPublisherAware</classname></para></entry>
|
||||
|
||||
<entry><para>Spring JMX notification publisher</para></entry>
|
||||
|
||||
<entry><para><xref linkend="jmx-notifications"/></para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><classname>PortletConfigAware</classname></para></entry>
|
||||
|
||||
<entry><para>Current <interfacename>PortletConfig</interfacename>
|
||||
the container runs in. Valid only in a web-aware Spring
|
||||
<interfacename>ApplicationContext</interfacename></para></entry>
|
||||
|
||||
<entry><para><xref linkend="portlet"/></para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><classname>PortletContextAware</classname></para></entry>
|
||||
|
||||
<entry><para>Current <interfacename>PortletContext</interfacename>
|
||||
the container runs in. Valid only in a web-aware Spring
|
||||
<interfacename>ApplicationContext</interfacename></para></entry>
|
||||
|
||||
<entry><para><xref linkend="portlet"/></para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><classname>ResourceLoaderAware</classname></para></entry>
|
||||
|
||||
<entry><para>Configured loader for low-level access to
|
||||
resources</para></entry>
|
||||
|
||||
<entry><para><xref linkend="resources"/></para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><classname>ServletConfigAware</classname></para></entry>
|
||||
|
||||
<entry><para>Current <interfacename>ServletConfig</interfacename>
|
||||
the container runs in. Valid only in a web-aware Spring
|
||||
<interfacename>ApplicationContext</interfacename></para></entry>
|
||||
|
||||
<entry><para><xref linkend="mvc"/></para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><classname>ServletContextAware</classname></para></entry>
|
||||
|
||||
<entry><para>Current <interfacename>ServletContext</interfacename>
|
||||
the container runs in. Valid only in a web-aware Spring
|
||||
<interfacename>ApplicationContext</interfacename></para></entry>
|
||||
|
||||
<entry><para><xref linkend="mvc"/></para></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<para>Note again that usage of these interfaces ties your code to the Spring
|
||||
API and does not follow the Inversion of Control style. As such, they are
|
||||
recommended for infrastructure beans that require programmatic access to
|
||||
the container.</para>
|
||||
</section>
|
||||
</section>
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,568 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<section xml:id="beans-factory-extension"
|
||||
xmlns="http://docbook.org/ns/docbook" version="5.0"
|
||||
xmlns:xl="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
|
||||
http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd">
|
||||
<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 xml: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 xml: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 a <interfacename>ConfigurableBeanFactory</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>
|
||||
|
||||
<para>Note that if you have beans wired into your <interfacename>BeanPostProcessor</interfacename>
|
||||
using autowiring or <interfacename>@Resource</interfacename> (which may fall back to autowiring),
|
||||
Spring might access unexpected beans when searching for type-matching dependency candidates,
|
||||
and therefore make them ineligible for auto-proxying or other kinds of bean post-processing.
|
||||
For example, if you have a dependency annotated with <interfacename>@Resource</interfacename>
|
||||
where the field/setter name does not directly correspond to the declared name of a bean and
|
||||
no name attribute is used, then Spring will access other beans for matching them by type.</para>
|
||||
</note>
|
||||
|
||||
<para>The following examples show how to write, register, and use
|
||||
<literal>BeanPostProcessors</literal> in an
|
||||
<interfacename>ApplicationContext</interfacename>.</para>
|
||||
|
||||
<section xml: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 any 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.xsd
|
||||
http://www.springframework.org/schema/lang
|
||||
http://www.springframework.org/schema/lang/spring-lang.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
|
||||
BeanPostProcessor 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 xml: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 xml: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 xml: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 xml: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="${jdbc.driverClassName}"/>
|
||||
<property name="url" value="${jdbc.url}"/>
|
||||
<property name="username" value="${jdbc.username}"/>
|
||||
<property name="password" value="${jdbc.password}"/>
|
||||
</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 xml: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>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 xml: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>
|
||||
|
|
@ -1,955 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<section xml:id="beans-java"
|
||||
xmlns="http://docbook.org/ns/docbook" version="5.0"
|
||||
xmlns:xl="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
|
||||
http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd">
|
||||
<title>Java-based container configuration</title>
|
||||
|
||||
<section xml:id="beans-java-basic-concepts">
|
||||
<title>Basic concepts: <literal>@Bean</literal> and <literal>@Configuration</literal></title>
|
||||
|
||||
<sidebar>
|
||||
<title>Full @Configuration vs 'lite' @Beans mode?</title>
|
||||
<para>When <interfacename>@Bean</interfacename> methods are declared within
|
||||
classes that are <emphasis>not</emphasis> annotated with
|
||||
<interfacename>@Configuration</interfacename> they are referred to as being
|
||||
processed in a 'lite' mode. For example, bean methods declared in a
|
||||
<interfacename>@Component</interfacename> or even in a <emphasis>plain old
|
||||
class</emphasis> will be considered 'lite'.</para>
|
||||
<para>Unlike full <interfacename>@Configuration</interfacename>, lite
|
||||
<interfacename>@Bean</interfacename> methods cannot easily declare inter-bean
|
||||
dependencies. Usually one <interfacename>@Bean</interfacename> method should not
|
||||
invoke another <interfacename>@Bean</interfacename> method when operating in
|
||||
'lite' mode.</para>
|
||||
<para>Only using <interfacename>@Bean</interfacename> methods within
|
||||
<interfacename>@Configuration</interfacename> classes is a recommended approach
|
||||
of ensuring that 'full' mode is always used. This will prevent the same
|
||||
<interfacename>@Bean</interfacename> method from accidentally being invoked
|
||||
multiple times and helps to reduce subtle bugs that can be hard to track down
|
||||
when operating in 'lite' mode.</para>
|
||||
</sidebar>
|
||||
|
||||
<para>The central artifacts in Spring's new Java-configuration support are
|
||||
<interfacename>@Configuration</interfacename>-annotated classes and
|
||||
<interfacename>@Bean</interfacename>-annotated methods.</para>
|
||||
<para>The <interfacename>@Bean</interfacename> annotation is used to indicate that a
|
||||
method instantiates, configures and initializes a new object to be managed by
|
||||
the Spring IoC container. For those familiar with Spring's
|
||||
<literal><beans/></literal> XML configuration the <literal>@Bean</literal>
|
||||
annotation plays the same role as the <literal><bean/></literal>
|
||||
element. You can use <interfacename>@Bean</interfacename> annotated methods with
|
||||
any Spring <interfacename>@Component</interfacename>, however, they are most
|
||||
often used with <interfacename>@Configuration</interfacename> beans.</para>
|
||||
<para>Annotating a class with <interfacename>@Configuration</interfacename>
|
||||
indicates that its primary purpose is as a source of bean definitions. Furthermore,
|
||||
<interfacename>@Configuration</interfacename> classes allow inter-bean
|
||||
dependencies to be defined by simply calling other <interfacename>@Bean</interfacename>
|
||||
methods in the same class. 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>The <literal>AppConfig</literal> class above would be equivalent to the
|
||||
following Spring <literal><beans/></literal> XML:
|
||||
<programlisting language="xml"><beans>
|
||||
<bean id="myService" class="com.acme.services.MyServiceImpl"/>
|
||||
</beans></programlisting>
|
||||
The <interfacename>@Bean</interfacename> and <interfacename>@Configuration</interfacename>
|
||||
annotations 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 xml: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 xml: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 xml: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 xml: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 xml: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 xml: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 xml: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 xml:id="beans-java-lifecycle-callbacks">
|
||||
<title>Receiving lifecycle callbacks</title>
|
||||
|
||||
<para>Any classes defined with the
|
||||
<literal>@Bean</literal> annotation support
|
||||
the regular lifecycle callbacks and 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 xml:id="beans-java-specifying-bean-scope">
|
||||
<title>Specifying bean scope</title>
|
||||
|
||||
<section xml: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 xml: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>
|
||||
|
||||
<section xml: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 xml: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 xml:id="beans-java-configuration-annotation">
|
||||
<title>Using the <interfacename>@Configuration</interfacename> annotation</title>
|
||||
<para><interfacename>@Configuration</interfacename> is a class-level annotation
|
||||
indicating that an object is a source of bean definitions.
|
||||
<interfacename>@Configuration</interfacename> classes declare beans via
|
||||
public <interfacename>@Bean</interfacename> annotated methods. Calls to
|
||||
<interfacename>@Bean</interfacename> methods on
|
||||
<interfacename>@Configuration</interfacename> classes can also be used to
|
||||
define inter-bean dependencies. See <xref linkend="beans-java-basic-concepts"/> for
|
||||
a general introduction.</para>
|
||||
|
||||
<section xml:id="beans-java-injecting-dependencies">
|
||||
<title>Injecting inter-bean 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>
|
||||
|
||||
<note>
|
||||
<para>This method of declaring inter-bean dependencies only works when
|
||||
the <interfacename>@Bean</interfacename> method is declared within a
|
||||
<interfacename>@Configuration</interfacename> class. You cannot declare
|
||||
inter-bean dependencies using plain <interfacename>@Component</interfacename>
|
||||
classes.</para>
|
||||
</note>
|
||||
</section>
|
||||
|
||||
<section xml: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 xml: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. Note that as of Spring
|
||||
3.2, it is no longer necessary to add CGLIB to your classpath because
|
||||
CGLIB classes have been repackaged under org.springframework and included
|
||||
directly within the spring-core JAR.</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> 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>
|
||||
|
||||
|
||||
|
||||
|
||||
<section xml:id="beans-java-composing-configuration-classes">
|
||||
<title>Composing Java-based configurations</title>
|
||||
|
||||
<section xml: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 xml: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 xml: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 <link xl:href="http://www.springsource.com/products/sts"
|
||||
>SpringSource Tool Suite</link> 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 xml: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 xml: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 xml: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 xml: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 xml: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>
|
||||
|
|
@ -1,676 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<section xml:id="beans-factory-scopes"
|
||||
xmlns="http://docbook.org/ns/docbook" version="5.0"
|
||||
xmlns:xl="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
|
||||
http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd">
|
||||
<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 xml: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 <link
|
||||
xl:href="http://static.springsource.org/spring/docs/current/api/org/springframework/context/support/SimpleThreadScope.html"
|
||||
>SimpleThreadScope</link>. For instructions on how to register this or
|
||||
any other custom scope, see <xref
|
||||
linkend="beans-factory-scopes-custom-using"/>.</para>
|
||||
</note>
|
||||
|
||||
<section xml: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>
|
||||
<imagedata align="center" fileref="images/singleton.png" format="PNG" width="400" />
|
||||
</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 xml: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>
|
||||
<imagedata align="center" fileref="images/prototype.png" format="PNG" width="400"/>
|
||||
</imageobject>
|
||||
</mediaobject></para>
|
||||
|
||||
<para>The following example defines a bean as a prototype in XML:</para>
|
||||
|
||||
<programlisting language="xml"><lineannotation><!-- using spring-beans-2.0.dtd --></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 xml: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 xml: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 xml: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 xml: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 xml: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 xml: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 xml: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>.</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.xsd
|
||||
http://www.springframework.org/schema/aop
|
||||
http://www.springframework.org/schema/aop/spring-aop.xsd">
|
||||
|
||||
<lineannotation><!-- an HTTP Session-scoped bean exposed as a proxy --></lineannotation>
|
||||
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session">
|
||||
|
||||
<lineannotation><!-- instructs the container to proxy the surrounding bean --></lineannotation>
|
||||
<aop:scoped-proxy/>
|
||||
</bean>
|
||||
|
||||
<lineannotation><!-- a singleton-scoped bean injected with a proxy to the above bean --></lineannotation>
|
||||
<bean id="userService" class="com.foo.SimpleUserService">
|
||||
|
||||
<lineannotation><!-- a reference to the proxied userPreferences 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. 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">
|
||||
<literal><aop:scoped-proxy/></literal>
|
||||
</bean>
|
||||
|
||||
<bean id="userManager" class="com.foo.UserManager">
|
||||
<property name="userPreferences" ref="userPreferences"/>
|
||||
</bean></programlisting>
|
||||
|
||||
<section xml: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>.</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><!-- DefaultUserPreferences implements the UserPreferences interface --></lineannotation>
|
||||
<bean id="userPreferences" class="com.foo.DefaultUserPreferences" scope="session">
|
||||
<aop:scoped-proxy proxy-target-class="false"<literal/>/>
|
||||
</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 xml: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 xml: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 <link
|
||||
xl:href="http://static.springsource.org/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/config/Scope.html"
|
||||
>Scope Javadoc</link>, 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 xml: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("thread", 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.xsd
|
||||
http://www.springframework.org/schema/aop
|
||||
http://www.springframework.org/schema/aop/spring-aop.xsd">
|
||||
|
||||
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
|
||||
<property name="scopes">
|
||||
<map>
|
||||
<entry key="thread">
|
||||
<bean class="org.springframework.context.support.SimpleThreadScope"/>
|
||||
</entry>
|
||||
</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>
|
||||
|
|
@ -1,205 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<section xml:id="beans-standard-annotations"
|
||||
xmlns="http://docbook.org/ns/docbook" version="5.0"
|
||||
xmlns:xl="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
|
||||
http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd">
|
||||
<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
|
||||
(<link xl:href="http://repo1.maven.org/maven2/javax/inject/javax.inject/1/">http://repo1.maven.org/maven2/javax/inject/javax.inject/1/</link>).
|
||||
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 xml: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 xml: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 xml: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 xml: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
|
||||
<link xl:href="http://download.oracle.com/javaee/6/api/javax/inject/Scope.html">@Scope</link> 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>
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,626 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter xml:id="cache"
|
||||
xmlns="http://docbook.org/ns/docbook" version="5.0"
|
||||
xmlns:xl="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
|
||||
http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd">
|
||||
<title>Cache Abstraction</title>
|
||||
|
||||
<section xml: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 xml: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
|
||||
<link xl:href="http://en.wikipedia.org/wiki/Cache#The_difference_between_buffer_and_cache">here</link>.</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 behavior 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><para>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.</para></important>
|
||||
|
||||
<para>To use the cache abstraction, the developer needs to take care of two aspects:
|
||||
<itemizedlist>
|
||||
<listitem><para>caching declaration - identify the methods that need to be cached and their policy</para></listitem>
|
||||
<listitem><para>cache configuration - the backing cache where the data is stored and read from</para></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 <link xl:href="http://ehcache.org/">EhCache</link> - see <xref linkend="cache-plug"/> for more information on plugging in other cache stores/providers.</para>
|
||||
</section>
|
||||
|
||||
<section xml: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 xml: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><para>All the other caches that do not contain the method will be updated as well even though the cached method was not actually
|
||||
executed.</para></note>
|
||||
|
||||
<programlisting language="java"><![CDATA[@Cacheable({ "books", "isbns" })
|
||||
public Book findBook(ISBN isbn) {...}]]></programlisting>
|
||||
|
||||
<section xml: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><para>If no params are given, return 0.</para></listitem>
|
||||
<listitem><para>If only one param is given, return that instance.</para></listitem>
|
||||
<listitem><para>If more the one param is given, return a key computed from the hashes of all parameters.</para></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 does not specify its own key generation strategy (see below).
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section xml: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 xml: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>
|
||||
|
||||
<para>In addition the <literal>conditional</literal> parameter, the <literal>unless</literal> parameter can be used to veto the adding of a value to the cache. Unlike
|
||||
<literal>conditional</literal>, <literal>unless</literal> <literal>SpEL</literal> expressions are evalulated <emphasis>after</emphasis> the method has been called. Expanding
|
||||
on the previous example - perhaps we only want to cache paperback books:</para>
|
||||
|
||||
<programlisting language="java"><![CDATA[@Cacheable(value="book", condition="#name.length < 32", unless="#result.hardback")
|
||||
public Book findBook(String name)]]></programlisting>
|
||||
</section>
|
||||
|
||||
<section xml: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 xml: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>
|
||||
<row>
|
||||
<entry>result</entry>
|
||||
<entry>evaluation context</entry>
|
||||
<entry>The result of the method call (the value to be cached). Only available in '<literal>unless</literal>' expressions and '<literal>cache evict</literal>'
|
||||
expression (when <literal>beforeInvocation</literal> is <literal>false</literal>).</entry>
|
||||
<entry><screen>#result</screen></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section xml:id="cache-annotations-put">
|
||||
<title><literal>@CachePut</literal> annotation</title>
|
||||
|
||||
<para>For cases where the cache needs to be updated without interfering 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 generally discouraged because they have different behaviors. 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 behavior 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 xml: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 xml: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 xml: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).</para>
|
||||
|
||||
<para>To enable caching annotations add the annotation <interfacename>@EnableCaching</interfacename> to one of your <interfacename>@Configuration</interfacename> classes:</para>
|
||||
|
||||
<programlisting language="java">@Configuration
|
||||
@EnableCaching
|
||||
public class AppConfig {
|
||||
}</programlisting>
|
||||
|
||||
<para>Alternatively for XML configuration use the <literal>cache:annotation-driven</literal> element:</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>Both the <literal>cache:annotation-driven</literal> element and <interfacename>@EnableCaching</interfacename> annotation allow various options to be specified that influence the way the
|
||||
caching behavior is added to the application through AOP. The configuration is intentionally similar
|
||||
with that of <link linkend="tx-annotation-driven-settings"><interfacename>@Transactional</interfacename></link>:
|
||||
</para>
|
||||
|
||||
<para><table xml:id="cache-annotation-driven-settings">
|
||||
<title>Cache annotation settings</title>
|
||||
|
||||
<tgroup cols="4">
|
||||
<thead>
|
||||
<row>
|
||||
<entry>XML Attribute</entry>
|
||||
|
||||
<entry>Annotation Attribute</entry>
|
||||
|
||||
<entry>Default</entry>
|
||||
|
||||
<entry>Description</entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><literal>cache-manager</literal></entry>
|
||||
<entry>N/A (See <literal>CachingConfigurer</literal> Javadoc)</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><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><literal>proxyTargetClass</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><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 xml: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
|
||||
mentioned <link linkend="cache-annotation-enable">above</link>, the annotation-driven behavior needs to be enabled.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section xml: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 behavior 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. However through XML, it is easier to apply a package/group/interface-wide caching (again due to the AspectJ pointcut) 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 xml: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 <link xl:href="http://ehcache.org/">EhCache</link> 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 xml: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 <classname>ConcurrentMapCache</classname>
|
||||
instances 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 xml: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 xml:id="cache-store-configuration-gemfire">
|
||||
<title>GemFire-based <interfacename>Cache</interfacename></title>
|
||||
|
||||
<para>GemFire is a memory-oriented/disk-backed, elastically scalable, continuously available, active (with built-in pattern-based subscription notifications),
|
||||
globally replicated database and provides fully-featured edge caching. For further information on how to use GemFire as a CacheManager (and more), please refer
|
||||
to the <link xl:href="http://static.springsource.org/spring-gemfire/docs/1.0.0.RELEASE/reference/html/">Spring GemFire reference documentation</link>.</para>
|
||||
</section>
|
||||
|
||||
<section xml: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="fallbackToNoOpCache" value="true"/>
|
||||
</bean>]]></programlisting>
|
||||
|
||||
<para>The <literal>CompositeCacheManager</literal> above chains multiple <literal>CacheManager</literal>s and additionally, through the <literal>fallbackToNoOpCache</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 xml: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 <link xl:href="http://en.wikipedia.org/wiki/Adapter_pattern">adapter</link>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 xml: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>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -1,458 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<appendix xml:id="classic-spring"
|
||||
xmlns="http://docbook.org/ns/docbook" version="5.0"
|
||||
xmlns:xl="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
|
||||
http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd">
|
||||
<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 xml: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 xml:id="classic-spring-hibernate">
|
||||
<title>Hibernate</title>
|
||||
|
||||
<para>For the currently recommended usage patterns for Hibernate see
|
||||
<xref linkend="orm-hibernate" /></para>
|
||||
|
||||
<section xml: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 xml: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 xml:id="classic-spring-jdo">
|
||||
<title>JDO</title>
|
||||
|
||||
<para>For the currently recommended usage patterns for JDO see <xref
|
||||
linkend="orm-jdo" /></para>
|
||||
|
||||
<section xml: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 xml:id="classic-spring-jpa">
|
||||
<title>JPA</title>
|
||||
|
||||
<para>For the currently recommended usage patterns for JPA see <xref
|
||||
linkend="orm-jpa" /></para>
|
||||
|
||||
<section xml: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 xml:id="clasic-spring-mvc">
|
||||
<title>Classic Spring MVC</title>
|
||||
|
||||
<para>...</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="classic-spring-jms">
|
||||
<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 xml:id="classic-spring-jms-template">
|
||||
<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 xml:id="classic-spring-aysnc-messages">
|
||||
<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 xml:id="classic-spring-jms-connections">
|
||||
<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 xml:id="classic-spring-jms-tx-management">
|
||||
<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>
|
||||
|
|
@ -1,156 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter xml:id="dao"
|
||||
xmlns="http://docbook.org/ns/docbook" version="5.0"
|
||||
xmlns:xl="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
|
||||
http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd">
|
||||
<title>DAO support</title>
|
||||
|
||||
<section xml: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 xml: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" format="PNG" width="400" />
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
</section>
|
||||
|
||||
<section xml: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>
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,313 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter xml:id="ejb"
|
||||
xmlns="http://docbook.org/ns/docbook" version="5.0"
|
||||
xmlns:xl="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
|
||||
http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd">
|
||||
<title>Enterprise JavaBeans (EJB) integration</title>
|
||||
|
||||
<section xml: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 xml:id="ejb-access">
|
||||
<title>Accessing EJBs</title>
|
||||
|
||||
<section xml: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 xml: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 xml: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 xml: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 xml:id="ejb-implementation">
|
||||
<title>Using Spring's EJB implementation support classes</title>
|
||||
|
||||
<section xml: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>
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,492 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<book xml:id="spring-framework-reference"
|
||||
xmlns="http://docbook.org/ns/docbook" version="5.0"
|
||||
xmlns:xl="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
|
||||
http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd">
|
||||
|
||||
<info>
|
||||
<title>Spring Framework Reference Documentation</title>
|
||||
|
||||
<productname>Spring Framework</productname>
|
||||
|
||||
<releaseinfo>${version}</releaseinfo>
|
||||
|
||||
<authorgroup>
|
||||
<author>
|
||||
<personname>
|
||||
<firstname>Rod</firstname>
|
||||
<surname>Johnson</surname>
|
||||
</personname>
|
||||
</author><author>
|
||||
<personname>
|
||||
<firstname>Juergen</firstname>
|
||||
<surname>Hoeller</surname>
|
||||
</personname>
|
||||
</author><author>
|
||||
<personname>
|
||||
<firstname>Keith</firstname>
|
||||
<surname>Donald</surname>
|
||||
</personname>
|
||||
</author><author>
|
||||
<personname>
|
||||
<firstname>Colin</firstname>
|
||||
<surname>Sampaleanu</surname>
|
||||
</personname>
|
||||
</author><author>
|
||||
<personname>
|
||||
<firstname>Rob</firstname>
|
||||
<surname>Harrop</surname>
|
||||
</personname>
|
||||
</author><author>
|
||||
<personname>
|
||||
<firstname>Thomas</firstname>
|
||||
<surname>Risberg</surname>
|
||||
</personname>
|
||||
</author><author>
|
||||
<personname>
|
||||
<firstname>Alef</firstname>
|
||||
<surname>Arendsen</surname>
|
||||
</personname>
|
||||
</author><author>
|
||||
<personname>
|
||||
<firstname>Darren</firstname>
|
||||
<surname>Davison</surname>
|
||||
</personname>
|
||||
</author><author>
|
||||
<personname>
|
||||
<firstname>Dmitriy</firstname>
|
||||
<surname>Kopylenko</surname>
|
||||
</personname>
|
||||
</author><author>
|
||||
<personname>
|
||||
<firstname>Mark</firstname>
|
||||
<surname>Pollack</surname>
|
||||
</personname>
|
||||
</author><author>
|
||||
<personname>
|
||||
<firstname>Thierry</firstname>
|
||||
<surname>Templier</surname>
|
||||
</personname>
|
||||
</author><author>
|
||||
<personname>
|
||||
<firstname>Erwin</firstname>
|
||||
<surname>Vervaet</surname>
|
||||
</personname>
|
||||
</author><author>
|
||||
<personname>
|
||||
<firstname>Portia</firstname>
|
||||
<surname>Tung</surname>
|
||||
</personname>
|
||||
</author><author>
|
||||
<personname>
|
||||
<firstname>Ben</firstname>
|
||||
<surname>Hale</surname>
|
||||
</personname>
|
||||
</author><author>
|
||||
<personname>
|
||||
<firstname>Adrian</firstname>
|
||||
<surname>Colyer</surname>
|
||||
</personname>
|
||||
</author><author>
|
||||
<personname>
|
||||
<firstname>John</firstname>
|
||||
<surname>Lewis</surname>
|
||||
</personname>
|
||||
</author><author>
|
||||
<personname>
|
||||
<firstname>Costin</firstname>
|
||||
<surname>Leau</surname>
|
||||
</personname>
|
||||
</author><author>
|
||||
<personname>
|
||||
<firstname>Mark</firstname>
|
||||
<surname>Fisher</surname>
|
||||
</personname>
|
||||
</author><author>
|
||||
<personname>
|
||||
<firstname>Sam</firstname>
|
||||
<surname>Brannen</surname>
|
||||
</personname>
|
||||
</author><author>
|
||||
<personname>
|
||||
<firstname>Ramnivas</firstname>
|
||||
<surname>Laddad</surname>
|
||||
</personname>
|
||||
</author><author>
|
||||
<personname>
|
||||
<firstname>Arjen</firstname>
|
||||
<surname>Poutsma</surname>
|
||||
</personname>
|
||||
</author><author>
|
||||
<personname>
|
||||
<firstname>Chris</firstname>
|
||||
<surname>Beams</surname>
|
||||
</personname>
|
||||
</author><author>
|
||||
<personname>
|
||||
<firstname>Tareq</firstname>
|
||||
<surname>Abedrabbo</surname>
|
||||
</personname>
|
||||
</author><author>
|
||||
<personname>
|
||||
<firstname>Andy</firstname>
|
||||
<surname>Clement</surname>
|
||||
</personname>
|
||||
</author><author>
|
||||
<personname>
|
||||
<firstname>Dave</firstname>
|
||||
<surname>Syer</surname>
|
||||
</personname>
|
||||
</author><author>
|
||||
<personname>
|
||||
<firstname>Oliver</firstname>
|
||||
<surname>Gierke</surname>
|
||||
</personname>
|
||||
</author><author>
|
||||
<personname>
|
||||
<firstname>Rossen</firstname>
|
||||
<surname>Stoyanchev</surname>
|
||||
</personname>
|
||||
</author><author>
|
||||
<personname>
|
||||
<firstname>Phillip</firstname>
|
||||
<surname>Webb</surname>
|
||||
</personname>
|
||||
</author>
|
||||
</authorgroup>
|
||||
|
||||
<copyright>
|
||||
<year>2004-2013</year>
|
||||
</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>
|
||||
</info>
|
||||
|
||||
<!-- front matter -->
|
||||
|
||||
<toc></toc>
|
||||
|
||||
<part xml:id="spring-introduction">
|
||||
<title>Overview of Spring Framework</title>
|
||||
|
||||
<partintro>
|
||||
<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
|
||||
<link xl:href="http://forum.springsource.org/"></link>.<!-- 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 xml: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" />
|
||||
<xi:include href="new-in-3.2.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
</part>
|
||||
|
||||
<part xml:id="spring-core">
|
||||
<title>Core Technologies</title>
|
||||
|
||||
<partintro>
|
||||
<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 xml:id="spring-data-tier">
|
||||
<title>Data Access</title>
|
||||
|
||||
<partintro xml: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 xml:id="spring-web">
|
||||
<title>The Web</title>
|
||||
|
||||
<partintro>
|
||||
<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 xml:id="spring-integration">
|
||||
<title>Integration</title>
|
||||
|
||||
<partintro>
|
||||
<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>
|
||||
|
||||
<part xml: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="migration-3.1.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
||||
|
||||
<xi:include href="migration-3.2.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="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>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -1,404 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter xml:id="mail"
|
||||
xmlns="http://docbook.org/ns/docbook" version="5.0"
|
||||
xmlns:xl="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
|
||||
http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd">
|
||||
<title>Email</title>
|
||||
|
||||
<section xml: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 <link xl:href="http://java.sun.com/products/javamail/">JavaMail</link> <filename class="libraryfile">mail.jar</filename> library</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>The <link xl:href="http://java.sun.com/products/javabeans/jaf/downloads/index.html">JAF</link> <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 xml: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 xml: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 xml: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 xml: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 xml: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 xml: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 xml: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 xml: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 xml:id="mail-templates-example">
|
||||
<title>A Velocity-based example</title>
|
||||
<para>To use <link xl:href="http://velocity.apache.org">Velocity</link> 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 com/foo/package</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.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>
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<appendix xml:id="migration-3.1"
|
||||
xmlns="http://docbook.org/ns/docbook" version="5.0"
|
||||
xmlns:xl="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
|
||||
http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd">
|
||||
<title>Migrating to Spring Framework 3.1</title>
|
||||
|
||||
<para>In this appendix we discuss what users will want to know when upgrading to
|
||||
Spring Framework 3.1. For a general overview of features, please see
|
||||
<xref linkend="new-in-3.1"/></para>
|
||||
|
||||
<section xml:id="migration-3.1-component-scan">
|
||||
<title>Component scanning against the "org" base package</title>
|
||||
<para>Spring Framework 3.1 introduces a number of <literal>@Configuration</literal>
|
||||
classes such as <literal>org.springframework.cache.annotation.ProxyCachingConfiguration
|
||||
</literal> and
|
||||
<literal>org.springframework.scheduling.annotation.ProxyAsyncConfiguration</literal>.
|
||||
Because <literal>@Configuration</literal> is ultimately meta-annotated with Spring's
|
||||
<literal>@Component</literal> annotation, these classes will inadvertently be scanned
|
||||
and processed by the container for any component-scanning directive against the
|
||||
unqualified "org" package, e.g.:
|
||||
<programlisting language="xml">
|
||||
<context:component-scan base-package="org"/></programlisting>
|
||||
Therefore, in order to avoid errors like the one reported in <link
|
||||
xl:href="https://jira.springsource.org/browse/SPR-9843">SPR-9843</link>,
|
||||
any such directives should be updated to at least one more level of qualification e.g.:
|
||||
<programlisting language="xml">
|
||||
<context:component-scan base-package="org.xyz"/></programlisting>
|
||||
Alternatively, an <literal>exclude-filter</literal> may be used. See
|
||||
<link linkend="beans-scanning-filters"><literal>context:component-scan</literal></link>
|
||||
documentation for details.</para>
|
||||
</section>
|
||||
</appendix>
|
||||
|
|
@ -1,357 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<appendix xml:id="migration-3.2"
|
||||
xmlns="http://docbook.org/ns/docbook" version="5.0"
|
||||
xmlns:xl="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
|
||||
http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd">
|
||||
<title>Migrating to Spring Framework 3.2</title>
|
||||
|
||||
<para>In this appendix we discuss what users will want to know when upgrading to
|
||||
Spring Framework 3.2. For a general overview of features, please see
|
||||
<xref linkend="new-in-3.2"/></para>
|
||||
|
||||
<section xml:id="migration-3.2-new-optional-deps">
|
||||
<title>Newly optional dependencies</title>
|
||||
<para>Certain inter-module dependencies are now <literal>optional</literal> at the
|
||||
Maven POM level where they were once required. For example, <literal>spring-tx</literal>
|
||||
and its dependence on <literal>spring-context</literal>. This may result in <literal>
|
||||
ClassNotFoundErrors</literal> or other similar problems for users that have been relying
|
||||
on transitive dependency management to pull in affected downstream <literal>spring-*
|
||||
</literal>. To resolve this problem, simply add the appropriate missing jars to your
|
||||
build configuration.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="migration-3.2-ehcache-support">
|
||||
<title>EHCache support moved to spring-context-support</title>
|
||||
<para>Along with Spring's new JCache support, the EHCache support classes in the
|
||||
<literal>org.springframework.cache.ehcache</literal> package moved from the
|
||||
<literal>spring-context</literal> module to <literal>spring-context-support</literal>.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="migration-3.2-inline-asm">
|
||||
<title>Inlining of spring-asm jar</title>
|
||||
<para>In versions 3.0 and 3.1, we published a discrete <literal>spring-asm</literal>
|
||||
containing repackaged <literal>org.objectweb.asm</literal> 3.x sources. As of Spring
|
||||
Framework 3.2, we have upgraded to <literal>org.objectweb.asm</literal> 4.0 and done
|
||||
away with the separate module jar, favoring inlining these classes directly within
|
||||
<literal>spring-core</literal>. This should cause no migration issue for most users;
|
||||
but on the off chance that you have <literal>spring-asm</literal> declared directly
|
||||
within your project's build script, you'll want to remove it when upgrading to
|
||||
Spring Framework 3.2.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="migration-3.2-inline-cglib">
|
||||
<title>Explicit CGLIB dependency no longer required</title>
|
||||
<para>In prior versions, users of Spring's subclass-based AOP proxies (e.g. via
|
||||
<literal>proxy-target-class="true"</literal>) and <literal>@Configuration</literal>
|
||||
class support were required to declare an explicit dependency on CGLIB 2.2. As of
|
||||
Spring Framework 3.2, we now repackage and inline the newly-released CGLIB 3.0.</para>
|
||||
<para>This means greater convenience for users, as well as correct functionality for
|
||||
Java 7 users who are creating subclass proxies of types that contain <literal>
|
||||
invokedynamic</literal> bytecode instructions. Repackaging CGLIB internally ensures
|
||||
no classpath conflicts with other third party frameworks that may depend on other
|
||||
versions of CGLIB.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="migration-3.2-osgi-users">
|
||||
<title>For OSGi users</title>
|
||||
<para>OSGi metadata is no longer published within individual Spring Framework
|
||||
jar MANIFEST.MF files. Please see this
|
||||
<link xl:href="http://www.springsource.org/springframework-ebr">announcement</link>
|
||||
for more information about how users can get OSGi-ready versions of Spring
|
||||
Framework 3.2 jars.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="migration-3.2-compatibility-mvc-config">
|
||||
<title>MVC Java Config and MVC Namespace</title>
|
||||
|
||||
<para>As explained in <xref linkend="mvc-config-content-negotiation"/>, both
|
||||
the MVC Java config and the MVC namespace register extensions such as
|
||||
<filename>.json</filename> and <filename>.xml</filename> if the
|
||||
corresponding classpath dependencies are present. That means controller
|
||||
methods may now return JSON or XML formatted content if those
|
||||
extensions are present in the request URI,
|
||||
even if the 'Accept' header doesn't request those media types.</para>
|
||||
|
||||
<para>The newly added support for matrix variables is explained in
|
||||
<xref linkend="mvc-ann-matrix-variables"/>. To preserve backward
|
||||
compatibility, by default, semicolon content is removed from incoming
|
||||
request URIs and therefore <interfacename>@MatrixVariable</interfacename>
|
||||
cannot be used without additional configuration. However, when using
|
||||
the MVC Java config and the MVC namespace, semicolon content is left
|
||||
in the URI so that matrix variables are automatically supported.
|
||||
The removal of semicolon content is controlled through the
|
||||
<classname>UrlPathHelper</classname> property of
|
||||
<classname>RequestMappingHandlerMapping</classname>.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="migration-3.2-compatibility-uri-variable-values">
|
||||
<title>Decoding of URI Variable Values</title>
|
||||
<para>URI variable values now get decoded when
|
||||
<code>UrlPathHelper.setUrlDecode</code> is set to <code>false</code>.
|
||||
See <link xl:href="https://jira.springsource.org/browse/SPR-9098">SPR-9098</link>.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="migration-3.2-compatibility-http-patch">
|
||||
<title>HTTP PATCH method</title>
|
||||
<para>The <classname>DispatcherServlet</classname> now allows the
|
||||
HTTP PATCH method where previously it didn't.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="migration-3.2-compatibility-tiles3">
|
||||
<title>Tiles 3</title>
|
||||
|
||||
<para>Besides the version number change, the set of Tiles
|
||||
dependencies has also changed. You will need to have a subset or all of
|
||||
<filename>tiles-request-api</filename>, <filename>tiles-api</filename>,
|
||||
<filename>tiles-core</filename>, <filename>tiles-servlet</filename>,
|
||||
<filename>tiles-jsp</filename>, <filename>tiles-el</filename>.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="migration-3.2-compatibility-spring-mvc-test">
|
||||
<title>Spring MVC Test standalone project</title>
|
||||
|
||||
<para>If migrating from the
|
||||
<link xl:href="https://github.com/SpringSource/spring-test-mvc">spring-test-mvc</link>
|
||||
standalone project to the <filename>spring-test</filename> module in
|
||||
Spring Framework 3.2, you will need to adjust the root package
|
||||
to be <classname>org.springframework.test.web.servlet</classname>.</para>
|
||||
|
||||
<para>You will no longer be able to use the
|
||||
<classname>MockMvcBuilders</classname> <code>annotationConfigSetup</code>
|
||||
and <code>xmlConfigSetup</code> options. Instead you'll need to switch
|
||||
to using the <interfacename>@WebAppConfiguration</interfacename> support
|
||||
of <filename>spring-test</filename> for loading Spring configuration,
|
||||
then inject a <interfacename>WebApplicationContext</interfacename> into
|
||||
the test and use it to create a <classname>MockMvc</classname>. See
|
||||
<xref linkend="spring-mvc-test-framework" /> for details.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="migration-3.2-compatibility-spring-test">
|
||||
<title>Spring Test Dependencies</title>
|
||||
|
||||
<para>The <literal>spring-test</literal> module has been upgraded to
|
||||
depend on JUnit 4.11 (<literal>junit:junit</literal>), TestNG 6.5.2
|
||||
(<literal>org.testng:testng</literal>), and Hamcrest Core 1.3
|
||||
(<literal>org.hamcrest:hamcrest-core</literal>). Each of these
|
||||
dependencies is declared as an <emphasis>optional</emphasis> dependency in
|
||||
the Maven POM. Furthermore, it is important to note that the JUnit team
|
||||
has stopped inlining Hamcrest Core within the
|
||||
<literal>junit:junit</literal> Maven artifact as of JUnit 4.11. Hamcrest
|
||||
Core is now a <emphasis>required</emphasis> transitive dependency of
|
||||
<literal>junit</literal>, and users may therefore need to remove any
|
||||
exclusions on <literal>hamcrest-core</literal> that they had previously
|
||||
configured for their build.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="migration-3.2-changes">
|
||||
<title>Public API changes</title>
|
||||
|
||||
<section xml:id="migration-3.2-api-changes">
|
||||
<title>JDiff reports</title>
|
||||
<para>
|
||||
Select JDiff reports are now being published to provide users with a convenient
|
||||
means of understanding what's changed between versions. Going forward these will be
|
||||
published between each minor version, e.g. from 3.1.3.RELEASE to 3.1.4.RELEASE; from
|
||||
the latest maintenance version to the latest GA release, e.g.
|
||||
<link xl:href="http://static.springsource.org/spring-framework/docs/3.1.3.RELEASE_to_3.2.0.RELEASE">
|
||||
3.1.3.RELEASE to 3.2.0.RELEASE</link>; and in between each milestone
|
||||
and/or RC for users who are tracking next-generation development, e.g.
|
||||
<link xl:href="http://static.springsource.org/spring-framework/docs/3.2.0.RC2_to_3.2.0.RELEASE">
|
||||
3.2.0.RC2 to 3.2.0.RELEASE</link>.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="migration-3.2-removals-and-deprecations">
|
||||
<title>Deprecations</title>
|
||||
<para>The following packages and types have been wholly or partially deprecated
|
||||
in Spring Framework 3.2 and may be removed in a future version. Click through
|
||||
to the linked Javadoc for each item for exact details. See also the
|
||||
<link xl:href="http://static.springsource.org/spring-framework/docs/3.2.0.RELEASE/javadoc-api/deprecated-list.html">
|
||||
complete list of deprecations</link> in the framework.</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<link xl:href="http://static.springsource.org/spring-framework/docs/3.2.0.RELEASE/javadoc-api/org/springframework/orm/ibatis/package-summary.html">
|
||||
org.springframework.orm.ibatis</link>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<link xl:href="http://static.springsource.org/spring-framework/docs/3.2.0.RELEASE/javadoc-api/org/springframework/scheduling/backportconcurrent/package-summary.html">
|
||||
org.springframework.scheduling.backportconcurrent</link>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<link xl:href="http://static.springsource.org/spring-framework/docs/3.2.0.RELEASE/javadoc-api/org/springframework/ejb/support/package-summary.html">
|
||||
org.springframework.ejb.support</link>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<link xl:href="http://static.springsource.org/spring-framework/docs/3.2.0.RELEASE/javadoc-api/org/springframework/http/converter/xml/XmlAwareFormHttpMessageConverter.html">
|
||||
org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter</link>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<link xl:href="http://static.springsource.org/spring-framework/docs/3.2.0.RELEASE/javadoc-api/org/springframework/web/jsf/DelegatingVariableResolver.html">
|
||||
org.springframework.web.jsf.DelegatingVariableResolver</link>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<link xl:href="http://static.springsource.org/spring-framework/docs/3.2.0.RELEASE/javadoc-api/org/springframework/web/jsf/SpringBeanVariableResolver.html">
|
||||
org.springframework.web.jsf.SpringBeanVariableResolver</link>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<link xl:href="http://static.springsource.org/spring-framework/docs/3.2.0.RELEASE/javadoc-api/org/springframework/ui/velocity/CommonsLoggingLogSystem.html">
|
||||
org.springframework.ui.velocity.CommonsLoggingLogSystem</link>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<link xl:href="http://static.springsource.org/spring-framework/docs/3.2.0.RELEASE/javadoc-api/org/springframework/ui/velocity/VelocityEngineUtils.html">
|
||||
org.springframework.ui.velocity.VelocityEngineUtils</link>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<link xl:href="http://static.springsource.org/spring-framework/docs/3.2.0.RELEASE/javadoc-api/org/springframework/beans/factory/config/BeanReferenceFactoryBean.html">
|
||||
org.springframework.beans.factory.config.BeanReferenceFactoryBean</link>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<link xl:href="http://static.springsource.org/spring-framework/docs/3.2.0.RELEASE/javadoc-api/org/springframework/beans/factory/config/CommonsLogFactoryBean.html">
|
||||
org.springframework.beans.factory.config.CommonsLogFactoryBean</link>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<link xl:href="http://static.springsource.org/spring-framework/docs/3.2.0.RELEASE/javadoc-api/org/springframework/instrument/classloading/oc4j/OC4JLoadTimeWeaver.html">
|
||||
org.springframework.beans.instrument.classloading.oc4j.OC4JLoadTimeWeaver</link>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<link xl:href="http://static.springsource.org/spring-framework/docs/3.2.0.RELEASE/javadoc-api/org/springframework/transaction/jta/OC4JJtaTransactionManager.html">
|
||||
org.springframework.transaction.jta.OC4JJtaTransactionManager</link>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<link xl:href="http://static.springsource.org/spring-framework/docs/3.2.0.RELEASE/javadoc-api/org/springframework/web/util/ExpressionEvaluationUtils.html">
|
||||
org.springframework.web.util.ExpressionEvaluationUtils</link>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<link xl:href="http://static.springsource.org/spring-framework/docs/3.2.0.RELEASE/javadoc-api/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.html">
|
||||
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter</link>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<link xl:href="http://static.springsource.org/spring-framework/docs/3.2.0.RELEASE/javadoc-api/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerExceptionResolver.html">
|
||||
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver</link>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<link xl:href="http://static.springsource.org/spring-framework/docs/3.2.0.RELEASE/javadoc-api/org/springframework/web/servlet/mvc/annotation/DefaultAnnotationHandlerMapping.html">
|
||||
org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping</link>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<link xl:href="http://static.springsource.org/spring-framework/docs/3.2.0.RELEASE/javadoc-api/org/springframework/web/servlet/mvc/annotation/ServletAnnotationMappingUtils.html">
|
||||
org.springframework.web.servlet.mvc.annotation.ServletAnnotationMappingUtils</link>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<link xl:href="http://static.springsource.org/spring-framework/docs/3.2.0.RELEASE/javadoc-api/org/springframework/jmx/support/MBeanRegistrationSupport.html">
|
||||
org.springframework.jmx.support.MBeanRegistrationSupport</link>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<link xl:href="http://static.springsource.org/spring-framework/docs/3.2.0.RELEASE/javadoc-api/org/springframework/test/context/ContextConfigurationAttributes.html">
|
||||
org.springframework.test.context.ContextConfigurationAttributes</link>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<link xl:href="http://static.springsource.org/spring-framework/docs/3.2.0.RELEASE/javadoc-api/org/springframework/test/context/junit4/AbstractTransactionalJUnit4SpringContextTests.html">
|
||||
org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests</link>:
|
||||
use of the <varname>simpleJdbcTemplate</varname> instance variable has been deprecated
|
||||
in favor of the new <varname>jdbcTemplate</varname> instance variable.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<link xl:href="http://static.springsource.org/spring-framework/docs/3.2.0.RELEASE/javadoc-api/org/springframework/test/context/testng/AbstractTransactionalTestNGSpringContextTests.html">
|
||||
org.springframework.test.context.testng.AbstractTransactionalTestNGSpringContextTests</link>:
|
||||
use of the <varname>simpleJdbcTemplate</varname> instance variable has been deprecated
|
||||
in favor of the new <varname>jdbcTemplate</varname> instance variable.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<link xl:href="http://static.springsource.org/spring-framework/docs/3.2.0.RELEASE/javadoc-api/org/springframework/test/jdbc/SimpleJdbcTestUtils.html">
|
||||
org.springframework.test.jdbc.SimpleJdbcTestUtils</link> has been deprecated in
|
||||
favor of <classname>JdbcTestUtils</classname> which now contains all of the
|
||||
functionality previously available in <classname>SimpleJdbcTestUtils</classname>.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<link xl:href="http://static.springsource.org/spring-framework/docs/3.2.0.RELEASE/javadoc-api/org/springframework/web/servlet/view/ContentNegotiatingViewResolver.html">
|
||||
org.springframework.web.servlet.view.ContentNegotiatingViewResolver</link>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<link xl:href="http://static.springsource.org/spring-framework/docs/3.2.0.RELEASE/javadoc-api/org/springframework/transaction/interceptor/TransactionAspectUtils.html">
|
||||
org.springframework.transaction.interceptor.TransactionAspectUtils</link>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<link xl:href="http://static.springsource.org/spring-framework/docs/3.2.0.RELEASE/javadoc-api/org/springframework/http/HttpStatus.html">
|
||||
org.springframework.http.HttpStatus</link>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<link xl:href="http://static.springsource.org/spring-framework/docs/3.2.0.RELEASE/javadoc-api/org/springframework/web/util/UriUtils.html">
|
||||
org.springframework.web.util.UriUtils</link>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<link xl:href="http://static.springsource.org/spring-framework/docs/3.2.0.RELEASE/javadoc-api/org/springframework/orm/jpa/vendor/TopLinkJpaDialect.html">
|
||||
org.springframework.orm.jpa.vendor.TopLinkJpaDialect</link>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<link xl:href="http://static.springsource.org/spring-framework/docs/3.2.0.RELEASE/javadoc-api/org/springframework/orm/jpa/vendor/TopLinkJpaVendorAdapter.html">
|
||||
org.springframework.orm.jpa.vendor.TopLinkJpaVendorAdapter</link>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<link xl:href="http://static.springsource.org/spring-framework/docs/3.2.0.RELEASE/javadoc-api/org/springframework/util/CachingMapDecorator.html">
|
||||
org.springframework.orm.util.CachingMapDecorator</link>
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
</section>
|
||||
</appendix>
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,522 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter xml:id="new-in-3.0"
|
||||
xmlns="http://docbook.org/ns/docbook" version="5.0"
|
||||
xmlns:xl="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
|
||||
http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd">
|
||||
<title>New Features and Enhancements in Spring Framework 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 Framework 3.0.</para>
|
||||
|
||||
<sidebar xml: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 xml: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 xml: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 Framework
|
||||
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 <link xl:href="http://jira.springframework.org/">raising an
|
||||
issue</link>.</para>
|
||||
</section>
|
||||
|
||||
<section xml: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 Framework 3 features. Read them at the
|
||||
<link xl:href="http://www.springsource.org/documentation">Spring Documentation</link> page.
|
||||
</para>
|
||||
<para xml:id="new-in-3.0-samples">
|
||||
The samples have been improved and updated to take advantage of the new features in Spring
|
||||
Framework 3. Additionally, the samples have been moved out of the source tree into a dedicated SVN
|
||||
<link xl:href="https://anonsvn.springframework.org/svn/spring-samples/">repository</link> 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
|
||||
Framework 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><para>For more information on Subversion (or in short SVN), see the project homepage at:
|
||||
<literal>http://subversion.apache.org/</literal></para>
|
||||
</note>
|
||||
|
||||
</section>
|
||||
|
||||
<section xml: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 xml: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 xml:id="new-in-3.0-features-overview">
|
||||
<title>Overview of new features</title>
|
||||
|
||||
<para>This is a list of new features for Spring Framework 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 xml: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 xml: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 <link xl:href="http://www.springsource.com/products/sts">SpringSource
|
||||
Tool Suite</link>.</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 xml:id="new-feature-java-config">
|
||||
<title>The Inversion of Control (IoC) container</title>
|
||||
|
||||
<section xml:id="new-java-configuration">
|
||||
<title>Java based bean metadata</title>
|
||||
|
||||
<para>Some core features from the <link
|
||||
xl:href="http://www.springsource.org/javaconfig">JavaConfig</link>
|
||||
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 xml:id="new-bean-metadata-in-components">
|
||||
<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 xml: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 xml: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 xml: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 xml:id="new-feature-rest-support">
|
||||
<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 xml:id="new-feature-at-mvc">
|
||||
<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 xml: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 xml: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 xml: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>
|
||||
|
|
@ -1,509 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter xml:id="new-in-3.1"
|
||||
xmlns="http://docbook.org/ns/docbook" version="5.0"
|
||||
xmlns:xl="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
|
||||
http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd">
|
||||
<title>New Features and Enhancements in Spring Framework 3.1</title>
|
||||
|
||||
<para>This is a list of new features for Spring Framework 3.1. A number of features
|
||||
do not have dedicated reference documentation but do have complete Javadoc. In such
|
||||
cases, fully-qualified class names are given. See also <xref linkend="migration-3.1"/>
|
||||
</para>
|
||||
|
||||
<section xml:id="new-in-3.1-cache-abstraction">
|
||||
<title>Cache Abstraction</title>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><xref linkend="cache" /></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><link
|
||||
xl:href="http://blog.springsource.com/2011/02/23/spring-3-1-m1-caching/">
|
||||
Cache Abstraction</link> (SpringSource team blog)</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section xml:id="new-in-3.1-bean-definition-profiles">
|
||||
<title>Bean Definition Profiles</title>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><link
|
||||
xl:href="http://blog.springsource.com/2011/02/11/spring-framework-3-1-m1-released/">
|
||||
XML profiles</link> (SpringSource Team Blog)</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><link
|
||||
xl:href="http://blog.springsource.com/2011/02/14/spring-3-1-m1-introducing-profile/">
|
||||
Introducing @Profile</link> (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 xml:id="new-in-3.1-environment-abstraction">
|
||||
<title>Environment Abstraction</title>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><link
|
||||
xl:href="http://blog.springsource.com/2011/02/11/spring-framework-3-1-m1-released/">
|
||||
Environment Abstraction</link> (SpringSource Team Blog)</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>See org.springframework.core.env.Environment Javadoc</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section xml:id="new-in-3.1-property-source-abstraction">
|
||||
<title>PropertySource Abstraction</title>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><link
|
||||
xl:href="http://blog.springsource.com/2011/02/15/spring-3-1-m1-unified-property-management/">
|
||||
Unified Property Management</link> (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 xml:id="new-in-3.1-code-equivalent-xml-namespaces">
|
||||
<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 Framework 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 xml:id="new-in-3.1-hibernate-4-support">
|
||||
<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 xml:id="new-in-3.1-test-context-profiles">
|
||||
<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><link
|
||||
xl:href="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</link>
|
||||
(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 xml:id="new-in-3.1-c-namespace">
|
||||
<title>c: namespace for more concise constructor injection</title>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><xref linkend="beans-c-namespace" /></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section xml:id="new-in-3.1-injection-non-javabeans-setters">
|
||||
<title>Support for injection against non-standard JavaBeans
|
||||
setters</title>
|
||||
|
||||
<para>Prior to Spring Framework 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 xml:id="new-in-3.1-servlet-3-code-config">
|
||||
<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><link xl:href="http://bit.ly/lrDHja">Diff from Spring's
|
||||
Greenhouse reference application</link> demonstrating migration
|
||||
from web.xml to
|
||||
<interfacename>WebApplicationInitializer</interfacename></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section xml:id="new-in-3.1-servlet-3-multipart-resolver">
|
||||
<title>Support for Servlet 3 MultipartResolver</title>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>See
|
||||
org.springframework.web.multipart.support.StandardServletMultipartResolver
|
||||
Javadoc</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section xml:id="new-in-3.1-jpa-without-xml">
|
||||
<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 Framework
|
||||
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 xml:id="new-in-3.1-handler-method-controller-processing">
|
||||
<title>New HandlerMethod-based Support Classes For Annotated Controller
|
||||
Processing</title>
|
||||
|
||||
<para>Spring Framework 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
|
||||
<interfacename>@RequestMapping</interfacename> 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 <interfacename>@EnableWebMvc</interfacename>. The
|
||||
existing classes will continue to be available but use of the new
|
||||
classes is recommended going forward.</para>
|
||||
|
||||
<para>See <xref linkend="mvc-ann-requestmapping-31-vs-30"/> for additional
|
||||
details and a list of features not available with the new support classes.</para>
|
||||
|
||||
</section>
|
||||
|
||||
<section xml:id="new-in-3.1-request-mapping-consumes-produces">
|
||||
<title>"consumes" and "produces" conditions in
|
||||
<interfacename>@RequestMapping</interfacename></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 xml:id="new-in-3.1-flash-redirect-attributes">
|
||||
<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 xml:id="new-in-3.1-uri-template-var-enhancements">
|
||||
<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 xml:id="new-in-3.1-mvc-valid-requestbody">
|
||||
<title><interfacename>@Valid</interfacename> On
|
||||
<interfacename>@RequestBody</interfacename> Controller Method Arguments</title>
|
||||
|
||||
<para>An <interfacename>@RequestBody</interfacename> method argument can be
|
||||
annotated with <interfacename>@Valid</interfacename> to invoke automatic
|
||||
validation similar to the support for
|
||||
<interfacename>@ModelAttribute</interfacename> 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 xml:id="new-in-3.1-mvc-requestpart">
|
||||
<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 xml:id="new-in-3.1-mvc-uricomponentsbuilder">
|
||||
<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 new <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>
|
||||
</chapter>
|
||||
|
|
@ -1,328 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter version="5.0"
|
||||
xsi:schemaLocation="http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd"
|
||||
xml:id="new-in-3.2" xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:xl="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xmlns:ns="http://docbook.org/ns/docbook">
|
||||
<title>New Features and Enhancements in Spring Framework 3.2</title>
|
||||
|
||||
<para>This section covers what's new in Spring Framework 3.2. See also
|
||||
<xref linkend="migration-3.2"/></para>
|
||||
|
||||
<section xml:id="new-in-3.2-webmvc-async">
|
||||
<title>Support for Servlet 3 based asynchronous request processing</title>
|
||||
|
||||
<para>The Spring MVC programming model now provides explicit Servlet 3
|
||||
async support. <interfacename>@RequestMapping</interfacename> methods can
|
||||
return one of:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><interfacename>java.util.concurrent.Callable</interfacename> to
|
||||
complete processing in a separate thread managed by a task executor
|
||||
within Spring MVC.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><classname>org.springframework.web.context.request.async.DeferredResult</classname>
|
||||
to complete processing at a later time from a thread not known to
|
||||
Spring MVC — for example, in response to some external event (JMS,
|
||||
AMQP, etc.)</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><classname>org.springframework.web.context.request.async.AsyncTask</classname>
|
||||
to wrap a <interfacename>Callable</interfacename> and customize the
|
||||
timeout value or the task executor to use.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>See <xref linkend="mvc-ann-async"/>.</para>
|
||||
|
||||
</section>
|
||||
|
||||
<section xml:id="new-in-3.2-spring-mvc-test">
|
||||
<title>Spring MVC Test framework</title>
|
||||
|
||||
<para>First-class support for testing Spring MVC applications with a
|
||||
fluent API and without a Servlet container. Server-side tests involve use
|
||||
of the <classname>DispatcherServlet</classname> while client-side REST
|
||||
tests rely on the <classname>RestTemplate</classname>. See <xref
|
||||
linkend="spring-mvc-test-framework" />.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="new-in-3.2-webmvc-content-negotiation">
|
||||
<title>Content negotiation improvements</title>
|
||||
|
||||
<para>A <interfacename>ContentNegotiationStrategy</interfacename> is now
|
||||
available for resolving the requested media types from an incoming
|
||||
request. The available implementations are based on the file extension,
|
||||
query parameter, the 'Accept' header, or a fixed content type.
|
||||
Equivalent options were previously available only in the
|
||||
ContentNegotiatingViewResolver but are now available throughout.</para>
|
||||
|
||||
<para><classname>ContentNegotiationManager</classname> is the central
|
||||
class to use when configuring content negotiation options.
|
||||
For more details see <xref linkend="mvc-config-content-negotiation" />.</para>
|
||||
|
||||
<para>The introduction of <classname>ContentNegotiationManger</classname>
|
||||
also enables selective suffix pattern matching for incoming requests.
|
||||
For more details, see the Javadoc of
|
||||
<link
|
||||
xl:href="http://static.springsource.org/spring-framework/docs/3.2.0.BUILD-SNAPSHOT/api/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMapping.html#setUseRegisteredSuffixPatternMatch(boolean)">RequestMappingHandlerMapping.setUseRegisteredSuffixPatternMatch</link>.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="new-in-3.2-webmvc-controller-advice">
|
||||
<title><interfacename>@ControllerAdvice</interfacename> annotation</title>
|
||||
|
||||
<para>Classes annotated with
|
||||
<interfacename>@ControllerAdvice</interfacename> can contain
|
||||
<interfacename>@ExceptionHandler</interfacename>,
|
||||
<interfacename>@InitBinder</interfacename>, and
|
||||
<interfacename>@ModelAttribute</interfacename> methods and those will
|
||||
apply to <interfacename>@RequestMapping</interfacename> methods across
|
||||
controller hierarchies as opposed to the controller hierarchy within which
|
||||
they are declared. <interfacename>@ControllerAdvice</interfacename> is a
|
||||
component annotation allowing implementation classes to be auto-detected
|
||||
through classpath scanning.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="new-in-3.2-matrix-variables">
|
||||
<title>Matrix variables</title>
|
||||
|
||||
<para>A new <interfacename>@MatrixVariable</interfacename> annotation adds
|
||||
support for extracting matrix variables from the request URI. For more
|
||||
details see <xref linkend="mvc-ann-matrix-variables" />.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="new-in-3.2-dispatcher-servlet-initializer">
|
||||
<title>Abstract base class for code-based Servlet 3+ container
|
||||
initialization</title>
|
||||
|
||||
<para>An abstract base class implementation of the
|
||||
<interfacename>WebApplicationInitializer</interfacename> interface is
|
||||
provided to simplify code-based registration of a DispatcherServlet and
|
||||
filters mapped to it. The new class is named
|
||||
<classname>AbstractDispatcherServletInitializer</classname> and its
|
||||
sub-class
|
||||
<classname>AbstractAnnotationConfigDispatcherServletInitializer</classname>
|
||||
can be used with Java-based Spring configuration. For more details see
|
||||
<xref linkend="mvc-container-config" />.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="new-in-3.2-webmvc-exception-handler-support">
|
||||
<title><classname>ResponseEntityExceptionHandler</classname> class</title>
|
||||
|
||||
<para>A convenient base class with an
|
||||
<interfacename>@ExceptionHandler</interfacename> method that handles
|
||||
standard Spring MVC exceptions and returns a
|
||||
<classname>ResponseEntity</classname> that allowing customizing and
|
||||
writing the response with HTTP message converters. This serves as an
|
||||
alternative to the <classname>DefaultHandlerExceptionResolver</classname>,
|
||||
which does the same but returns a <classname>ModelAndView</classname>
|
||||
instead.</para>
|
||||
|
||||
<para>See the revised <xref linkend="mvc-exceptionhandlers" /> including
|
||||
information on customizing the default Servlet container error
|
||||
page.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="new-in-3.2-webmvc-generic-types-rest-template">
|
||||
<title>Support for generic types in the
|
||||
<classname>RestTemplate</classname> and in
|
||||
<interfacename>@RequestBody</interfacename> arguments</title>
|
||||
|
||||
<para>The <classname>RestTemplate</classname> can now read an HTTP
|
||||
response to a generic type (e.g. <code>List<Account></code>). There
|
||||
are three new <code>exchange()</code> methods that accept
|
||||
<classname>ParameterizedTypeReference</classname>, a new class that
|
||||
enables capturing and passing generic type info.</para>
|
||||
|
||||
<para>In support of this feature, the
|
||||
<interfacename>HttpMessageConverter</interfacename> is extended by
|
||||
<interfacename>GenericHttpMessageConverter</interfacename> adding a method
|
||||
for reading content given a specified parameterized type. The new
|
||||
interface is implemented by the
|
||||
<classname>MappingJacksonHttpMessageConverter</classname> and also by a
|
||||
new <classname>Jaxb2CollectionHttpMessageConverter</classname> that can
|
||||
read read a generic <interfacename>Collection</interfacename> where the
|
||||
generic type is a JAXB type annotated with
|
||||
<interfacename>@XmlRootElement</interfacename> or
|
||||
<interfacename>@XmlType</interfacename>.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="new-in-3.2-webmvc-jackson-json">
|
||||
<title>Jackson JSON 2 and related improvements</title>
|
||||
|
||||
<para>The Jackson JSON 2 library is now supported. Due to packaging
|
||||
changes in the Jackson library, there are separate classes in Spring MVC
|
||||
as well. Those are
|
||||
<classname>MappingJackson2HttpMessageConverter</classname> and
|
||||
<classname>MappingJackson2JsonView</classname>. Other related
|
||||
configuration improvements include support for pretty printing as well as
|
||||
a <classname>JacksonObjectMapperFactoryBean</classname> for convenient
|
||||
customization of an <classname>ObjectMapper</classname> in XML
|
||||
configuration.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="new-in-3.2-webmvc-tiles3">
|
||||
<title>Tiles 3</title>
|
||||
|
||||
<para>Tiles 3 is now supported in addition to Tiles 2.x. Configuring
|
||||
it should be very similar to the Tiles 2 configuration, i.e. the
|
||||
combination of <classname>TilesConfigurer</classname>,
|
||||
<classname>TilesViewResolver</classname> and <classname>TilesView</classname>
|
||||
except using the <code>tiles3</code> instead of the <code>tiles2</code>
|
||||
package.</para>
|
||||
|
||||
<para>Also note that besides the version number change, the tiles
|
||||
dependencies have also changed. You will need to have a subset or all of
|
||||
<filename>tiles-request-api</filename>, <filename>tiles-api</filename>,
|
||||
<filename>tiles-core</filename>, <filename>tiles-servlet</filename>,
|
||||
<filename>tiles-jsp</filename>, <filename>tiles-el</filename>.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="new-in-3.2-webmvc-request-body-arg-with-binding-result">
|
||||
<title><interfacename>@RequestBody</interfacename> improvements</title>
|
||||
|
||||
<para>An <interfacename>@RequestBody</interfacename> or an
|
||||
<interfacename>@RequestPart</interfacename> argument can now be followed
|
||||
by an <interfacename>Errors</interfacename> argument making it possible to
|
||||
handle validation errors (as a result of an
|
||||
<interfacename>@Valid</interfacename> annotation) locally within the
|
||||
<interfacename>@RequestMapping</interfacename> method.
|
||||
<interfacename>@RequestBody</interfacename> now also supports a required
|
||||
flag.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="new-in-3.2-webmvc-http-patch">
|
||||
<title>HTTP PATCH method</title>
|
||||
|
||||
<para>The HTTP request method <code>PATCH</code> may now be used in
|
||||
<interfacename>@RequestMapping</interfacename> methods as well as in the
|
||||
<classname>RestTemplate</classname> in conjunction with Apache
|
||||
HttpComponents HttpClient version 4.2 or later. The JDK
|
||||
<classname>HttpURLConnection</classname> does not support the
|
||||
<code>PATCH</code> method.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="new-in-3.2-webmvc-mapped-interceptor-exclude-patterns">
|
||||
<title>Excluded patterns in mapped interceptors</title>
|
||||
|
||||
<para>Mapped interceptors now support URL patterns to be excluded. The MVC
|
||||
namespace and the MVC JavaConfig both expose these options.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="new-in-3.2-meta-annotations">
|
||||
<title>Using meta-annotations for injection points and for bean definition methods</title>
|
||||
|
||||
<para>As of 3.2, Spring allows for <interfacename>@Autowired</interfacename> and
|
||||
<interfacename>@Value</interfacename> to be used as meta-annotations,
|
||||
e.g. to build custom injection annotations in combination with specific qualifiers.
|
||||
Analogously, you may build custom <interfacename>@Bean</interfacename> definition
|
||||
annotations for <interfacename>@Configuration</interfacename> classes,
|
||||
e.g. in combination with specific qualifiers, @Lazy, @Primary, etc.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="new-in-3.2-jcache">
|
||||
<title>Initial support for JCache 0.5</title>
|
||||
|
||||
<para>Spring provides a CacheManager adapter for JCache, building against the JCache 0.5
|
||||
preview release. Full JCache support is coming next year, along with Java EE 7 final.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="new-in-3.2-date-time-format-without-joda">
|
||||
<title>Support for <interfacename>@DateTimeFormat</interfacename> without
|
||||
Joda Time</title>
|
||||
|
||||
<para>The <interfacename>@DateTimeFormat</interfacename> annotation can
|
||||
now be used without needing a dependency on the Joda Time library. If Joda
|
||||
Time is not present the JDK <classname>SimpleDateFormat</classname> will
|
||||
be used to parse and print date patterns. When Joda Time is present it
|
||||
will continue to be used in preference to
|
||||
<classname>SimpleDateFormat</classname>.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="new-in-3.2-global-date-time-format">
|
||||
<title>Global date & time formatting</title>
|
||||
|
||||
<para>It is now possible to define global formats that will be used when
|
||||
parsing and printing date and time types. See <xref
|
||||
linkend="format-configuring-formatting-globaldatetimeformat" /> for
|
||||
details.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="new-in-3.2-testing">
|
||||
<title>New Testing Features</title>
|
||||
|
||||
<para>In addition to the aforementioned inclusion of the <link
|
||||
linkend="spring-mvc-test-framework">Spring MVC Test Framework</link> in
|
||||
the <literal>spring-test</literal> module, the <emphasis>Spring
|
||||
TestContext Framework</emphasis> has been revised with support for
|
||||
integration testing web applications as well as configuring application
|
||||
contexts with context initializers. For further details, consult the
|
||||
following.</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Configuring and <link
|
||||
linkend="testcontext-ctx-management-web">loading a
|
||||
WebApplicationContext</link> in integration tests</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Configuring <link
|
||||
linkend="testcontext-ctx-management-ctx-hierarchies">context hierarchies</link>
|
||||
in integration tests</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Testing <link linkend="testcontext-web-scoped-beans">request and
|
||||
session scoped beans</link></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Improvements to <link linkend="mock-objects-servlet">Servlet API
|
||||
mocks</link></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Configuring test application contexts with <link
|
||||
linkend="testcontext-ctx-management-initializers">ApplicationContextInitializers</link></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section xml:id="new-in-3.2-concurrency">
|
||||
<title>Concurrency refinements across the framework</title>
|
||||
|
||||
<para>Spring Framework 3.2 includes fine-tuning of concurrent data structures
|
||||
in many parts of the framework, minimizing locks and generally improving the
|
||||
arrangements for highly concurrent creation of scoped/prototype beans.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="new-in-3.2-build">
|
||||
<title>New Gradle-based build and move to GitHub</title>
|
||||
|
||||
<para>Building and contributing to the framework has never been simpler with
|
||||
our move to a Gradle-based build system and source control at GitHub.
|
||||
See the <link xl:href="https://github.com/SpringSource/spring-framework#building-from-source">
|
||||
building from source</link> section of the README and the
|
||||
<link xl:href="https://github.com/SpringSource/spring-framework/blob/master/CONTRIBUTING.md">
|
||||
contributor guidelines</link> for complete details.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="new-in-3.2-java7">
|
||||
<title>Refined Java SE 7 / OpenJDK 7 support</title>
|
||||
|
||||
<para>Last but not least, Spring Framework 3.2 comes with refined Java 7 support
|
||||
within the framework as well as through upgraded third-party dependencies:
|
||||
specifically, CGLIB 3.0, ASM 4.0 (both of which come as inlined dependencies with
|
||||
Spring now) and AspectJ 1.7 support (next to the existing AspectJ 1.6 support).</para>
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,939 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter xml:id="overview"
|
||||
xmlns="http://docbook.org/ns/docbook" version="5.0"
|
||||
xmlns:xl="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
|
||||
http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd">
|
||||
<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 xml:id="overview-dependency-injection">
|
||||
<title>Dependency Injection and Inversion of Control</title>
|
||||
|
||||
<sidebar xml: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 <link
|
||||
xl:href="http://martinfowler.com/articles/injection.html">http://martinfowler.com/articles/injection.html</link>.</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 xml: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>
|
||||
<imagedata align="center" fileref="images/spring-overview.png" format="PNG" width="400" />
|
||||
</imageobject>
|
||||
|
||||
<caption><para>Overview of the Spring Framework</para></caption>
|
||||
</mediaobject></para>
|
||||
|
||||
<section xml:id="overview-core-container">
|
||||
<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 xml:id="overview-data-access">
|
||||
<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 xml:id="overview-web">
|
||||
<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 xml:id="overview-aop-instrumentation">
|
||||
<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 xml:id="overview-testing">
|
||||
<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 xml: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>
|
||||
<imagedata align="center" fileref="images/overview-full.png" format="PNG" width="400" />
|
||||
</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>
|
||||
<imagedata align="center"
|
||||
fileref="images/overview-thirdparty-web.png" format="PNG"
|
||||
width="400"/>
|
||||
</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>
|
||||
<imagedata align="center" fileref="images/overview-remoting.png"
|
||||
format="PNG" width="400" />
|
||||
</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>
|
||||
<imagedata align="center" fileref="images/overview-ejb.png"
|
||||
format="PNG" width="400" />
|
||||
</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 xml: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 <link
|
||||
xl:href="http://www.springsource.org/download/community">http://www.springsource.org/download/community</link>.
|
||||
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 <link
|
||||
xl:href="http://www.springsource.com/repository/app/faq">FAQ</link>
|
||||
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 deployed
|
||||
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><link
|
||||
xl:href="http://www.springsource.com/repository">http://www.springsource.com/repository</link></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 xml:id="overview-spring-dependencies">
|
||||
<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 xml:id="overview-maven-dependency-management">
|
||||
<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 language="xml"><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 snapshots), you need to specify the repository location in
|
||||
your Maven configuration. For full releases:</para>
|
||||
|
||||
<programlisting language="xml"><repositories>
|
||||
<repository>
|
||||
<id>com.springsource.repository.maven.release</id>
|
||||
<url>http://repo.springsource.org/release/</url>
|
||||
<snapshots><enabled>false</enabled></snapshots>
|
||||
</repository>
|
||||
</repositories></programlisting>
|
||||
|
||||
<para>For milestones:</para>
|
||||
|
||||
<programlisting language="xml"><repositories>
|
||||
<repository>
|
||||
<id>com.springsource.repository.maven.milestone</id>
|
||||
<url>http://repo.springsource.org/milestone/</url>
|
||||
<snapshots><enabled>false</enabled></snapshots>
|
||||
</repository>
|
||||
</repositories></programlisting>
|
||||
|
||||
<para>And for snapshots:</para>
|
||||
|
||||
<programlisting language="xml"><repositories>
|
||||
<repository>
|
||||
<id>com.springsource.repository.maven.snapshot</id>
|
||||
<url>http://repo.springsource.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 language="xml"><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 language="xml"><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 browsable, but there is a user
|
||||
interface at <link
|
||||
xl:href="http://www.springsource.com/repository">http://www.springsource.com/repository</link>
|
||||
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 xml:id="overview-ivy-dependency-management">
|
||||
<title>Ivy Dependency Management</title>
|
||||
|
||||
<para>If you prefer to use <link
|
||||
xl:href="http://ant.apache.org/ivy">Ivy</link> 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 language="xml"><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 language="xml"><dependency org="org.springframework"
|
||||
name="org.springframework.core" rev="3.0.0.RELEASE" conf="compile->runtime"/></programlisting>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section xml:id="overview-logging">
|
||||
<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 xml:id="overview-not-using-commons-logging">
|
||||
<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 (<link
|
||||
xl:href="http://www.slf4j.org">SLF4J</link>), 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 language="xml"><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 xml:id="overview-logging-slf4j">
|
||||
<title>Using SLF4J</title>
|
||||
|
||||
<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 language="xml"><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 <link
|
||||
xl:href="http://logback.qos.ch">Logback</link>. This removes the extra
|
||||
binding step because Logback implements SLF4J directly, so you only need
|
||||
to depend on two libraries not four (<code>jcl-over-slf4j</code> and
|
||||
<code>logback</code>). If you do that you might also need to exclude the
|
||||
slf4j-api dependency from other external dependencies (not Spring),
|
||||
because you only want one version of that API on the classpath.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="overview-logging-log4j">
|
||||
<title>Using Log4J</title>
|
||||
|
||||
<para>Many people use <link
|
||||
xl:href="http://logging.apache.org/log4j">Log4j</link> 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 language="xml"><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 xml:id="overview-native-jcl">
|
||||
<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>
|
||||
|
|
@ -1,786 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter xml:id="oxm"
|
||||
xmlns="http://docbook.org/ns/docbook" version="5.0"
|
||||
xmlns:xl="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
|
||||
http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd">
|
||||
<title>Marshalling XML using O/X Mappers</title>
|
||||
|
||||
<section xml: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 xml: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 xml:id="oxm-marshaller">
|
||||
<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 xml:id="oxm-unmarshaller">
|
||||
<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>
|
||||
<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>
|
||||
<section xml:id="oxm-xmlmappingexception">
|
||||
<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 align="center" fileref="images/oxm-exceptions.png"
|
||||
format="PNG" width="400"/>
|
||||
</imageobject>
|
||||
<caption>O/X Mapping exception hierarchy</caption>
|
||||
</mediaobject>
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
<section xml: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 xml:id="oxm-schema-based-config">
|
||||
<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.xsd
|
||||
]]><emphasis role="bold"><![CDATA[http://www.springframework.org/schema/oxm
|
||||
]]><![CDATA[http://www.springframework.org/schema/oxm/spring-oxm.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-castor-xsd"><literal>castor-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 xml: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 xml: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 xml: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 xml: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 <link xl:href="http://castor.codehaus.org/xml-framework.html">
|
||||
<citetitle>Castor web site</citetitle></link>. The Spring integration classes reside in the
|
||||
<package>org.springframework.oxm.castor</package> package.
|
||||
</para>
|
||||
<section xml:id="oxm-castor-marshaller">
|
||||
<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 xml:id="oxm-castor-mapping">
|
||||
<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 <link xl:href="http://castor.codehaus.org/xml-mapping.html">Castor XML Mapping</link>.
|
||||
</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 xml:id="oxm-castor-xsd">
|
||||
<title>XML Schema-based Configuration</title>
|
||||
<para>
|
||||
The <literal>castor-marshaller</literal> tag configures a
|
||||
<classname>org.springframework.oxm.castor.CastorMarshaller</classname>.
|
||||
Here is an example:
|
||||
</para>
|
||||
|
||||
<programlisting language="xml">
|
||||
<![CDATA[<oxm:castor-marshaller id="marshaller" mapping-location="classpath:org/springframework/oxm/castor/mapping.xml"/>]]></programlisting>
|
||||
|
||||
<para>
|
||||
The marshaller instance can be configured in two ways, by specifying either the location of
|
||||
a mapping file (through the <property>mapping-location</property> property), or by
|
||||
identifying Java POJOs (through the <property>target-class</property> or
|
||||
<property>target-package</property> properties) for which there exist corresponding
|
||||
XML descriptor classes. The latter way is usually used in conjunction with XML code generation
|
||||
from XML schemas.
|
||||
</para>
|
||||
|
||||
<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>encoding</literal>
|
||||
</entry>
|
||||
<entry>the encoding to use for unmarshalling from XML</entry>
|
||||
<entry>no</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<literal>target-class</literal>
|
||||
</entry>
|
||||
<entry>a Java class name for a POJO for which an XML class descriptor is available (as
|
||||
generated through code generation)
|
||||
</entry>
|
||||
<entry>no</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<literal>target-package</literal>
|
||||
</entry>
|
||||
<entry>a Java package name that identifies a package that contains POJOs and their
|
||||
corresponding Castor
|
||||
XML descriptor classes (as generated through code generation from XML schemas)
|
||||
</entry>
|
||||
<entry>no</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<literal>mapping-location</literal>
|
||||
</entry>
|
||||
<entry>location of a Castor XML mapping file</entry>
|
||||
<entry>no</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section xml: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 <link xl:href="http://xmlbeans.apache.org/">
|
||||
<citetitle>XMLBeans web site </citetitle></link>. The Spring-WS integration classes reside
|
||||
in the <package>org.springframework.oxm.xmlbeans</package> package.
|
||||
</para>
|
||||
<section xml:id="oxm-xmlbeans-marshaller">
|
||||
<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 xml: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 xml: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 <link xl:href="http://jibx.sourceforge.net/">
|
||||
<citetitle>JiBX web site</citetitle></link>. The Spring integration classes reside in the
|
||||
<package>org.springframework.oxm.jibx</package> package.
|
||||
</para>
|
||||
<section xml:id="oxm-jibx-marshaller">
|
||||
<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 xml: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 xml: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 <link xl:href="http://xstream.codehaus.org/">
|
||||
<citetitle>XStream web site</citetitle></link>. The Spring integration classes reside in the
|
||||
<package>org.springframework.oxm.xstream</package> package.
|
||||
</para>
|
||||
<section xml:id="oxm-xstream-marshaller">
|
||||
<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 <emphasis>not recommended to use the <classname>XStreamMarshaller</classname> to
|
||||
unmarshal XML from external sources</emphasis> (i.e. the Web), as this can result in
|
||||
<emphasis>security vulnerabilities</emphasis>.
|
||||
If you do use the <classname>XStreamMarshaller</classname> to unmarshal XML from an external source,
|
||||
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 <link xl:href="http://static.springsource.org/spring/docs/current/api/org/springframework/oxm/xstream/XStreamMarshaller.html#setConverters(com.thoughtworks.xstream.converters.ConverterMatcher[])">
|
||||
custom converters</link> to make sure that only your supported classes can be unmarshalled.
|
||||
You might want to add a <classname>CatchAllConverter</classname> as the last converter in the list,
|
||||
in addition to converters that explicitly support the domain classes that should be supported.
|
||||
As a result, default XStream converters with lower priorities and possible security vulnerabilities do not get invoked.
|
||||
</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>
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,42 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<preface xml:id="preface"
|
||||
xmlns="http://docbook.org/ns/docbook" version="5.0"
|
||||
xmlns:xl="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
|
||||
http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd">
|
||||
<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. If you
|
||||
have any requests or comments, please add an issue at
|
||||
<link xl:href="http://jira.springsource.org/SPR" />.
|
||||
</para>
|
||||
</preface>
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,746 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter xml:id="resources"
|
||||
xmlns="http://docbook.org/ns/docbook" version="5.0"
|
||||
xmlns:xl="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
|
||||
http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd">
|
||||
<title>Resources</title>
|
||||
|
||||
<section xml: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 xml: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 xml: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 xml: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 xml: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 xml: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 xml: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 xml: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 xml: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 xml: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" xml: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 xml: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 xml: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 xml:id="resources-app-ctx">
|
||||
<title>Application contexts and <interfacename>Resource</interfacename> paths</title>
|
||||
|
||||
<section xml: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 xml: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 xml: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 xml: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 xml: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 xml: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 resolution
|
||||
strategy described above is used for the wildcard subpath.</para>
|
||||
</section>
|
||||
|
||||
<section xml: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 xml: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 Resource will always be UrlResource</lineannotation><![CDATA[
|
||||
ctx.getResource("file:/some/resource/path/myTemplate.txt");]]></programlisting>
|
||||
|
||||
<programlisting language="java"><lineannotation>// force this FileSystemXmlApplicationContext to load its definition via a UrlResource</lineannotation><![CDATA[
|
||||
ApplicationContext ctx =
|
||||
new FileSystemXmlApplicationContext("file:/conf/context.xml");]]></programlisting>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
||||
|
|
@ -1,891 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter xml:id="scheduling"
|
||||
xmlns="http://docbook.org/ns/docbook" version="5.0"
|
||||
xmlns:xl="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
|
||||
http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd">
|
||||
<title>Task Execution and Scheduling</title>
|
||||
|
||||
<section xml:id="scheduling-introduction">
|
||||
<title>Introduction</title>
|
||||
|
||||
<para>The Spring Framework provides abstractions for asynchronous
|
||||
execution and scheduling of tasks with the
|
||||
<interfacename>TaskExecutor</interfacename> and
|
||||
<interfacename>TaskScheduler</interfacename> interfaces, respectively.
|
||||
Spring also features implementations of those interfaces that support
|
||||
thread pools or delegation to CommonJ within an application server
|
||||
environment. Ultimately the use of these implementations behind the common
|
||||
interfaces abstracts away the differences between Java SE 5, Java SE 6 and
|
||||
Java EE environments.</para>
|
||||
|
||||
<para>Spring also features integration classes for supporting scheduling
|
||||
with the <classname>Timer</classname>, part of the JDK since 1.3, and the
|
||||
Quartz Scheduler (<link
|
||||
xl:href="http://quartz-scheduler.org"></link>). Both of those
|
||||
schedulers are set up using a <interfacename>FactoryBean</interfacename>
|
||||
with optional references to <classname>Timer</classname> or
|
||||
<classname>Trigger</classname> instances, respectively. Furthermore, a
|
||||
convenience class for both the Quartz Scheduler and the
|
||||
<classname>Timer</classname> is available that allows you to invoke a
|
||||
method of an existing target object (analogous to the normal
|
||||
<classname>MethodInvokingFactoryBean</classname> operation).</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="scheduling-task-executor">
|
||||
<title>The Spring <interfacename>TaskExecutor</interfacename>
|
||||
abstraction</title>
|
||||
|
||||
<para>Spring 2.0 introduces a new abstraction for dealing with executors.
|
||||
Executors are the Java 5 name for the concept of thread pools. The
|
||||
"executor" naming is due to the fact that there is no guarantee that the
|
||||
underlying implementation is actually a pool; an executor may be
|
||||
single-threaded or even synchronous. Spring's abstraction hides
|
||||
implementation details between Java SE 1.4, Java SE 5 and Java EE
|
||||
environments.</para>
|
||||
|
||||
<para>Spring's <interfacename>TaskExecutor</interfacename> interface is
|
||||
identical to the <classname>java.util.concurrent.Executor</classname>
|
||||
interface. In fact, its primary reason for existence is to abstract away
|
||||
the need for Java 5 when using thread pools. The interface has a single
|
||||
method <classname>execute(Runnable task)</classname> that accepts a task
|
||||
for execution based on the semantics and configuration of the thread
|
||||
pool.</para>
|
||||
|
||||
<para>The <interfacename>TaskExecutor</interfacename> was originally
|
||||
created to give other Spring components an abstraction for thread pooling
|
||||
where needed. Components such as the
|
||||
<classname>ApplicationEventMulticaster</classname>, JMS's
|
||||
<classname>AbstractMessageListenerContainer</classname>, and Quartz
|
||||
integration all use the <interfacename>TaskExecutor</interfacename>
|
||||
abstraction to pool threads. However, if your beans need thread pooling
|
||||
behavior, it is possible to use this abstraction for your own
|
||||
needs.</para>
|
||||
|
||||
<section xml:id="scheduling-task-executor-types">
|
||||
<title><interfacename>TaskExecutor</interfacename> types</title>
|
||||
|
||||
<para>There are a number of pre-built implementations of
|
||||
<interfacename>TaskExecutor</interfacename> included with the Spring
|
||||
distribution. In all likelihood, you shouldn't ever need to implement
|
||||
your own.</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><classname>SimpleAsyncTaskExecutor</classname></para>
|
||||
|
||||
<para>This implementation does not reuse any threads, rather it
|
||||
starts up a new thread for each invocation. However, it does support
|
||||
a concurrency limit which will block any invocations that are over
|
||||
the limit until a slot has been freed up. If you're looking for true
|
||||
pooling, keep scrolling further down the page.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem xml:id="syncTaskExecutor">
|
||||
<para><classname>SyncTaskExecutor</classname></para>
|
||||
|
||||
<para>This implementation doesn't execute invocations
|
||||
asynchronously. Instead, each invocation takes place in the calling
|
||||
thread. It is primarily used in situations where multithreading
|
||||
isn't necessary such as simple test cases.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem xml:id="concurrentTaskExecutor">
|
||||
<para><classname>ConcurrentTaskExecutor</classname></para>
|
||||
|
||||
<para>This implementation is a wrapper for a Java 5
|
||||
<classname>java.util.concurrent.Executor</classname>. There is an
|
||||
alternative, <classname>ThreadPoolTaskExecutor</classname>, that
|
||||
exposes the <classname>Executor</classname> configuration parameters
|
||||
as bean properties. It is rare to need to use the
|
||||
<classname>ConcurrentTaskExecutor</classname> but if the <link
|
||||
linkend="threadPoolTaskExecutor"><classname>ThreadPoolTaskExecutor</classname></link>
|
||||
isn't robust enough for your needs, the
|
||||
<classname>ConcurrentTaskExecutor</classname> is an
|
||||
alternative.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem xml:id="simpleThreadPoolTaskExecutor">
|
||||
<para><classname>SimpleThreadPoolTaskExecutor</classname></para>
|
||||
|
||||
<para>This implementation is actually a subclass of Quartz's
|
||||
<classname>SimpleThreadPool</classname> which listens to Spring's
|
||||
lifecycle callbacks. This is typically used when you have a thread
|
||||
pool that may need to be shared by both Quartz and non-Quartz
|
||||
components.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem xml:id="threadPoolTaskExecutor">
|
||||
<para><classname>ThreadPoolTaskExecutor</classname></para>
|
||||
|
||||
<sidebar>
|
||||
<para>It is not possible to use any backport or alternate versions
|
||||
of the <classname>java.util.concurrent</classname> package with
|
||||
this implementation. Both Doug Lea's and Dawid Kurzyniec's
|
||||
implementations use different package structures which will
|
||||
prevent them from working correctly.</para>
|
||||
</sidebar>
|
||||
|
||||
<para>This implementation can only be used in a Java 5 environment
|
||||
but is also the most commonly used one in that environment. It
|
||||
exposes bean properties for configuring a
|
||||
<classname>java.util.concurrent.ThreadPoolExecutor</classname> and
|
||||
wraps it in a <interfacename>TaskExecutor</interfacename>. If you
|
||||
need something advanced such as a
|
||||
<classname>ScheduledThreadPoolExecutor</classname>, it is
|
||||
recommended that you use a <link
|
||||
linkend="concurrentTaskExecutor"><classname>ConcurrentTaskExecutor</classname></link>
|
||||
instead.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><classname>TimerTaskExecutor</classname></para>
|
||||
|
||||
<para>This implementation uses a single
|
||||
<classname>TimerTask</classname> as its backing implementation. It's
|
||||
different from the <link
|
||||
linkend="syncTaskExecutor"><classname>SyncTaskExecutor</classname></link>
|
||||
in that the method invocations are executed in a separate thread,
|
||||
although they are synchronous in that thread.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><classname>WorkManagerTaskExecutor</classname></para>
|
||||
|
||||
<sidebar>
|
||||
<para>CommonJ is a set of specifications jointly developed between
|
||||
BEA and IBM. These specifications are not Java EE standards, but
|
||||
are standard across BEA's and IBM's Application Server
|
||||
implementations.</para>
|
||||
</sidebar>
|
||||
|
||||
<para>This implementation uses the CommonJ WorkManager as its
|
||||
backing implementation and is the central convenience class for
|
||||
setting up a CommonJ WorkManager reference in a Spring context.
|
||||
Similar to the <link
|
||||
linkend="simpleThreadPoolTaskExecutor"><classname>SimpleThreadPoolTaskExecutor</classname></link>,
|
||||
this class implements the WorkManager interface and therefore can be
|
||||
used directly as a WorkManager as well.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section xml:id="scheduling-task-executor-usage">
|
||||
<title>Using a <interfacename>TaskExecutor</interfacename></title>
|
||||
|
||||
<para>Spring's <interfacename>TaskExecutor</interfacename>
|
||||
implementations are used as simple JavaBeans. In the example below, we
|
||||
define a bean that uses the
|
||||
<classname>ThreadPoolTaskExecutor</classname> to asynchronously print
|
||||
out a set of messages.</para>
|
||||
|
||||
<programlisting language="java">import org.springframework.core.task.TaskExecutor;
|
||||
|
||||
public class TaskExecutorExample {
|
||||
|
||||
private class MessagePrinterTask implements Runnable {
|
||||
|
||||
private String message;
|
||||
|
||||
public MessagePrinterTask(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
System.out.println(message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private TaskExecutor taskExecutor;
|
||||
|
||||
public TaskExecutorExample(TaskExecutor taskExecutor) {
|
||||
this.taskExecutor = taskExecutor;
|
||||
}
|
||||
|
||||
public void printMessages() {
|
||||
for(int i = 0; i < 25; i++) {
|
||||
taskExecutor.execute(new MessagePrinterTask("Message" + i));
|
||||
}
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<para>As you can see, rather than retrieving a thread from the pool and
|
||||
executing yourself, you add your <classname>Runnable</classname> to the
|
||||
queue and the <interfacename>TaskExecutor</interfacename> uses its
|
||||
internal rules to decide when the task gets executed.</para>
|
||||
|
||||
<para>To configure the rules that the
|
||||
<interfacename>TaskExecutor</interfacename> will use, simple bean
|
||||
properties have been exposed.</para>
|
||||
|
||||
<programlisting language="xml"><bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
|
||||
<property name="corePoolSize" value="5" />
|
||||
<property name="maxPoolSize" value="10" />
|
||||
<property name="queueCapacity" value="25" />
|
||||
</bean>
|
||||
|
||||
<bean id="taskExecutorExample" class="TaskExecutorExample">
|
||||
<constructor-arg ref="taskExecutor" />
|
||||
</bean></programlisting>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section xml:id="scheduling-task-scheduler">
|
||||
<title>The Spring <interfacename>TaskScheduler</interfacename>
|
||||
abstraction</title>
|
||||
|
||||
<para>In addition to the <interfacename>TaskExecutor</interfacename>
|
||||
abstraction, Spring 3.0 introduces a
|
||||
<interfacename>TaskScheduler</interfacename> with a variety of methods for
|
||||
scheduling tasks to run at some point in the future.</para>
|
||||
|
||||
<programlisting language="java">public interface TaskScheduler {
|
||||
|
||||
ScheduledFuture schedule(Runnable task, Trigger trigger);
|
||||
|
||||
ScheduledFuture schedule(Runnable task, Date startTime);
|
||||
|
||||
ScheduledFuture scheduleAtFixedRate(Runnable task, Date startTime, long period);
|
||||
|
||||
ScheduledFuture scheduleAtFixedRate(Runnable task, long period);
|
||||
|
||||
ScheduledFuture scheduleWithFixedDelay(Runnable task, Date startTime, long delay);
|
||||
|
||||
ScheduledFuture scheduleWithFixedDelay(Runnable task, long delay);
|
||||
|
||||
}</programlisting>
|
||||
|
||||
<para>The simplest method is the one named 'schedule' that takes a
|
||||
<interfacename>Runnable</interfacename> and <classname>Date</classname>
|
||||
only. That will cause the task to run once after the specified time. All
|
||||
of the other methods are capable of scheduling tasks to run repeatedly.
|
||||
The fixed-rate and fixed-delay methods are for simple, periodic execution,
|
||||
but the method that accepts a Trigger is much more flexible.</para>
|
||||
|
||||
<section xml:id="scheduling-trigger-interface">
|
||||
<title>The <interfacename>Trigger</interfacename> interface</title>
|
||||
|
||||
<para>The <interfacename>Trigger</interfacename> interface is
|
||||
essentially inspired by JSR-236, which, as of Spring 3.0, has not yet
|
||||
been officially implemented. The basic idea of the
|
||||
<interfacename>Trigger</interfacename> is that execution times may be
|
||||
determined based on past execution outcomes or even arbitrary
|
||||
conditions. If these determinations do take into account the outcome of
|
||||
the preceding execution, that information is available within a
|
||||
<interfacename>TriggerContext</interfacename>. The
|
||||
<interfacename>Trigger</interfacename> interface itself is quite
|
||||
simple:</para>
|
||||
|
||||
<programlisting language="java">public interface Trigger {
|
||||
|
||||
Date nextExecutionTime(TriggerContext triggerContext);
|
||||
|
||||
}</programlisting>
|
||||
|
||||
<para>As you can see, the <interfacename>TriggerContext</interfacename>
|
||||
is the most important part. It encapsulates all of the relevant data,
|
||||
and is open for extension in the future if necessary. The
|
||||
<interfacename>TriggerContext</interfacename> is an interface (a
|
||||
<classname>SimpleTriggerContext</classname> implementation is used by
|
||||
default). Here you can see what methods are available for
|
||||
<interfacename>Trigger</interfacename> implementations.</para>
|
||||
|
||||
<programlisting language="java">public interface TriggerContext {
|
||||
|
||||
Date lastScheduledExecutionTime();
|
||||
|
||||
Date lastActualExecutionTime();
|
||||
|
||||
Date lastCompletionTime();
|
||||
|
||||
}</programlisting>
|
||||
</section>
|
||||
|
||||
<section xml:id="scheduling-trigger-implementations">
|
||||
<title><interfacename>Trigger</interfacename> implementations</title>
|
||||
|
||||
<para>Spring provides two implementations of the
|
||||
<interfacename>Trigger</interfacename> interface. The most interesting
|
||||
one is the <classname>CronTrigger</classname>. It enables the scheduling
|
||||
of tasks based on cron expressions. For example the following task is
|
||||
being scheduled to run 15 minutes past each hour but only during the
|
||||
9-to-5 "business hours" on weekdays.</para>
|
||||
|
||||
<programlisting language="java">scheduler.schedule(task, new CronTrigger("* 15 9-17 * * MON-FRI"));</programlisting>
|
||||
|
||||
<para>The other out-of-the-box implementation is a
|
||||
<classname>PeriodicTrigger</classname> that accepts a fixed period, an
|
||||
optional initial delay value, and a boolean to indicate whether the
|
||||
period should be interpreted as a fixed-rate or a fixed-delay. Since the
|
||||
<interfacename>TaskScheduler</interfacename> interface already defines
|
||||
methods for scheduling tasks at a fixed-rate or with a fixed-delay,
|
||||
those methods should be used directly whenever possible. The value of
|
||||
the <classname>PeriodicTrigger</classname> implementation is that it can
|
||||
be used within components that rely on the
|
||||
<interfacename>Trigger</interfacename> abstraction. For example, it may
|
||||
be convenient to allow periodic triggers, cron-based triggers, and even
|
||||
custom trigger implementations to be used interchangeably. Such a
|
||||
component could take advantage of dependency injection so that such
|
||||
<interfacename>Triggers</interfacename> could be configured
|
||||
externally.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="scheduling-task-scheduler-implementations">
|
||||
<title><interfacename>TaskScheduler</interfacename>
|
||||
implementations</title>
|
||||
|
||||
<para>As with Spring's <interfacename>TaskExecutor</interfacename>
|
||||
abstraction, the primary benefit of the
|
||||
<interfacename>TaskScheduler</interfacename> is that code relying on
|
||||
scheduling behavior need not be coupled to a particular scheduler
|
||||
implementation. The flexibility this provides is particularly relevant
|
||||
when running within Application Server environments where threads should
|
||||
not be created directly by the application itself. For such cases,
|
||||
Spring provides a <classname>TimerManagerTaskScheduler</classname> that
|
||||
delegates to a CommonJ TimerManager instance, typically configured with
|
||||
a JNDI-lookup.</para>
|
||||
|
||||
<para>A simpler alternative, the
|
||||
<classname>ThreadPoolTaskScheduler</classname>, can be used whenever
|
||||
external thread management is not a requirement. Internally, it
|
||||
delegates to a <interfacename>ScheduledExecutorService</interfacename>
|
||||
instance. <classname>ThreadPoolTaskScheduler</classname> actually
|
||||
implements Spring's <interfacename>TaskExecutor</interfacename>
|
||||
interface as well, so that a single instance can be used for
|
||||
asynchronous execution <emphasis>as soon as possible</emphasis> as well
|
||||
as scheduled, and potentially recurring, executions.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section xml:id="scheduling-annotation-support">
|
||||
<title>Annotation Support for Scheduling and Asynchronous
|
||||
Execution</title>
|
||||
|
||||
<para>Spring provides annotation support for both task scheduling and
|
||||
asynchronous method execution.</para>
|
||||
|
||||
<section xml:id="scheduling-enable-annotation-support">
|
||||
|
||||
<title>Enable scheduling annotations</title>
|
||||
|
||||
<para>To enable support for <interfacename>@Scheduled</interfacename> and
|
||||
<interfacename>@Async</interfacename> annotations add
|
||||
<interfacename>@EnableScheduling</interfacename> and
|
||||
<interfacename>@EnableAsync</interfacename> to one of your
|
||||
<interfacename>@Configuration</interfacename> classes:</para>
|
||||
|
||||
<programlisting language="java">@Configuration
|
||||
@EnableAsync
|
||||
@EnableScheduling
|
||||
public class AppConfig {
|
||||
}</programlisting>
|
||||
|
||||
<para>You are free to pick and choose the relevant annotations
|
||||
for your application. For example, if you only need support
|
||||
for <interfacename>@Scheduled</interfacename>, simply omit
|
||||
<interfacename>@EnableAsync</interfacename>. For more fine-grained
|
||||
control you can additionally implement the
|
||||
<interfacename>SchedulingConfigurer</interfacename> and/or
|
||||
<interfacename>AsyncConfigurer</interfacename> interfaces. See
|
||||
the Javadoc for full details.</para>
|
||||
|
||||
<para>If you prefer XML configuration use the
|
||||
<literal><task:annotation-driven></literal> element.</para>
|
||||
|
||||
<programlisting language="xml"><task:annotation-driven executor="myExecutor" scheduler="myScheduler"/>
|
||||
<task:executor id="myExecutor" pool-size="5"/>
|
||||
<task:scheduler id="myScheduler" pool-size="10"/>}</programlisting>
|
||||
|
||||
<para>Notice with the above XML that an executor reference is provided
|
||||
for handling those tasks that correspond to methods with the
|
||||
<interfacename>@Async</interfacename> annotation, and the scheduler
|
||||
reference is provided for managing those methods annotated
|
||||
with <interfacename>@Scheduled</interfacename>.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="scheduling-annotation-support-scheduled">
|
||||
<title>The @Scheduled Annotation</title>
|
||||
|
||||
<para>The @Scheduled annotation can be added to a method along with
|
||||
trigger metadata. For example, the following method would be invoked
|
||||
every 5 seconds with a fixed delay, meaning that the period will be
|
||||
measured from the completion time of each preceding invocation.</para>
|
||||
|
||||
<programlisting language="java">@Scheduled(fixedDelay=5000)
|
||||
public void doSomething() {
|
||||
// something that should execute periodically
|
||||
}</programlisting>
|
||||
|
||||
<para>If a fixed rate execution is desired, simply change the property
|
||||
name specified within the annotation. The following would be executed
|
||||
every 5 seconds measured between the successive start times of each
|
||||
invocation.</para>
|
||||
|
||||
<programlisting language="java">@Scheduled(fixedRate=5000)
|
||||
public void doSomething() {
|
||||
// something that should execute periodically
|
||||
}</programlisting>
|
||||
|
||||
<para>For fixed-delay and fixed-rate tasks, an initial delay may be
|
||||
specified indicating the number of milliseconds to wait before the first
|
||||
execution of the method.
|
||||
</para>
|
||||
|
||||
<programlisting language="java">@Scheduled(initialDelay=1000, fixedRate=5000)
|
||||
public void doSomething() {
|
||||
// something that should execute periodically
|
||||
}</programlisting>
|
||||
|
||||
<para>If simple periodic scheduling is not expressive enough, then a
|
||||
cron expression may be provided. For example, the following will only
|
||||
execute on weekdays.</para>
|
||||
|
||||
<programlisting language="java">@Scheduled(cron="*/5 * * * * MON-FRI")
|
||||
public void doSomething() {
|
||||
// something that should execute on weekdays only
|
||||
}</programlisting>
|
||||
|
||||
<para>Notice that the methods to be scheduled must have void returns and
|
||||
must not expect any arguments. If the method needs to interact with
|
||||
other objects from the Application Context, then those would typically
|
||||
have been provided through dependency injection.</para>
|
||||
|
||||
<note>
|
||||
<para>Make sure that you are not initializing multiple instances of
|
||||
the same @Scheduled annotation class at runtime, unless you do want to
|
||||
schedule callbacks to each such instance. Related to this, make sure
|
||||
that you do not use @Configurable on bean classes which are annotated
|
||||
with @Scheduled and registered as regular Spring beans with the
|
||||
container: You would get double initialization otherwise, once through
|
||||
the container and once through the @Configurable aspect, with the
|
||||
consequence of each @Scheduled method being invoked twice.</para>
|
||||
</note>
|
||||
</section>
|
||||
|
||||
<section xml:id="scheduling-annotation-support-async">
|
||||
<title>The @Async Annotation</title>
|
||||
|
||||
<para>The <interfacename>@Async</interfacename> annotation can be
|
||||
provided on a method so that invocation of that method will occur
|
||||
asynchronously. In other words, the caller will return immediately upon
|
||||
invocation and the actual execution of the method will occur in a task
|
||||
that has been submitted to a Spring
|
||||
<interfacename>TaskExecutor</interfacename>. In the simplest case, the
|
||||
annotation may be applied to a <literal>void</literal>-returning
|
||||
method.</para>
|
||||
|
||||
<programlisting language="java">@Async
|
||||
void doSomething() {
|
||||
// this will be executed asynchronously
|
||||
}</programlisting>
|
||||
|
||||
<para>Unlike the methods annotated with the
|
||||
<interfacename>@Scheduled</interfacename> annotation, these methods can
|
||||
expect arguments, because they will be invoked in the "normal" way by
|
||||
callers at runtime rather than from a scheduled task being managed by
|
||||
the container. For example, the following is a legitimate application of
|
||||
the <interfacename>@Async</interfacename> annotation.</para>
|
||||
|
||||
<programlisting language="java">@Async
|
||||
void doSomething(String s) {
|
||||
// this will be executed asynchronously
|
||||
}</programlisting>
|
||||
|
||||
<para>Even methods that return a value can be invoked asynchronously.
|
||||
However, such methods are required to have a
|
||||
<interfacename>Future</interfacename> typed return value. This still
|
||||
provides the benefit of asynchronous execution so that the caller can
|
||||
perform other tasks prior to calling <methodname>get()</methodname> on
|
||||
that Future.</para>
|
||||
|
||||
<programlisting language="java">@Async
|
||||
Future<String> returnSomething(int i) {
|
||||
// this will be executed asynchronously
|
||||
}</programlisting>
|
||||
|
||||
<para><interfacename>@Async</interfacename> can not be used in
|
||||
conjunction with lifecycle callbacks such as
|
||||
<interfacename>@PostConstruct</interfacename>. To asynchronously
|
||||
initialize Spring beans you currently have to use a separate
|
||||
initializing Spring bean that invokes the
|
||||
<interfacename>@Async</interfacename> annotated method on the target
|
||||
then.</para>
|
||||
|
||||
<programlisting language="java">public class SampleBeanImpl implements SampleBean {
|
||||
|
||||
@Async
|
||||
void doSomething() { … }
|
||||
}
|
||||
|
||||
|
||||
public class SampleBeanInititalizer {
|
||||
|
||||
private final SampleBean bean;
|
||||
|
||||
public SampleBeanInitializer(SampleBean bean) {
|
||||
this.bean = bean;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void initialize() {
|
||||
bean.doSomething();
|
||||
}
|
||||
}</programlisting>
|
||||
</section>
|
||||
|
||||
<section xml:id="scheduling-annotation-support-qualification">
|
||||
<title>Executor qualification with @Async</title>
|
||||
|
||||
<para>By default when specifying <interfacename>@Async</interfacename> on
|
||||
a method, the executor that will be used is the one supplied to the
|
||||
'annotation-driven' element as described above. However, the
|
||||
<literal>value</literal> attribute of the
|
||||
<interfacename>@Async</interfacename> annotation can be used when needing
|
||||
to indicate that an executor other than the default should be used when
|
||||
executing a given method.</para>
|
||||
<programlisting language="java">@Async("otherExecutor")
|
||||
void doSomething(String s) {
|
||||
// this will be executed asynchronously by "otherExecutor"
|
||||
}</programlisting>
|
||||
|
||||
<para>In this case, "otherExecutor" may be the name of any
|
||||
<interfacename>Executor</interfacename> bean in the Spring container, or
|
||||
may be the name of a <emphasis>qualifier</emphasis> associated with any
|
||||
<interfacename>Executor</interfacename>, e.g. as specified with the
|
||||
<literal><qualifier></literal> element or Spring's
|
||||
<interfacename>@Qualifier</interfacename> annotation.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section xml:id="scheduling-task-namespace">
|
||||
<title>The Task Namespace</title>
|
||||
|
||||
<para>Beginning with Spring 3.0, there is an XML namespace for configuring
|
||||
<interfacename>TaskExecutor</interfacename> and
|
||||
<interfacename>TaskScheduler</interfacename> instances. It also provides a
|
||||
convenient way to configure tasks to be scheduled with a trigger.</para>
|
||||
|
||||
<section xml:id="scheduling-task-namespace-scheduler">
|
||||
<title>The 'scheduler' element</title>
|
||||
|
||||
<para>The following element will create a
|
||||
<classname>ThreadPoolTaskScheduler</classname> instance with the
|
||||
specified thread pool size.</para>
|
||||
|
||||
<programlisting language="xml"><task:scheduler id="scheduler" pool-size="10"/></programlisting>
|
||||
|
||||
<para>The value provided for the 'id' attribute will be used as the
|
||||
prefix for thread names within the pool. The 'scheduler' element is
|
||||
relatively straightforward. If you do not provide a 'pool-size'
|
||||
attribute, the default thread pool will only have a single thread. There
|
||||
are no other configuration options for the scheduler.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="scheduling-task-namespace-executor">
|
||||
<title>The 'executor' element</title>
|
||||
|
||||
<para>The following will create a
|
||||
<classname>ThreadPoolTaskExecutor</classname> instance: <programlisting
|
||||
language="xml"><task:executor id="executor" pool-size="10"/></programlisting></para>
|
||||
|
||||
<para>As with the scheduler above, the value provided for the 'id'
|
||||
attribute will be used as the prefix for thread names within the pool.
|
||||
As far as the pool size is concerned, the 'executor' element supports
|
||||
more configuration options than the 'scheduler' element. For one thing,
|
||||
the thread pool for a <classname>ThreadPoolTaskExecutor</classname> is
|
||||
itself more configurable. Rather than just a single size, an executor's
|
||||
thread pool may have different values for the <emphasis>core</emphasis>
|
||||
and the <emphasis>max</emphasis> size. If a single value is provided
|
||||
then the executor will have a fixed-size thread pool (the core and max
|
||||
sizes are the same). However, the 'executor' element's 'pool-size'
|
||||
attribute also accepts a range in the form of "min-max". <programlisting
|
||||
language="xml"><task:executor id="executorWithPoolSizeRange"
|
||||
pool-size="5-25"
|
||||
queue-capacity="100"/></programlisting></para>
|
||||
|
||||
<para>As you can see from that configuration, a 'queue-capacity' value
|
||||
has also been provided. The configuration of the thread pool should also
|
||||
be considered in light of the executor's queue capacity. For the full
|
||||
description of the relationship between pool size and queue capacity,
|
||||
consult the documentation for <link
|
||||
xl:href="http://java.sun.com/javase/6/docs/api/java/util/concurrent/ThreadPoolExecutor.html">ThreadPoolExecutor</link>.
|
||||
The main idea is that when a task is submitted, the executor will first
|
||||
try to use a free thread if the number of active threads is currently
|
||||
less than the core size. If the core size has been reached, then the
|
||||
task will be added to the queue as long as its capacity has not yet been
|
||||
reached. Only then, if the queue's capacity <emphasis>has</emphasis>
|
||||
been reached, will the executor create a new thread beyond the core
|
||||
size. If the max size has also been reached, then the executor will
|
||||
reject the task.</para>
|
||||
|
||||
<para>By default, the queue is <emphasis>unbounded</emphasis>, but this
|
||||
is rarely the desired configuration, because it can lead to
|
||||
<classname>OutOfMemoryErrors</classname> if enough tasks are added to
|
||||
that queue while all pool threads are busy. Furthermore, if the queue is
|
||||
unbounded, then the max size has no effect at all. Since the executor
|
||||
will always try the queue before creating a new thread beyond the core
|
||||
size, a queue must have a finite capacity for the thread pool to grow
|
||||
beyond the core size (this is why a <emphasis>fixed size</emphasis> pool
|
||||
is the only sensible case when using an unbounded queue).</para>
|
||||
|
||||
<para>In a moment, we will review the effects of the keep-alive setting
|
||||
which adds yet another factor to consider when providing a pool size
|
||||
configuration. First, let's consider the case, as mentioned above, when
|
||||
a task is rejected. By default, when a task is rejected, a thread pool
|
||||
executor will throw a <classname>TaskRejectedException</classname>.
|
||||
However, the rejection policy is actually configurable. The exception is
|
||||
thrown when using the default rejection policy which is the
|
||||
<classname>AbortPolicy</classname> implementation. For applications
|
||||
where some tasks can be skipped under heavy load, either the
|
||||
<classname>DiscardPolicy</classname> or
|
||||
<classname>DiscardOldestPolicy</classname> may be configured instead.
|
||||
Another option that works well for applications that need to throttle
|
||||
the submitted tasks under heavy load is the
|
||||
<classname>CallerRunsPolicy</classname>. Instead of throwing an
|
||||
exception or discarding tasks, that policy will simply force the thread
|
||||
that is calling the submit method to run the task itself. The idea is
|
||||
that such a caller will be busy while running that task and not able to
|
||||
submit other tasks immediately. Therefore it provides a simple way to
|
||||
throttle the incoming load while maintaining the limits of the thread
|
||||
pool and queue. Typically this allows the executor to "catch up" on the
|
||||
tasks it is handling and thereby frees up some capacity on the queue, in
|
||||
the pool, or both. Any of these options can be chosen from an
|
||||
enumeration of values available for the 'rejection-policy' attribute on
|
||||
the 'executor' element.</para>
|
||||
|
||||
<programlisting language="xml"><task:executor id="executorWithCallerRunsPolicy"
|
||||
pool-size="5-25"
|
||||
queue-capacity="100"
|
||||
rejection-policy="CALLER_RUNS"/></programlisting>
|
||||
</section>
|
||||
|
||||
<section xml:id="scheduling-task-namespace-scheduled-tasks">
|
||||
<title>The 'scheduled-tasks' element</title>
|
||||
|
||||
<para>The most powerful feature of Spring's task namespace is the
|
||||
support for configuring tasks to be scheduled within a Spring
|
||||
Application Context. This follows an approach similar to other
|
||||
"method-invokers" in Spring, such as that provided by the JMS namespace
|
||||
for configuring Message-driven POJOs. Basically a "ref" attribute can
|
||||
point to any Spring-managed object, and the "method" attribute provides
|
||||
the name of a method to be invoked on that object. Here is a simple
|
||||
example.</para>
|
||||
|
||||
<programlisting language="xml"><task:scheduled-tasks scheduler="myScheduler">
|
||||
<task:scheduled ref="beanA" method="methodA" fixed-delay="5000"/>
|
||||
</task:scheduled-tasks>
|
||||
|
||||
<task:scheduler id="myScheduler" pool-size="10"/></programlisting>
|
||||
|
||||
<para>As you can see, the scheduler is referenced by the outer element,
|
||||
and each individual task includes the configuration of its trigger
|
||||
metadata. In the preceding example, that metadata defines a periodic
|
||||
trigger with a fixed delay indicating the number of milliseconds to wait
|
||||
after each task execution has completed. Another option is 'fixed-rate',
|
||||
indicating how often the method should be executed regardless of how long
|
||||
any previous execution takes. Additionally, for both fixed-delay and
|
||||
fixed-rate tasks an 'initial-delay' parameter may be specified indicating
|
||||
the number of milliseconds to wait before the first execution of the
|
||||
method. For more control, a "cron" attribute may be provided instead.
|
||||
Here is an example demonstrating these other options.</para>
|
||||
|
||||
<programlisting language="xml"><task:scheduled-tasks scheduler="myScheduler">
|
||||
<task:scheduled ref="beanA" method="methodA" fixed-delay="5000" initial-delay="1000"/>
|
||||
<task:scheduled ref="beanB" method="methodB" fixed-rate="5000"/>
|
||||
<task:scheduled ref="beanC" method="methodC" cron="*/5 * * * * MON-FRI"/>
|
||||
</task:scheduled-tasks>
|
||||
|
||||
<task:scheduler id="myScheduler" pool-size="10"/></programlisting>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section xml:id="scheduling-quartz">
|
||||
<title>Using the Quartz Scheduler</title>
|
||||
|
||||
<para>Quartz uses <classname>Trigger</classname>,
|
||||
<classname>Job</classname> and <classname>JobDetail</classname> objects to
|
||||
realize scheduling of all kinds of jobs. For the basic concepts behind
|
||||
Quartz, have a look at <link
|
||||
xl:href="http://quartz-scheduler.org"></link>. For convenience
|
||||
purposes, Spring offers a couple of classes that simplify the usage of
|
||||
Quartz within Spring-based applications.</para>
|
||||
|
||||
<section xml:id="scheduling-quartz-jobdetail">
|
||||
<title>Using the JobDetailBean</title>
|
||||
|
||||
<para><classname>JobDetail</classname> objects contain all information
|
||||
needed to run a job. The Spring Framework provides a
|
||||
<classname>JobDetailBean</classname> that makes the
|
||||
<classname>JobDetail</classname> more of an actual JavaBean with
|
||||
sensible defaults. Let's have a look at an example:</para>
|
||||
|
||||
<programlisting language="xml">
|
||||
<bean name="exampleJob" class="org.springframework.scheduling.quartz.JobDetailBean">
|
||||
<property name="jobClass" value="example.ExampleJob" />
|
||||
<property name="jobDataAsMap">
|
||||
<map>
|
||||
<entry key="timeout" value="5" />
|
||||
</map>
|
||||
</property>
|
||||
</bean></programlisting>
|
||||
|
||||
<para>The job detail bean has all information it needs to run the job
|
||||
(<classname>ExampleJob</classname>). The timeout is specified in the job
|
||||
data map. The job data map is available through the
|
||||
<classname>JobExecutionContext</classname> (passed to you at execution
|
||||
time), but the <classname>JobDetailBean</classname> also maps the
|
||||
properties from the job data map to properties of the actual job. So in
|
||||
this case, if the <classname>ExampleJob</classname> contains a property
|
||||
named <literal>timeout</literal>, the
|
||||
<classname>JobDetailBean</classname> will automatically apply it:</para>
|
||||
|
||||
<programlisting language="java">package example;
|
||||
|
||||
public class ExampleJob extends QuartzJobBean {
|
||||
|
||||
private int timeout;
|
||||
|
||||
/**
|
||||
* Setter called after the ExampleJob is instantiated
|
||||
* with the value from the JobDetailBean (5)
|
||||
*/
|
||||
public void setTimeout(int timeout) {
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
protected void executeInternal(JobExecutionContext ctx) throws JobExecutionException {
|
||||
<lineannotation>// do the actual work</lineannotation>
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<para>All additional settings from the job detail bean are of course
|
||||
available to you as well.</para>
|
||||
|
||||
<para><emphasis>Note: Using the <literal>name</literal> and
|
||||
<literal>group</literal> properties, you can modify the name and the
|
||||
group of the job, respectively. By default, the name of the job matches
|
||||
the bean name of the job detail bean (in the example above, this is
|
||||
<literal>exampleJob</literal>).</emphasis></para>
|
||||
</section>
|
||||
|
||||
<section xml:id="scheduling-quartz-method-invoking-job">
|
||||
<title>Using the
|
||||
<classname>MethodInvokingJobDetailFactoryBean</classname></title>
|
||||
|
||||
<para>Often you just need to invoke a method on a specific object. Using
|
||||
the <classname>MethodInvokingJobDetailFactoryBean</classname> you can do
|
||||
exactly this:</para>
|
||||
|
||||
<programlisting language="xml"><bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
|
||||
<property name="targetObject" ref="exampleBusinessObject" />
|
||||
<property name="targetMethod" value="doIt" />
|
||||
</bean></programlisting>
|
||||
|
||||
<para>The above example will result in the <literal>doIt</literal>
|
||||
method being called on the <literal>exampleBusinessObject</literal>
|
||||
method (see below):</para>
|
||||
|
||||
<programlisting language="java">public class ExampleBusinessObject {
|
||||
|
||||
<lineannotation>// properties and collaborators</lineannotation>
|
||||
|
||||
public void doIt() {
|
||||
<lineannotation>// do the actual work</lineannotation>
|
||||
}
|
||||
}</programlisting>
|
||||
|
||||
<programlisting language="xml">
|
||||
<bean id="exampleBusinessObject" class="examples.ExampleBusinessObject"/></programlisting>
|
||||
|
||||
<para>Using the
|
||||
<classname>MethodInvokingJobDetailFactoryBean</classname>, you don't
|
||||
need to create one-line jobs that just invoke a method, and you only
|
||||
need to create the actual business object and wire up the detail
|
||||
object.</para>
|
||||
|
||||
<para>By default, Quartz Jobs are stateless, resulting in the
|
||||
possibility of jobs interfering with each other. If you specify two
|
||||
triggers for the same <classname>JobDetail</classname>, it might be
|
||||
possible that before the first job has finished, the second one will
|
||||
start. If <classname>JobDetail</classname> classes implement the
|
||||
<interfacename>Stateful</interfacename> interface, this won't happen.
|
||||
The second job will not start before the first one has finished. To make
|
||||
jobs resulting from the
|
||||
<classname>MethodInvokingJobDetailFactoryBean</classname>
|
||||
non-concurrent, set the <literal>concurrent</literal> flag to
|
||||
<literal>false</literal>.</para>
|
||||
|
||||
<programlisting language="xml">
|
||||
<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
|
||||
<property name="targetObject" ref="exampleBusinessObject" />
|
||||
<property name="targetMethod" value="doIt" />
|
||||
<property name="concurrent" value="false" />
|
||||
</bean></programlisting>
|
||||
|
||||
<note>
|
||||
<para>By default, jobs will run in a concurrent fashion.</para>
|
||||
</note>
|
||||
</section>
|
||||
|
||||
<section xml:id="scheduling-quartz-cron">
|
||||
<title>Wiring up jobs using triggers and the
|
||||
<classname>SchedulerFactoryBean</classname></title>
|
||||
|
||||
<para>We've created job details and jobs. We've also reviewed the
|
||||
convenience bean that allows you to invoke a method on a specific
|
||||
object. Of course, we still need to schedule the jobs themselves. This
|
||||
is done using triggers and a
|
||||
<classname>SchedulerFactoryBean</classname>. Several triggers are
|
||||
available within Quartz and Spring offers two Quartz <interfacename>FactoryBean</interfacename>
|
||||
implementations with convenient defaults: <classname>CronTriggerFactoryBean</classname> and
|
||||
<classname>SimpleTriggerFactoryBean</classname>.</para>
|
||||
|
||||
<para>Triggers need to be scheduled. Spring offers a
|
||||
<classname>SchedulerFactoryBean</classname> that exposes triggers to be
|
||||
set as properties. <classname>SchedulerFactoryBean</classname> schedules
|
||||
the actual jobs with those triggers.</para>
|
||||
|
||||
<para>Find below a couple of examples:</para>
|
||||
|
||||
<programlisting language="xml"><bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
|
||||
<!-- see the example of method invoking job above -->
|
||||
<property name="jobDetail" ref="jobDetail" />
|
||||
<!-- 10 seconds -->
|
||||
<property name="startDelay" value="10000" />
|
||||
<!-- repeat every 50 seconds -->
|
||||
<property name="repeatInterval" value="50000" />
|
||||
</bean>
|
||||
|
||||
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
|
||||
<property name="jobDetail" ref="exampleJob" />
|
||||
<!-- run every morning at 6 AM -->
|
||||
<property name="cronExpression" value="0 0 6 * * ?" />
|
||||
</bean></programlisting>
|
||||
|
||||
<para>Now we've set up two triggers, one running every 50 seconds with a
|
||||
starting delay of 10 seconds and one every morning at 6 AM. To finalize
|
||||
everything, we need to set up the
|
||||
<classname>SchedulerFactoryBean</classname>:</para>
|
||||
|
||||
<programlisting language="xml"><bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
|
||||
<property name="triggers">
|
||||
<list>
|
||||
<ref bean="cronTrigger" />
|
||||
<ref bean="simpleTrigger" />
|
||||
</list>
|
||||
</property>
|
||||
</bean></programlisting>
|
||||
|
||||
<para>More properties are available for the
|
||||
<classname>SchedulerFactoryBean</classname> for you to set, such as the
|
||||
calendars used by the job details, properties to customize Quartz with,
|
||||
etc. Have a look at the <link
|
||||
xl:href="http://static.springsource.org/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/quartz/SchedulerFactoryBean.html">SchedulerFactoryBean
|
||||
Javadoc</link> for more information.</para>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,969 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<appendix xml:id="spring.tld"
|
||||
xmlns="http://docbook.org/ns/docbook" version="5.0"
|
||||
xmlns:xl="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
|
||||
http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd">
|
||||
<title>spring.tld</title>
|
||||
<section xml:id="spring.tld-intro">
|
||||
<title>Introduction</title>
|
||||
<para>One of the view technologies you can use with the Spring Framework
|
||||
is Java Server Pages (JSPs). To help you implement views using Java Server Pages
|
||||
the Spring Framework provides you with some tags for evaluating errors, setting
|
||||
themes and outputting internationalized messages.</para>
|
||||
<para>Please note that the various tags generated by this form tag library
|
||||
are compliant with the <link xl:href="http://www.w3.org/TR/xhtml1/">XHTML-1.0-Strict specification</link> and attendant <link xl:href="http://www.w3.org/TR/xhtml1/dtds.html#a_dtd_XHTML-1.0-Strict">DTD</link>.</para>
|
||||
<para>This appendix describes the <literal>spring.tld</literal> tag library.</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<xref linkend="spring.tld.bind"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<xref linkend="spring.tld.escapeBody"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<xref linkend="spring.tld.hasBindErrors"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<xref linkend="spring.tld.htmlEscape"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<xref linkend="spring.tld.message"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<xref linkend="spring.tld.nestedPath"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<xref linkend="spring.tld.theme"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<xref linkend="spring.tld.transform"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<xref linkend="spring.tld.url"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<xref linkend="spring.tld.eval"/>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
<section xml:id="spring.tld.bind">
|
||||
<title>The <literal>bind</literal> tag</title>
|
||||
<para>
|
||||
Provides BindStatus object for the given bind path.
|
||||
The HTML escaping flag participates in a page-wide or application-wide setting
|
||||
(i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml).
|
||||
</para>
|
||||
<table xml:id="spring.tld.bind.table">
|
||||
<title>Attributes</title>
|
||||
<tgroup cols="4">
|
||||
<colspec align="center" colname="Attribute"/>
|
||||
<colspec align="center" colname="Required"/>
|
||||
<colspec align="center" colname="Runtime.Expression"/>
|
||||
<colspec align="left" colname="Description"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry align="center">Attribute</entry>
|
||||
<entry align="center">Required?</entry>
|
||||
<entry align="center">Runtime Expression?</entry>
|
||||
<entry align="left">Description</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>
|
||||
<para>htmlEscape</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Set HTML escaping for this tag, as boolean value. Overrides
|
||||
the default HTML escaping setting for the current page.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>ignoreNestedPath</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Set whether to ignore a nested path, if any. Default is to not ignore.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>path</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>The path to the bean or bean property to bind status
|
||||
information for. For instance account.name, company.address.zipCode
|
||||
or just employee. The status object will exported to the page scope,
|
||||
specifically for this bean or bean property</para>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<section xml:id="spring.tld.escapeBody">
|
||||
<title>The <literal>escapeBody</literal> tag</title>
|
||||
<para>
|
||||
Escapes its enclosed body content, applying HTML escaping and/or JavaScript escaping.
|
||||
The HTML escaping flag participates in a page-wide or application-wide setting
|
||||
(i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml).
|
||||
</para>
|
||||
<table xml:id="spring.tld.escapeBody.table">
|
||||
<title>Attributes</title>
|
||||
<tgroup cols="4">
|
||||
<colspec align="center" colname="Attribute"/>
|
||||
<colspec align="center" colname="Required"/>
|
||||
<colspec align="center" colname="Runtime.Expression"/>
|
||||
<colspec align="left" colname="Description"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry align="center">Attribute</entry>
|
||||
<entry align="center">Required?</entry>
|
||||
<entry align="center">Runtime Expression?</entry>
|
||||
<entry align="left">Description</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>
|
||||
<para>htmlEscape</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Set HTML escaping for this tag, as boolean value. Overrides the
|
||||
default HTML escaping setting for the current page.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>javaScriptEscape</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Set JavaScript escaping for this tag, as boolean value.
|
||||
Default is false.</para>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</section>
|
||||
<section xml:id="spring.tld.hasBindErrors">
|
||||
<title>The <literal>hasBindErrors</literal> tag</title>
|
||||
<para>
|
||||
Provides Errors instance in case of bind errors.
|
||||
The HTML escaping flag participates in a page-wide or application-wide setting
|
||||
(i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml).
|
||||
</para>
|
||||
<table xml:id="spring.tld.hasBindErrors.table">
|
||||
<title>Attributes</title>
|
||||
<tgroup cols="4">
|
||||
<colspec align="center" colname="Attribute"/>
|
||||
<colspec align="center" colname="Required"/>
|
||||
<colspec align="center" colname="Runtime.Expression"/>
|
||||
<colspec align="left" colname="Description"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry align="center">Attribute</entry>
|
||||
<entry align="center">Required?</entry>
|
||||
<entry align="center">Runtime Expression?</entry>
|
||||
<entry align="left">Description</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>
|
||||
<para>htmlEscape</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Set HTML escaping for this tag, as boolean value.
|
||||
Overrides the default HTML escaping setting for the current page.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>name</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>The name of the bean in the request, that needs to be
|
||||
inspected for errors. If errors are available for this bean, they
|
||||
will be bound under the 'errors' key.</para>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</section>
|
||||
<section xml:id="spring.tld.htmlEscape">
|
||||
<title>The <literal>htmlEscape</literal> tag</title>
|
||||
<para>
|
||||
Sets default HTML escape value for the current page.
|
||||
Overrides a "defaultHtmlEscape" context-param in web.xml, if any.
|
||||
</para>
|
||||
<table xml:id="spring.tld.htmlEscape.table">
|
||||
<title>Attributes</title>
|
||||
<tgroup cols="4">
|
||||
<colspec align="center" colname="Attribute"/>
|
||||
<colspec align="center" colname="Required"/>
|
||||
<colspec align="center" colname="Runtime.Expression"/>
|
||||
<colspec align="left" colname="Description"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry align="center">Attribute</entry>
|
||||
<entry align="center">Required?</entry>
|
||||
<entry align="center">Runtime Expression?</entry>
|
||||
<entry align="left">Description</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>
|
||||
<para>defaultHtmlEscape</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Set the default value for HTML escaping, to be put
|
||||
into the current PageContext.</para>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</section>
|
||||
<section xml:id="spring.tld.message">
|
||||
<title>The <literal>message</literal> tag</title>
|
||||
<para>
|
||||
Retrieves the message with the given code, or text if code isn't resolvable.
|
||||
The HTML escaping flag participates in a page-wide or application-wide setting
|
||||
(i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml).
|
||||
</para>
|
||||
<table xml:id="spring.tld.message.table">
|
||||
<title>Attributes</title>
|
||||
<tgroup cols="4">
|
||||
<colspec align="center" colname="Attribute"/>
|
||||
<colspec align="center" colname="Required"/>
|
||||
<colspec align="center" colname="Runtime.Expression"/>
|
||||
<colspec align="left" colname="Description"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry align="center">Attribute</entry>
|
||||
<entry align="center">Required?</entry>
|
||||
<entry align="center">Runtime Expression?</entry>
|
||||
<entry align="left">Description</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>
|
||||
<para>arguments</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Set optional message arguments for this tag, as a
|
||||
(comma-)delimited String (each String argument can contain JSP EL),
|
||||
an Object array (used as argument array), or a single Object (used
|
||||
as single argument).</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>argumentSeparator</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>The separator character to be used for splitting the
|
||||
arguments string value; defaults to a 'comma' (',').</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>code</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>The code (key) to use when looking up the message.
|
||||
If code is not provided, the text attribute will be used.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>htmlEscape</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Set HTML escaping for this tag, as boolean value.
|
||||
Overrides the default HTML escaping setting for the current page.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>javaScriptEscape</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Set JavaScript escaping for this tag, as boolean value. Default is false.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>message</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>A MessageSourceResolvable argument (direct or through JSP EL).
|
||||
Fits nicely when used in conjunction with Spring's own validation error
|
||||
classes which all implement the MessageSourceResolvable interface. For
|
||||
example, this allows you to iterate over all of the errors in a form,
|
||||
passing each error (using a runtime expression) as the value of this
|
||||
'message' attribute, thus effecting the easy display of such error
|
||||
messages.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>scope</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>The scope to use when exporting the result to a variable.
|
||||
This attribute is only used when var is also set. Possible values are
|
||||
page, request, session and application.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>text</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Default text to output when a message for the given code
|
||||
could not be found. If both text and code are not set, the tag will
|
||||
output null.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>var</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>The string to use when binding the result to the page,
|
||||
request, session or application scope. If not specified, the result
|
||||
gets outputted to the writer (i.e. typically directly to the JSP).</para>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</section>
|
||||
<section xml:id="spring.tld.nestedPath">
|
||||
<title>The <literal>nestedPath</literal> tag</title>
|
||||
<para>
|
||||
Sets a nested path to be used by the bind tag's path.
|
||||
</para>
|
||||
<table xml:id="spring.tld.nestedPath.table">
|
||||
<title>Attributes</title>
|
||||
<tgroup cols="4">
|
||||
<colspec align="center" colname="Attribute"/>
|
||||
<colspec align="center" colname="Required"/>
|
||||
<colspec align="center" colname="Runtime.Expression"/>
|
||||
<colspec align="left" colname="Description"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry align="center">Attribute</entry>
|
||||
<entry align="center">Required?</entry>
|
||||
<entry align="center">Runtime Expression?</entry>
|
||||
<entry align="left">Description</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>
|
||||
<para>path</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Set the path that this tag should apply. E.g. 'customer'
|
||||
to allow bind paths like 'address.street' rather than
|
||||
'customer.address.street'.</para>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</section>
|
||||
<section xml:id="spring.tld.theme">
|
||||
<title>The <literal>theme</literal> tag</title>
|
||||
<para>
|
||||
Retrieves the theme message with the given code, or text if code isn't resolvable.
|
||||
The HTML escaping flag participates in a page-wide or application-wide setting
|
||||
(i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml).
|
||||
</para>
|
||||
<table xml:id="spring.tld.theme.table">
|
||||
<title>Attributes</title>
|
||||
<tgroup cols="4">
|
||||
<colspec align="center" colname="Attribute"/>
|
||||
<colspec align="center" colname="Required"/>
|
||||
<colspec align="center" colname="Runtime.Expression"/>
|
||||
<colspec align="left" colname="Description"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry align="center">Attribute</entry>
|
||||
<entry align="center">Required?</entry>
|
||||
<entry align="center">Runtime Expression?</entry>
|
||||
<entry align="left">Description</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>
|
||||
<para>arguments</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Set optional message arguments for this tag, as a
|
||||
(comma-)delimited String (each String argument can contain JSP EL),
|
||||
an Object array (used as argument array), or a single Object (used
|
||||
as single argument).</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>argumentSeparator</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>The separator character to be used for splitting the
|
||||
arguments string value; defaults to a 'comma' (',').</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>code</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>The code (key) to use when looking up the message.
|
||||
If code is not provided, the text attribute will be used.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>htmlEscape</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Set HTML escaping for this tag, as boolean value.
|
||||
Overrides the default HTML escaping setting for the current page.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>javaScriptEscape</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Set JavaScript escaping for this tag, as boolean value. Default is false.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>message</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>A MessageSourceResolvable argument (direct or through JSP EL).</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>scope</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>The scope to use when exporting the result to a variable.
|
||||
This attribute is only used when var is also set. Possible values are
|
||||
page, request, session and application.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>text</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Default text to output when a message for the given code
|
||||
could not be found. If both text and code are not set, the tag will
|
||||
output null.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>var</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>The string to use when binding the result to the page,
|
||||
request, session or application scope. If not specified, the result
|
||||
gets outputted to the writer (i.e. typically directly to the JSP).</para>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</section>
|
||||
<section xml:id="spring.tld.transform">
|
||||
<title>The <literal>transform</literal> tag</title>
|
||||
<para>
|
||||
Provides transformation of variables to Strings, using an appropriate
|
||||
custom PropertyEditor from BindTag (can only be used inside BindTag).
|
||||
The HTML escaping flag participates in a page-wide or application-wide setting
|
||||
(i.e. by HtmlEscapeTag or a 'defaultHtmlEscape' context-param in web.xml).
|
||||
</para>
|
||||
<table xml:id="spring.tld.transform.table">
|
||||
<title>Attributes</title>
|
||||
<tgroup cols="4">
|
||||
<colspec align="center" colname="Attribute"/>
|
||||
<colspec align="center" colname="Required"/>
|
||||
<colspec align="center" colname="Runtime.Expression"/>
|
||||
<colspec align="left" colname="Description"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry align="center">Attribute</entry>
|
||||
<entry align="center">Required?</entry>
|
||||
<entry align="center">Runtime Expression?</entry>
|
||||
<entry align="left">Description</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>
|
||||
<para>htmlEscape</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Set HTML escaping for this tag, as boolean value. Overrides
|
||||
the default HTML escaping setting for the current page.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>scope</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>The scope to use when exported the result to a variable.
|
||||
This attribute is only used when var is also set. Possible values are
|
||||
page, request, session and application.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>value</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>The value to transform. This is the actual object you want
|
||||
to have transformed (for instance a Date). Using the PropertyEditor that
|
||||
is currently in use by the 'spring:bind' tag.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>var</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>The string to use when binding the result to the page,
|
||||
request, session or application scope. If not specified, the result gets
|
||||
outputted to the writer (i.e. typically directly to the JSP).</para>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</section>
|
||||
<section xml:id="spring.tld.url">
|
||||
<title>The <literal>url</literal> tag</title>
|
||||
<para>
|
||||
Creates URLs with support for URI template variables, HTML/XML escaping, and Javascript escaping.
|
||||
Modeled after the JSTL c:url tag with backwards compatibility in mind.
|
||||
</para>
|
||||
<table xml:id="spring.tld.url.table">
|
||||
<title>Attributes</title>
|
||||
<tgroup cols="4">
|
||||
<colspec align="center" colname="Attribute"/>
|
||||
<colspec align="center" colname="Required"/>
|
||||
<colspec align="center" colname="Runtime.Expression"/>
|
||||
<colspec align="left" colname="Description"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry align="center">Attribute</entry>
|
||||
<entry align="center">Required?</entry>
|
||||
<entry align="center">Runtime Expression?</entry>
|
||||
<entry align="left">Description</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>
|
||||
<para>url</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>The URL to build. This value can include template {placeholders}
|
||||
that are replaced with the URL encoded value of the named parameter. Parameters
|
||||
must be defined using the param tag inside the body of this tag.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>context</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Specifies a remote application context path. The default is the
|
||||
current application context path.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>var</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>The name of the variable to export the URL value to.
|
||||
If not specified the URL is written as output.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>scope</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>The scope for the var. 'application', 'session', 'request' and
|
||||
'page' scopes are supported. Defaults to page scope. This attribute has no
|
||||
effect unless the var attribute is also defined.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>htmlEscape</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Set HTML escaping for this tag, as a boolean value. Overrides the
|
||||
default HTML escaping setting for the current page.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>javaScriptEscape</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Set JavaScript escaping for this tag, as a boolean value.
|
||||
Default is false.</para>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</section>
|
||||
<section xml:id="spring.tld.eval">
|
||||
<title>The <literal>eval</literal> tag</title>
|
||||
<para>
|
||||
Evaluates a Spring expression (SpEL) and either prints the result or assigns it to a variable.
|
||||
</para>
|
||||
<table xml:id="spring.tld.eval.table">
|
||||
<title>Attributes</title>
|
||||
<tgroup cols="4">
|
||||
<colspec align="center" colname="Attribute"/>
|
||||
<colspec align="center" colname="Required"/>
|
||||
<colspec align="center" colname="Runtime.Expression"/>
|
||||
<colspec align="left" colname="Description"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry align="center">Attribute</entry>
|
||||
<entry align="center">Required?</entry>
|
||||
<entry align="center">Runtime Expression?</entry>
|
||||
<entry align="left">Description</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>
|
||||
<para>expression</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>The expression to evaluate.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>var</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>The name of the variable to export the evaluation result to.
|
||||
If not specified the evaluation result is converted to a String and written as output.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>scope</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>The scope for the var. 'application', 'session', 'request' and
|
||||
'page' scopes are supported. Defaults to page scope. This attribute has no
|
||||
effect unless the var attribute is also defined.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>htmlEscape</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Set HTML escaping for this tag, as a boolean value. Overrides the
|
||||
default HTML escaping setting for the current page.</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<para>javaScriptEscape</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>false</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>true</para>
|
||||
</entry>
|
||||
<entry>
|
||||
<para>Set JavaScript escaping for this tag, as a boolean value.
|
||||
Default is false.</para>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</section>
|
||||
</appendix>
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<sidebar
|
||||
xmlns="http://docbook.org/ns/docbook" version="5.0"
|
||||
xmlns:xl="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
|
||||
http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd">
|
||||
<title>Spring Web Flow</title>
|
||||
|
||||
<para>Spring Web Flow (SWF) aims to be the best solution for the management
|
||||
of web application page flow.</para>
|
||||
|
||||
<para>SWF integrates with existing frameworks like Spring MVC, Struts, and
|
||||
JSF, in both servlet and portlet environments. If you have a business
|
||||
process (or processes) that would benefit from a conversational model as
|
||||
opposed to a purely request model, then SWF may be the solution.</para>
|
||||
|
||||
<para>SWF allows you to capture logical page flows as self-contained modules
|
||||
that are reusable in different situations, and as such is ideal for building
|
||||
web application modules that guide the user through controlled navigations
|
||||
that drive business processes.</para>
|
||||
|
||||
<para>For more information about SWF, consult the
|
||||
<link xl:href="http://www.springframework.org/webflow">Spring Web Flow website</link>.
|
||||
</para>
|
||||
</sidebar>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -1,610 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<appendix xml:id="extensible-xml"
|
||||
xmlns="http://docbook.org/ns/docbook" version="5.0"
|
||||
xmlns:xl="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
|
||||
http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd">
|
||||
<title>Extensible XML authoring</title>
|
||||
<section xml:id="extensible-xml-introduction">
|
||||
<title>Introduction</title>
|
||||
<para>Since version 2.0, Spring has featured a mechanism for schema-based extensions
|
||||
to the basic Spring XML format for defining and configuring beans. This section is
|
||||
devoted to detailing how you would go about writing your own custom XML bean definition
|
||||
parsers and integrating such parsers into the Spring IoC container.</para>
|
||||
<para>To facilitate the authoring of configuration files using a schema-aware XML editor,
|
||||
Spring's extensible XML configuration mechanism is based on XML Schema. If you are
|
||||
not familiar with Spring's current XML configuration extensions that come with the
|
||||
standard Spring distribution, please first read the appendix entitled
|
||||
<xref linkend="xsd-config"/>.</para>
|
||||
<para>Creating new XML configuration extensions can be done by following these (relatively)
|
||||
simple steps:</para>
|
||||
<para>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem>
|
||||
<para><link linkend="extensible-xml-schema">Authoring</link> an XML schema to describe your custom element(s).</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><link linkend="extensible-xml-namespacehandler">Coding</link> a custom <interfacename>NamespaceHandler</interfacename>
|
||||
implementation (this is an easy step, don't worry).</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><link linkend="extensible-xml-parser">Coding</link> one or more <interfacename>BeanDefinitionParser</interfacename>
|
||||
implementations (this is where the real work is done).</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><link linkend="extensible-xml-registration">Registering</link> the above artifacts with Spring (this too is an easy step).</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
</para>
|
||||
<para>What follows is a description of each of these steps. For the example, we will create
|
||||
an XML extension (a custom XML element) that allows us to configure objects of the type
|
||||
<classname>SimpleDateFormat</classname> (from the <literal>java.text</literal> package)
|
||||
in an easy manner. When we are done, we will be able to define bean definitions of type
|
||||
<classname>SimpleDateFormat</classname> like this:</para>
|
||||
<programlisting language="xml"><![CDATA[<myns:dateformat id="dateFormat"
|
||||
pattern="yyyy-MM-dd HH:mm"
|
||||
lenient="true"/>
|
||||
]]></programlisting>
|
||||
<para><emphasis>(Don't worry about the fact that this example is very simple; much more
|
||||
detailed examples follow afterwards. The intent in this first simple example is to walk
|
||||
you through the basic steps involved.)</emphasis></para>
|
||||
</section>
|
||||
<section xml:id="extensible-xml-schema">
|
||||
<title>Authoring the schema</title>
|
||||
<para>Creating an XML configuration extension for use with Spring's IoC container
|
||||
starts with authoring an XML Schema to describe the extension. What follows
|
||||
is the schema we'll use to configure <classname>SimpleDateFormat</classname>
|
||||
objects.</para>
|
||||
<programlisting language="xml"><lineannotation><!-- myns.xsd (inside package org/springframework/samples/xml) --></lineannotation><![CDATA[
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsd:schema xmlns="http://www.mycompany.com/schema/myns"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
targetNamespace="http://www.mycompany.com/schema/myns"
|
||||
elementFormDefault="qualified"
|
||||
attributeFormDefault="unqualified">
|
||||
|
||||
<xsd:import namespace="http://www.springframework.org/schema/beans"/>
|
||||
|
||||
<xsd:element name="dateformat">
|
||||
<xsd:complexType>
|
||||
<xsd:complexContent>]]>
|
||||
<emphasis role="bold"><![CDATA[<xsd:extension base="beans:identifiedType">]]></emphasis><![CDATA[
|
||||
<xsd:attribute name="lenient" type="xsd:boolean"/>
|
||||
<xsd:attribute name="pattern" type="xsd:string" use="required"/>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
</xsd:schema>]]></programlisting>
|
||||
<para>(The emphasized line contains an extension base for all tags that
|
||||
will be identifiable (meaning they have an <literal>id</literal> attribute
|
||||
that will be used as the bean identifier in the container). We are able to use this
|
||||
attribute because we imported the Spring-provided <literal>'beans'</literal>
|
||||
namespace.)</para>
|
||||
<para>The above schema will be used to configure <classname>SimpleDateFormat</classname>
|
||||
objects, directly in an XML application context file using the
|
||||
<literal><myns:dateformat/></literal> element.</para>
|
||||
<programlisting language="xml"><![CDATA[<myns:dateformat id="dateFormat"
|
||||
pattern="yyyy-MM-dd HH:mm"
|
||||
lenient="true"/>
|
||||
]]></programlisting>
|
||||
<para>Note that after we've created the infrastructure classes, the above snippet of XML
|
||||
will essentially be exactly the same as the following XML snippet. In other words,
|
||||
we're just creating a bean in the container, identified by the name
|
||||
<literal>'dateFormat'</literal> of type <classname>SimpleDateFormat</classname>, with a
|
||||
couple of properties set.</para>
|
||||
<programlisting language="xml"><![CDATA[<bean id="dateFormat" class="java.text.SimpleDateFormat">
|
||||
<constructor-arg value="yyyy-HH-dd HH:mm"/>
|
||||
<property name="lenient" value="true"/>
|
||||
</bean>]]></programlisting>
|
||||
<note>
|
||||
<para>The schema-based approach to creating configuration format allows for
|
||||
tight integration with an IDE that has a schema-aware XML editor. Using a properly
|
||||
authored schema, you can use autocompletion to have a user choose between several
|
||||
configuration options defined in the enumeration.</para>
|
||||
</note>
|
||||
</section>
|
||||
<section xml:id="extensible-xml-namespacehandler">
|
||||
<title>Coding a <interfacename>NamespaceHandler</interfacename></title>
|
||||
<para>In addition to the schema, we need a <interfacename>NamespaceHandler</interfacename>
|
||||
that will parse all elements of this specific namespace Spring encounters
|
||||
while parsing configuration files. The <interfacename>NamespaceHandler</interfacename>
|
||||
should in our case take care of the parsing of the <literal>myns:dateformat</literal>
|
||||
element.</para>
|
||||
<para>The <interfacename>NamespaceHandler</interfacename> interface is pretty simple in that
|
||||
it features just three methods:</para>
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para><methodname>init()</methodname> - allows for initialization of
|
||||
the <interfacename>NamespaceHandler</interfacename> and will be called by Spring
|
||||
before the handler is used</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><methodname>BeanDefinition parse(Element, ParserContext)</methodname> -
|
||||
called when Spring encounters a top-level element (not nested inside a bean definition
|
||||
or a different namespace). This method can register bean definitions itself and/or
|
||||
return a bean definition.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><methodname>BeanDefinitionHolder decorate(Node, BeanDefinitionHolder, ParserContext)</methodname> -
|
||||
called when Spring encounters an attribute or nested element of a different namespace.
|
||||
The decoration of one or more bean definitions is used for example with the
|
||||
<link linkend="beans-factory-scopes">out-of-the-box scopes Spring 2.0 supports</link>.
|
||||
We'll start by highlighting a simple example, without using decoration, after which
|
||||
we will show decoration in a somewhat more advanced example.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>Although it is perfectly possible to code your own
|
||||
<interfacename>NamespaceHandler</interfacename> for the entire namespace
|
||||
(and hence provide code that parses each and every element in the namespace),
|
||||
it is often the case that each top-level XML element in a Spring XML
|
||||
configuration file results in a single bean definition (as in our
|
||||
case, where a single <literal><myns:dateformat/></literal> element
|
||||
results in a single <classname>SimpleDateFormat</classname> bean definition).
|
||||
Spring features a number of convenience classes that support this scenario.
|
||||
In this example, we'll make use the <classname>NamespaceHandlerSupport</classname> class:</para>
|
||||
<programlisting language="java"><![CDATA[package org.springframework.samples.xml;
|
||||
|
||||
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
|
||||
|
||||
public class MyNamespaceHandler extends NamespaceHandlerSupport {
|
||||
|
||||
public void init() {]]><emphasis role="bold"><![CDATA[
|
||||
registerBeanDefinitionParser("dateformat", new SimpleDateFormatBeanDefinitionParser());
|
||||
]]></emphasis>}
|
||||
}</programlisting>
|
||||
<para>The observant reader will notice that there isn't actually a whole lot of
|
||||
parsing logic in this class. Indeed... the <classname>NamespaceHandlerSupport</classname>
|
||||
class has a built in notion of delegation. It supports the registration of any number
|
||||
of <interfacename>BeanDefinitionParser</interfacename> instances, to which it will delegate
|
||||
to when it needs to parse an element in its namespace. This clean separation of concerns
|
||||
allows a <interfacename>NamespaceHandler</interfacename> to handle the orchestration
|
||||
of the parsing of <emphasis>all</emphasis> of the custom elements in its namespace,
|
||||
while delegating to <literal>BeanDefinitionParsers</literal> to do the grunt work of the
|
||||
XML parsing; this means that each <interfacename>BeanDefinitionParser</interfacename> will
|
||||
contain just the logic for parsing a single custom element, as we can see in the next step</para>
|
||||
</section>
|
||||
<section xml:id="extensible-xml-parser">
|
||||
<title>Coding a <interfacename>BeanDefinitionParser</interfacename></title>
|
||||
<para>A <interfacename>BeanDefinitionParser</interfacename> will be used if the
|
||||
<interfacename>NamespaceHandler</interfacename> encounters an XML element of the type
|
||||
that has been mapped to the specific bean definition parser (which is <literal>'dateformat'</literal>
|
||||
in this case). In other words, the <interfacename>BeanDefinitionParser</interfacename> is
|
||||
responsible for parsing <emphasis>one</emphasis> distinct top-level XML element defined in the
|
||||
schema. In the parser, we'll have access to the XML element (and thus its subelements too)
|
||||
so that we can parse our custom XML content, as can be seen in the following example:</para>
|
||||
<programlisting language="java"><![CDATA[package org.springframework.samples.xml;
|
||||
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
public class SimpleDateFormatBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { ]]><co xml:id="extensible-xml-parser-simpledateformat-co-1"/><![CDATA[
|
||||
|
||||
protected Class getBeanClass(Element element) {
|
||||
return SimpleDateFormat.class; ]]><co xml:id="extensible-xml-parser-simpledateformat-co-2"/><![CDATA[
|
||||
}
|
||||
|
||||
protected void doParse(Element element, BeanDefinitionBuilder bean) {
|
||||
]]><lineannotation>// this will never be null since the schema explicitly requires that a value be supplied</lineannotation><![CDATA[
|
||||
String pattern = element.getAttribute("pattern");
|
||||
bean.addConstructorArg(pattern);
|
||||
|
||||
]]><lineannotation>// this however is an optional property</lineannotation><![CDATA[
|
||||
String lenient = element.getAttribute("lenient");
|
||||
if (StringUtils.hasText(lenient)) {
|
||||
bean.addPropertyValue("lenient", Boolean.valueOf(lenient));
|
||||
}
|
||||
}
|
||||
}]]></programlisting>
|
||||
<calloutlist>
|
||||
<callout arearefs="extensible-xml-parser-simpledateformat-co-1">
|
||||
<para>We use the Spring-provided <classname>AbstractSingleBeanDefinitionParser</classname>
|
||||
to handle a lot of the basic grunt work of creating a <emphasis>single</emphasis>
|
||||
<interfacename>BeanDefinition</interfacename>.</para>
|
||||
</callout>
|
||||
<callout arearefs="extensible-xml-parser-simpledateformat-co-2">
|
||||
<para>We supply the <classname>AbstractSingleBeanDefinitionParser</classname> superclass
|
||||
with the type that our single <interfacename>BeanDefinition</interfacename> will represent.</para>
|
||||
</callout>
|
||||
</calloutlist>
|
||||
<para>In this simple case, this is all that we need to do. The creation of our single
|
||||
<interfacename>BeanDefinition</interfacename> is handled by the <classname>AbstractSingleBeanDefinitionParser</classname>
|
||||
superclass, as is the extraction and setting of the bean definition's unique identifier.</para>
|
||||
</section>
|
||||
<section xml:id="extensible-xml-registration">
|
||||
<title>Registering the handler and the schema</title>
|
||||
<para>The coding is finished! All that remains to be done is to somehow make the Spring XML
|
||||
parsing infrastructure aware of our custom element; we do this by registering our custom
|
||||
<interfacename>namespaceHandler</interfacename> and custom XSD file in two special purpose
|
||||
properties files. These properties files are both placed in a
|
||||
<filename class="directory">'META-INF'</filename> directory in your application, and can, for
|
||||
example, be distributed alongside your binary classes in a JAR file. The Spring XML parsing
|
||||
infrastructure will automatically pick up your new extension by consuming these special
|
||||
properties files, the formats of which are detailed below.</para>
|
||||
<section xml:id="extensible-xml-registration-spring-handlers">
|
||||
<title><filename>'META-INF/spring.handlers'</filename></title>
|
||||
<para>The properties file called <filename>'spring.handlers'</filename> contains a mapping
|
||||
of XML Schema URIs to namespace handler classes. So for our example, we need to write the
|
||||
following:</para>
|
||||
<programlisting><![CDATA[http\://www.mycompany.com/schema/myns=org.springframework.samples.xml.MyNamespaceHandler]]></programlisting>
|
||||
<para><emphasis>(The <literal>':'</literal> character is a valid delimiter in the Java properties format,
|
||||
and so the <literal>':'</literal> character in the URI needs to be escaped with a backslash.)</emphasis></para>
|
||||
<para>The first part (the key) of the key-value pair is the URI associated with your custom namespace
|
||||
extension, and needs to <emphasis>match exactly</emphasis> the value of the
|
||||
<literal>'targetNamespace'</literal> attribute as specified in your custom XSD schema.</para>
|
||||
</section>
|
||||
<section xml:id="extensible-xml-registration-spring-schemas">
|
||||
<title><filename>'META-INF/spring.schemas'</filename></title>
|
||||
<para>The properties file called <filename>'spring.schemas'</filename> contains a mapping
|
||||
of XML Schema locations (referred to along with the schema declaration in XML files
|
||||
that use the schema as part of the <literal>'xsi:schemaLocation'</literal> attribute)
|
||||
to <emphasis>classpath</emphasis> resources. This file is needed to prevent Spring from
|
||||
absolutely having to use a default <interfacename>EntityResolver</interfacename> that requires
|
||||
Internet access to retrieve the schema file. If you specify the mapping in this properties file,
|
||||
Spring will search for the schema on the classpath (in this case <literal>'myns.xsd'</literal>
|
||||
in the <literal>'org.springframework.samples.xml'</literal> package):</para>
|
||||
<programlisting><![CDATA[http\://www.mycompany.com/schema/myns/myns.xsd=org/springframework/samples/xml/myns.xsd]]></programlisting>
|
||||
<para>The upshot of this is that you are encouraged to deploy your XSD file(s) right alongside
|
||||
the <interfacename>NamespaceHandler</interfacename> and <interfacename>BeanDefinitionParser</interfacename>
|
||||
classes on the classpath.</para>
|
||||
</section>
|
||||
</section>
|
||||
<section xml:id="extensible-xml-using">
|
||||
<title>Using a custom extension in your Spring XML configuration</title>
|
||||
<para>Using a custom extension that you yourself have implemented is no different from
|
||||
using one of the 'custom' extensions that Spring provides straight out of the box. Find below
|
||||
an example of using the custom <literal><dateformat/></literal> element developed in the
|
||||
previous steps in a Spring XML configuration file.</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"
|
||||
xmlns:myns="http://www.mycompany.com/schema/myns"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.mycompany.com/schema/myns http://www.mycompany.com/schema/myns/myns.xsd">
|
||||
|
||||
]]><lineannotation><!-- as a top-level bean --></lineannotation><![CDATA[
|
||||
<myns:dateformat id="defaultDateFormat" pattern="yyyy-MM-dd HH:mm" lenient="true"/>
|
||||
|
||||
<bean id="jobDetailTemplate" abstract="true">
|
||||
<property name="dateFormat">
|
||||
]]><lineannotation><!-- as an inner bean --></lineannotation><![CDATA[
|
||||
<myns:dateformat pattern="HH:mm MM-dd-yyyy"/>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
</beans>]]></programlisting>
|
||||
</section>
|
||||
<section xml:id="extensible-xml-meat">
|
||||
<title>Meatier examples</title>
|
||||
<para>Find below some much meatier examples of custom XML extensions.</para>
|
||||
<section xml:id="extensible-xml-custom-nested">
|
||||
<title>Nesting custom tags within custom tags</title>
|
||||
<para>This example illustrates how you might go about writing the various artifacts
|
||||
required to satisfy a target of the following configuration:</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"
|
||||
xmlns:foo="http://www.foo.com/schema/component"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.foo.com/schema/component http://www.foo.com/schema/component/component.xsd">
|
||||
|
||||
]]><lineannotation><![CDATA[<foo:component id="bionic-family" name="Bionic-1">
|
||||
<foo:component name="Mother-1">
|
||||
<foo:component name="Karate-1"/>
|
||||
<foo:component name="Sport-1"/>
|
||||
</foo:component>
|
||||
<foo:component name="Rock-1"/>
|
||||
</foo:component>]]></lineannotation><![CDATA[
|
||||
|
||||
</beans>]]></programlisting>
|
||||
<para>The above configuration actually nests custom extensions within each other. The class
|
||||
that is actually configured by the above <literal><foo:component/></literal>
|
||||
element is the <classname>Component</classname> class (shown directly below). Notice
|
||||
how the <classname>Component</classname> class does <emphasis>not</emphasis> expose
|
||||
a setter method for the <literal>'components'</literal> property; this makes it hard
|
||||
(or rather impossible) to configure a bean definition for the <classname>Component</classname>
|
||||
class using setter injection.</para>
|
||||
<programlisting language="java"><![CDATA[package com.foo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Component {
|
||||
|
||||
private String name;
|
||||
private List<Component> components = new ArrayList<Component> ();
|
||||
|
||||
]]><lineannotation>// mmm, there is no setter method for the 'components'</lineannotation><![CDATA[
|
||||
public void addComponent(Component component) {
|
||||
this.components.add(component);
|
||||
}
|
||||
|
||||
public List<Component> getComponents() {
|
||||
return components;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}]]></programlisting>
|
||||
<para>The typical solution to this issue is to create a custom <interfacename>FactoryBean</interfacename>
|
||||
that exposes a setter property for the <literal>'components'</literal> property.</para>
|
||||
<programlisting language="java"><![CDATA[package com.foo;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ComponentFactoryBean implements FactoryBean<Component> {
|
||||
|
||||
private Component parent;
|
||||
private List<Component> children;
|
||||
|
||||
public void setParent(Component parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public void setChildren(List<Component> children) {
|
||||
this.children = children;
|
||||
}
|
||||
|
||||
public Component getObject() throws Exception {
|
||||
if (this.children != null && this.children.size() > 0) {
|
||||
for (Component child : children) {
|
||||
this.parent.addComponent(child);
|
||||
}
|
||||
}
|
||||
return this.parent;
|
||||
}
|
||||
|
||||
public Class<Component> getObjectType() {
|
||||
return Component.class;
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
}]]></programlisting>
|
||||
<para>This is all very well, and does work nicely, but exposes a lot of Spring plumbing to the
|
||||
end user. What we are going to do is write a custom extension that hides away all of this
|
||||
Spring plumbing. If we stick to <link linkend="extensible-xml-introduction">the steps described
|
||||
previously</link>, we'll start off by creating the XSD schema to define the structure of
|
||||
our custom tag.</para>
|
||||
<programlisting language="xml"><![CDATA[<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
|
||||
<xsd:schema xmlns="http://www.foo.com/schema/component"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
targetNamespace="http://www.foo.com/schema/component"
|
||||
elementFormDefault="qualified"
|
||||
attributeFormDefault="unqualified">
|
||||
|
||||
<xsd:element name="component">
|
||||
<xsd:complexType>
|
||||
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:element ref="component"/>
|
||||
</xsd:choice>
|
||||
<xsd:attribute name="id" type="xsd:ID"/>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string"/>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
</xsd:schema>
|
||||
]]></programlisting>
|
||||
<para>We'll then create a custom <interfacename>NamespaceHandler</interfacename>.</para>
|
||||
<programlisting language="java"><![CDATA[package com.foo;
|
||||
|
||||
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
|
||||
|
||||
public class ComponentNamespaceHandler extends NamespaceHandlerSupport {
|
||||
|
||||
public void init() {
|
||||
registerBeanDefinitionParser("component", new ComponentBeanDefinitionParser());
|
||||
}
|
||||
}]]></programlisting>
|
||||
<para>Next up is the custom <interfacename>BeanDefinitionParser</interfacename>. Remember
|
||||
that what we are creating is a <interfacename>BeanDefinition</interfacename> describing
|
||||
a <classname>ComponentFactoryBean</classname>.</para>
|
||||
<programlisting language="java"><![CDATA[package com.foo;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ComponentBeanDefinitionParser extends AbstractBeanDefinitionParser {
|
||||
|
||||
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
|
||||
return parseComponentElement(element);
|
||||
}
|
||||
|
||||
private static AbstractBeanDefinition parseComponentElement(Element element) {
|
||||
BeanDefinitionBuilder factory = BeanDefinitionBuilder.rootBeanDefinition(ComponentFactoryBean.class);
|
||||
factory.addPropertyValue("parent", parseComponent(element));
|
||||
|
||||
List<Element> childElements = DomUtils.getChildElementsByTagName(element, "component");
|
||||
if (childElements != null && childElements.size() > 0) {
|
||||
parseChildComponents(childElements, factory);
|
||||
}
|
||||
|
||||
return factory.getBeanDefinition();
|
||||
}
|
||||
|
||||
private static BeanDefinition parseComponent(Element element) {
|
||||
BeanDefinitionBuilder component = BeanDefinitionBuilder.rootBeanDefinition(Component.class);
|
||||
component.addPropertyValue("name", element.getAttribute("name"));
|
||||
return component.getBeanDefinition();
|
||||
}
|
||||
|
||||
private static void parseChildComponents(List<Element> childElements, BeanDefinitionBuilder factory) {
|
||||
ManagedList<BeanDefinition> children = new ManagedList<BeanDefinition>(childElements.size());
|
||||
|
||||
for (Element element : childElements) {
|
||||
children.add(parseComponentElement(element));
|
||||
}
|
||||
|
||||
factory.addPropertyValue("children", children);
|
||||
}
|
||||
}]]></programlisting>
|
||||
<para>Lastly, the various artifacts need to be registered with the Spring XML infrastructure.</para>
|
||||
<programlisting><lineannotation># in 'META-INF/spring.handlers'</lineannotation><![CDATA[
|
||||
http\://www.foo.com/schema/component=com.foo.ComponentNamespaceHandler]]></programlisting>
|
||||
<programlisting><lineannotation># in 'META-INF/spring.schemas'</lineannotation><![CDATA[
|
||||
http\://www.foo.com/schema/component/component.xsd=com/foo/component.xsd]]></programlisting>
|
||||
</section>
|
||||
<section xml:id="extensible-xml-custom-just-attributes">
|
||||
<title>Custom attributes on 'normal' elements</title>
|
||||
<para>Writing your own custom parser and the associated artifacts isn't hard, but sometimes it
|
||||
is not the right thing to do. Consider the scenario where you need to add metadata to already
|
||||
existing bean definitions. In this case you certainly don't want to have to go off and write
|
||||
your own entire custom extension; rather you just want to add an additional attribute
|
||||
to the existing bean definition element.</para>
|
||||
<para>By way of another example, let's say that the service class that you are defining a bean
|
||||
definition for a service object that will (unknown to it) be accessing a clustered
|
||||
<link xl:href="http://jcp.org/en/jsr/detail?id=107">JCache</link>, and you want to ensure that
|
||||
the named JCache instance is eagerly started within the surrounding cluster:</para>
|
||||
<programlisting language="xml"><![CDATA[<bean id="checkingAccountService" class="com.foo.DefaultCheckingAccountService"
|
||||
]]><lineannotation>jcache:cache-name="checking.account"></lineannotation><![CDATA[
|
||||
]]><lineannotation><!-- other dependencies here... --></lineannotation><![CDATA[
|
||||
</bean>]]></programlisting>
|
||||
<para>What we are going to do here is create another <interfacename>BeanDefinition</interfacename>
|
||||
when the <literal>'jcache:cache-name'</literal> attribute is parsed; this
|
||||
<interfacename>BeanDefinition</interfacename> will then initialize the named JCache
|
||||
for us. We will also modify the existing <interfacename>BeanDefinition</interfacename> for the
|
||||
<literal>'checkingAccountService'</literal> so that it will have a dependency on this
|
||||
new JCache-initializing <interfacename>BeanDefinition</interfacename>.</para>
|
||||
<programlisting language="java"><![CDATA[package com.foo;
|
||||
|
||||
public class JCacheInitializer {
|
||||
|
||||
private String name;
|
||||
|
||||
public JCacheInitializer(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void initialize() {
|
||||
]]><lineannotation>// lots of JCache API calls to initialize the named cache...</lineannotation><![CDATA[
|
||||
}
|
||||
}]]></programlisting>
|
||||
<para>Now onto the custom extension. Firstly, the authoring of the XSD schema describing the
|
||||
custom attribute (quite easy in this case).</para>
|
||||
<programlisting language="xml"><![CDATA[<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
|
||||
<xsd:schema xmlns="http://www.foo.com/schema/jcache"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
targetNamespace="http://www.foo.com/schema/jcache"
|
||||
elementFormDefault="qualified">
|
||||
|
||||
<xsd:attribute name="cache-name" type="xsd:string"/>
|
||||
|
||||
</xsd:schema>
|
||||
]]></programlisting>
|
||||
<para>Next, the associated <interfacename>NamespaceHandler</interfacename>.</para>
|
||||
<programlisting language="java"><![CDATA[package com.foo;
|
||||
|
||||
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
|
||||
|
||||
public class JCacheNamespaceHandler extends NamespaceHandlerSupport {
|
||||
|
||||
public void init() {
|
||||
super.registerBeanDefinitionDecoratorForAttribute("cache-name",
|
||||
new JCacheInitializingBeanDefinitionDecorator());
|
||||
}
|
||||
}
|
||||
]]></programlisting>
|
||||
<para>Next, the parser. Note that in this case, because we are going to be parsing an XML
|
||||
attribute, we write a <interfacename>BeanDefinitionDecorator</interfacename> rather than a
|
||||
<interfacename>BeanDefinitionParser</interfacename>.</para>
|
||||
<programlisting language="java"><![CDATA[package com.foo;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.w3c.dom.Attr;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class JCacheInitializingBeanDefinitionDecorator implements BeanDefinitionDecorator {
|
||||
|
||||
private static final String[] EMPTY_STRING_ARRAY = new String[0];
|
||||
|
||||
public BeanDefinitionHolder decorate(
|
||||
Node source, BeanDefinitionHolder holder, ParserContext ctx) {
|
||||
String initializerBeanName = registerJCacheInitializer(source, ctx);
|
||||
createDependencyOnJCacheInitializer(holder, initializerBeanName);
|
||||
return holder;
|
||||
}
|
||||
|
||||
private void createDependencyOnJCacheInitializer(BeanDefinitionHolder holder, String initializerBeanName) {
|
||||
AbstractBeanDefinition definition = ((AbstractBeanDefinition) holder.getBeanDefinition());
|
||||
String[] dependsOn = definition.getDependsOn();
|
||||
if (dependsOn == null) {
|
||||
dependsOn = new String[]{initializerBeanName};
|
||||
} else {
|
||||
List dependencies = new ArrayList(Arrays.asList(dependsOn));
|
||||
dependencies.add(initializerBeanName);
|
||||
dependsOn = (String[]) dependencies.toArray(EMPTY_STRING_ARRAY);
|
||||
}
|
||||
definition.setDependsOn(dependsOn);
|
||||
}
|
||||
|
||||
private String registerJCacheInitializer(Node source, ParserContext ctx) {
|
||||
String cacheName = ((Attr) source).getValue();
|
||||
String beanName = cacheName + "-initializer";
|
||||
if (!ctx.getRegistry().containsBeanDefinition(beanName)) {
|
||||
BeanDefinitionBuilder initializer = BeanDefinitionBuilder.rootBeanDefinition(JCacheInitializer.class);
|
||||
initializer.addConstructorArg(cacheName);
|
||||
ctx.getRegistry().registerBeanDefinition(beanName, initializer.getBeanDefinition());
|
||||
}
|
||||
return beanName;
|
||||
}
|
||||
}
|
||||
]]></programlisting>
|
||||
<para>Lastly, the various artifacts need to be registered with the Spring XML infrastructure.</para>
|
||||
<programlisting><lineannotation># in 'META-INF/spring.handlers'</lineannotation><![CDATA[
|
||||
http\://www.foo.com/schema/jcache=com.foo.JCacheNamespaceHandler]]></programlisting>
|
||||
<programlisting><lineannotation># in 'META-INF/spring.schemas'</lineannotation><![CDATA[
|
||||
http\://www.foo.com/schema/jcache/jcache.xsd=com/foo/jcache.xsd]]></programlisting>
|
||||
</section>
|
||||
</section>
|
||||
<section xml:id="extensible-xml-resources">
|
||||
<title>Further Resources</title>
|
||||
<para>Find below links to further resources concerning XML Schema and the extensible XML support
|
||||
described in this chapter.</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>The <link xl:href="http://www.w3.org/TR/2004/REC-xmlschema-1-20041028/">XML Schema Part 1: Structures Second Edition</link></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>The <link xl:href="http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/">XML Schema Part 2: Datatypes Second Edition</link></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
</appendix>
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue