mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-09-25 16:29:28 +00:00
Added the Spring Framework reference documentation
git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@773 50f2f4bb-b051-0410-bef5-90022cba6387
This commit is contained in:
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
@@ -0,0 +1,125 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<chapter id="dao">
|
||||
<title>DAO support</title>
|
||||
<section id="dao-introduction">
|
||||
<title>Introduction</title>
|
||||
<para>
|
||||
The Data Access Object (DAO) support in Spring is aimed at
|
||||
making it easy to work with data access technologies like
|
||||
JDBC, Hibernate or JDO in a consistent way. This allows one
|
||||
to switch between the aforementioned persistence technologies
|
||||
fairly easily and it also allows one to code without worrying
|
||||
about catching exceptions that are specific to each technology.
|
||||
</para>
|
||||
</section>
|
||||
<section id="dao-exceptions">
|
||||
<title>Consistent exception hierarchy</title>
|
||||
<para>
|
||||
Spring provides a convenient translation from technology-specific
|
||||
exceptions like <classname>SQLException</classname> to its own
|
||||
exception class hierarchy with the
|
||||
<classname>DataAccessException</classname> as the root exception.
|
||||
These exceptions wrap the original exception so there is never
|
||||
any risk that one might lose any information as to what might
|
||||
have gone wrong.
|
||||
</para>
|
||||
<para>
|
||||
In addition to JDBC exceptions, Spring can also wrap Hibernate-specific
|
||||
exceptions, converting them from proprietary, checked exceptions
|
||||
(in the case of versions of Hibernate prior to Hibernate 3.0), to
|
||||
a set of focused runtime exceptions (the same is true for JDO and
|
||||
JPA exceptions). This allows one to handle most persistence exceptions,
|
||||
which are non-recoverable, only in the appropriate layers, without
|
||||
having annoying boilerplate catch-and-throw blocks and exception
|
||||
declarations in one's DAOs. (One can still trap and handle exceptions
|
||||
anywhere one needs to though.) As mentioned above, JDBC exceptions
|
||||
(including database-specific dialects) are also converted to the
|
||||
same hierarchy, meaning that one can perform some operations with
|
||||
JDBC within a consistent programming model.
|
||||
</para>
|
||||
<para>
|
||||
The above holds true for the various template classes in Springs
|
||||
support for various ORM frameworks. If one uses the interceptor-based
|
||||
classes then the application must care about handling
|
||||
<classname>HibernateExceptions</classname> and
|
||||
<classname>JDOExceptions</classname> itself, preferably via delegating
|
||||
to <classname>SessionFactoryUtils</classname>'
|
||||
<methodname>convertHibernateAccessException(..)</methodname> or
|
||||
<methodname>convertJdoAccessException</methodname> methods respectively.
|
||||
These methods convert the exceptions to ones that are compatible
|
||||
with the exceptions in the <literal>org.springframework.dao</literal>
|
||||
exception hierarchy. As <classname>JDOExceptions</classname> are
|
||||
unchecked, they can simply get thrown too, sacrificing generic DAO
|
||||
abstraction in terms of exceptions though.
|
||||
</para>
|
||||
<para>
|
||||
The exception hierarchy that Spring provides can be seen below.
|
||||
(Please note that the class hierarchy detailed in the image
|
||||
shows only a subset of the entire
|
||||
<classname>DataAccessException</classname> hierarchy.)
|
||||
</para>
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata fileref="images/DataAccessException.gif" align="center" />
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
</section>
|
||||
<section id="dao-abstract-superclasses">
|
||||
<title>Consistent abstract classes for DAO support</title>
|
||||
<para>
|
||||
To make it easier to work with a variety of data access technologies
|
||||
such as JDBC, JDO and Hibernate in a consistent way, Spring provides
|
||||
a set of <literal>abstract</literal> DAO classes that one can extend.
|
||||
These abstract classes have methods for providing the data source and
|
||||
any other configuration settings that are specific to the relevant
|
||||
data-access technology.
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<classname>JdbcDaoSupport</classname> - superclass for JDBC data
|
||||
access objects. Requires a <interfacename>DataSource</interfacename>
|
||||
to be provided; in turn, this class provides a
|
||||
<classname>JdbcTemplate</classname> instance initialized from the
|
||||
supplied <interfacename>DataSource</interfacename> to subclasses.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<classname>HibernateDaoSupport</classname> - superclass for
|
||||
Hibernate data access objects. Requires a
|
||||
<interfacename>SessionFactory</interfacename> to be provided;
|
||||
in turn, this class provides a
|
||||
<classname>HibernateTemplate</classname> instance initialized
|
||||
from the supplied <interfacename>SessionFactory</interfacename>
|
||||
to subclasses. Can alternatively be initialized directly via a
|
||||
<classname>HibernateTemplate</classname>, to reuse the latters
|
||||
settings like <interfacename>SessionFactory</interfacename>,
|
||||
flush mode, exception translator, and so forth.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<classname>JdoDaoSupport</classname> - super class for JDO data
|
||||
access objects. Requires a
|
||||
<interfacename>PersistenceManagerFactory</interfacename>
|
||||
to be provided; in turn, this class provides a
|
||||
<classname>JdoTemplate</classname> instance initialized from the
|
||||
supplied <interfacename>PersistenceManagerFactory</interfacename>
|
||||
to subclasses.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<classname>JpaDaoSupport</classname> - super class for JPA data
|
||||
access objects. Requires a
|
||||
<interfacename>EntityManagerFactory</interfacename> to be provided;
|
||||
in turn, this class provides a <classname>JpaTemplate</classname>
|
||||
instance initialized from the supplied
|
||||
<interfacename>EntityManagerFactory</interfacename> to subclasses.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
@@ -0,0 +1,681 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<appendix id="springbeansdtd">
|
||||
<title><literal>spring-beans-2.0.dtd</literal></title>
|
||||
|
||||
<para><programlisting><!--
|
||||
Spring XML Beans DTD, version 2.0
|
||||
Authors: Rod Johnson, Juergen Hoeller, Alef Arendsen, Colin Sampaleanu, Rob Harrop
|
||||
|
||||
This defines a simple and consistent way of creating a namespace
|
||||
of JavaBeans objects, managed by a Spring BeanFactory, read by
|
||||
XmlBeanDefinitionReader (with DefaultBeanDefinitionDocumentReader).
|
||||
|
||||
This document type is used by most Spring functionality, including
|
||||
web application contexts, which are based on bean factories.
|
||||
|
||||
Each "bean" element in this document defines a JavaBean.
|
||||
Typically the bean class is specified, along with JavaBean properties
|
||||
and/or constructor arguments.
|
||||
|
||||
A bean instance can be a "singleton" (shared instance) or a "prototype"
|
||||
(independent instance). Further scopes can be provided by extended
|
||||
bean factories, for example in a web environment.
|
||||
|
||||
References among beans are supported, that is, setting a JavaBean property
|
||||
or a constructor argument to refer to another bean in the same factory
|
||||
(or an ancestor factory).
|
||||
|
||||
As alternative to bean references, "inner bean definitions" can be used.
|
||||
Singleton flags of such inner bean definitions are effectively ignored:
|
||||
Inner beans are typically anonymous prototypes.
|
||||
|
||||
There is also support for lists, sets, maps, and java.util.Properties
|
||||
as bean property types or constructor argument types.
|
||||
|
||||
For simple purposes, this DTD is sufficient. As of Spring 2.0,
|
||||
XSD-based bean definitions are supported as more powerful alternative.
|
||||
|
||||
XML documents that conform to this DTD should declare the following doctype:
|
||||
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
|
||||
"http://www.springframework.org/dtd/spring-beans-2.0.dtd">
|
||||
-->
|
||||
|
||||
|
||||
<!--
|
||||
The document root. A document can contain bean definitions only,
|
||||
imports only, or a mixture of both (typically with imports first).
|
||||
-->
|
||||
<!ELEMENT beans (
|
||||
description?,
|
||||
(import | alias | bean)*
|
||||
)>
|
||||
|
||||
<!--
|
||||
Default values for all bean definitions. Can be overridden at
|
||||
the "bean" level. See those attribute definitions for details.
|
||||
-->
|
||||
<!ATTLIST beans default-lazy-init (true | false) "false">
|
||||
<!ATTLIST beans default-autowire (no | byName | byType | constructor | autodetect) "no">
|
||||
<!ATTLIST beans default-dependency-check (none | objects | simple | all) "none">
|
||||
<!ATTLIST beans default-init-method CDATA #IMPLIED>
|
||||
<!ATTLIST beans default-destroy-method CDATA #IMPLIED>
|
||||
<!ATTLIST beans default-merge (true | false) "false">
|
||||
|
||||
<!--
|
||||
Element containing informative text describing the purpose of the enclosing
|
||||
element. Always optional.
|
||||
Used primarily for user documentation of XML bean definition documents.
|
||||
-->
|
||||
<!ELEMENT description (#PCDATA)>
|
||||
|
||||
|
||||
<!--
|
||||
Specifies an XML bean definition resource to import.
|
||||
-->
|
||||
<!ELEMENT import EMPTY>
|
||||
|
||||
<!--
|
||||
The relative resource location of the XML bean definition file to import,
|
||||
for example "myImport.xml" or "includes/myImport.xml" or "../myImport.xml".
|
||||
-->
|
||||
<!ATTLIST import resource CDATA #REQUIRED>
|
||||
|
||||
|
||||
<!--
|
||||
Defines an alias for a bean, which can reside in a different definition file.
|
||||
-->
|
||||
<!ELEMENT alias EMPTY>
|
||||
|
||||
<!--
|
||||
The name of the bean to define an alias for.
|
||||
-->
|
||||
<!ATTLIST alias name CDATA #REQUIRED>
|
||||
|
||||
<!--
|
||||
The alias name to define for the bean.
|
||||
-->
|
||||
<!ATTLIST alias alias CDATA #REQUIRED>
|
||||
|
||||
<!--
|
||||
Allows for arbitrary metadata to be attached to a bean definition.
|
||||
-->
|
||||
<!ELEMENT meta EMPTY>
|
||||
|
||||
<!--
|
||||
Specifies the key name of the metadata parameter being defined.
|
||||
-->
|
||||
<!ATTLIST meta key CDATA #REQUIRED>
|
||||
|
||||
<!--
|
||||
Specifies the value of the metadata parameter being defined as a String.
|
||||
-->
|
||||
<!ATTLIST meta value CDATA #REQUIRED>
|
||||
|
||||
<!--
|
||||
Defines a single (usually named) bean.
|
||||
|
||||
A bean definition may contain nested tags for constructor arguments,
|
||||
property values, lookup methods, and replaced methods. Mixing constructor
|
||||
injection and setter injection on the same bean is explicitly supported.
|
||||
-->
|
||||
<!ELEMENT bean (
|
||||
description?,
|
||||
(meta | constructor-arg | property | lookup-method | replaced-method)*
|
||||
)>
|
||||
|
||||
<!--
|
||||
Beans can be identified by an id, to enable reference checking.
|
||||
|
||||
There are constraints on a valid XML id: if you want to reference your bean
|
||||
in Java code using a name that's illegal as an XML id, use the optional
|
||||
"name" attribute. If neither is given, the bean class name is used as id
|
||||
(with an appended counter like "#2" if there is already a bean with that name).
|
||||
-->
|
||||
<!ATTLIST bean id ID #IMPLIED>
|
||||
|
||||
<!--
|
||||
Optional. Can be used to create one or more aliases illegal in an id.
|
||||
Multiple aliases can be separated by any number of spaces, commas, or
|
||||
semi-colons (or indeed any mixture of the three).
|
||||
-->
|
||||
<!ATTLIST bean name CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Each bean definition must specify the fully qualified name of the class,
|
||||
except if it pure serves as parent for child bean definitions.
|
||||
-->
|
||||
<!ATTLIST bean class CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Optionally specify a parent bean definition.
|
||||
|
||||
Will use the bean class of the parent if none specified, but can
|
||||
also override it. In the latter case, the child bean class must be
|
||||
compatible with the parent, i.e. accept the parent's property values
|
||||
and constructor argument values, if any.
|
||||
|
||||
A child bean definition will inherit constructor argument values,
|
||||
property values and method overrides from the parent, with the option
|
||||
to add new values. If init method, destroy method, factory bean and/or factory
|
||||
method are specified, they will override the corresponding parent settings.
|
||||
|
||||
The remaining settings will always be taken from the child definition:
|
||||
depends on, autowire mode, dependency check, scope, lazy init.
|
||||
-->
|
||||
<!ATTLIST bean parent CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
The scope of this bean: typically "singleton" (one shared instance,
|
||||
which will be returned by all calls to getBean() with the id),
|
||||
or "prototype" (independent instance resulting from each call to
|
||||
getBean(). Default is "singleton".
|
||||
|
||||
Singletons are most commonly used, and are ideal for multi-threaded
|
||||
service objects. Further scopes, such as "request" or "session",
|
||||
might be supported by extended bean factories (for example, in a
|
||||
web environment).
|
||||
|
||||
Note: This attribute will not be inherited by child bean definitions.
|
||||
Hence, it needs to be specified per concrete bean definition.
|
||||
|
||||
Inner bean definitions inherit the singleton status of their containing
|
||||
bean definition, unless explicitly specified: The inner bean will be a
|
||||
singleton if the containing bean is a singleton, and a prototype if
|
||||
the containing bean has any other scope.
|
||||
-->
|
||||
<!ATTLIST bean scope CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Is this bean "abstract", i.e. not meant to be instantiated itself but
|
||||
rather just serving as parent for concrete child bean definitions.
|
||||
Default is "false". Specify "true" to tell the bean factory to not try to
|
||||
instantiate that particular bean in any case.
|
||||
|
||||
Note: This attribute will not be inherited by child bean definitions.
|
||||
Hence, it needs to be specified per abstract bean definition.
|
||||
-->
|
||||
<!ATTLIST bean abstract (true | false) #IMPLIED>
|
||||
|
||||
<!--
|
||||
If this bean should be lazily initialized.
|
||||
If false, it will get instantiated on startup by bean factories
|
||||
that perform eager initialization of singletons.
|
||||
|
||||
Note: This attribute will not be inherited by child bean definitions.
|
||||
Hence, it needs to be specified per concrete bean definition.
|
||||
-->
|
||||
<!ATTLIST bean lazy-init (true | false | default) "default">
|
||||
|
||||
<!--
|
||||
Indicates whether or not this bean should be considered when looking
|
||||
for candidates to satisfy another beans autowiring requirements.
|
||||
-->
|
||||
<!ATTLIST bean autowire-candidate (true | false) #IMPLIED>
|
||||
|
||||
<!--
|
||||
Optional attribute controlling whether to "autowire" bean properties.
|
||||
This is an automagical process in which bean references don't need to be coded
|
||||
explicitly in the XML bean definition file, but Spring works out dependencies.
|
||||
|
||||
There are 5 modes:
|
||||
|
||||
1. "no"
|
||||
The traditional Spring default. No automagical wiring. Bean references
|
||||
must be defined in the XML file via the <ref> element. We recommend this
|
||||
in most cases as it makes documentation more explicit.
|
||||
|
||||
2. "byName"
|
||||
Autowiring by property name. If a bean of class Cat exposes a dog property,
|
||||
Spring will try to set this to the value of the bean "dog" in the current factory.
|
||||
If there is no matching bean by name, nothing special happens;
|
||||
use dependency-check="objects" to raise an error in that case.
|
||||
|
||||
3. "byType"
|
||||
Autowiring if there is exactly one bean of the property type in the bean factory.
|
||||
If there is more than one, a fatal error is raised, and you can't use byType
|
||||
autowiring for that bean. If there is none, nothing special happens;
|
||||
use dependency-check="objects" to raise an error in that case.
|
||||
|
||||
4. "constructor"
|
||||
Analogous to "byType" for constructor arguments. If there isn't exactly one bean
|
||||
of the constructor argument type in the bean factory, a fatal error is raised.
|
||||
|
||||
5. "autodetect"
|
||||
Chooses "constructor" or "byType" through introspection of the bean class.
|
||||
If a default constructor is found, "byType" gets applied.
|
||||
|
||||
The latter two are similar to PicoContainer and make bean factories simple to
|
||||
configure for small namespaces, but doesn't work as well as standard Spring
|
||||
behaviour for bigger applications.
|
||||
|
||||
Note that explicit dependencies, i.e. "property" and "constructor-arg" elements,
|
||||
always override autowiring. Autowire behavior can be combined with dependency
|
||||
checking, which will be performed after all autowiring has been completed.
|
||||
|
||||
Note: This attribute will not be inherited by child bean definitions.
|
||||
Hence, it needs to be specified per concrete bean definition.
|
||||
-->
|
||||
<!ATTLIST bean autowire (no | byName | byType | constructor | autodetect | default) "default">
|
||||
|
||||
<!--
|
||||
Optional attribute controlling whether to check whether all this
|
||||
beans dependencies, expressed in its properties, are satisfied.
|
||||
Default is no dependency checking.
|
||||
|
||||
"simple" type dependency checking includes primitives and String;
|
||||
"objects" includes collaborators (other beans in the factory);
|
||||
"all" includes both types of dependency checking.
|
||||
|
||||
Note: This attribute will not be inherited by child bean definitions.
|
||||
Hence, it needs to be specified per concrete bean definition.
|
||||
-->
|
||||
<!ATTLIST bean dependency-check (none | objects | simple | all | default) "default">
|
||||
|
||||
<!--
|
||||
The names of the beans that this bean depends on being initialized.
|
||||
The bean factory will guarantee that these beans get initialized before.
|
||||
|
||||
Note that dependencies are normally expressed through bean properties or
|
||||
constructor arguments. This property should just be necessary for other kinds
|
||||
of dependencies like statics (*ugh*) or database preparation on startup.
|
||||
|
||||
Note: This attribute will not be inherited by child bean definitions.
|
||||
Hence, it needs to be specified per concrete bean definition.
|
||||
-->
|
||||
<!ATTLIST bean depends-on CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Optional attribute for the name of the custom initialization method
|
||||
to invoke after setting bean properties. The method must have no arguments,
|
||||
but may throw any exception.
|
||||
-->
|
||||
<!ATTLIST bean init-method CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Optional attribute for the name of the custom destroy method to invoke
|
||||
on bean factory shutdown. The method must have no arguments,
|
||||
but may throw any exception.
|
||||
|
||||
Note: Only invoked on beans whose lifecycle is under full control
|
||||
of the factory - which is always the case for singletons, but not
|
||||
guaranteed for any other scope.
|
||||
-->
|
||||
<!ATTLIST bean destroy-method CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Optional attribute specifying the name of a factory method to use to
|
||||
create this object. Use constructor-arg elements to specify arguments
|
||||
to the factory method, if it takes arguments. Autowiring does not apply
|
||||
to factory methods.
|
||||
|
||||
If the "class" attribute is present, the factory method will be a static
|
||||
method on the class specified by the "class" attribute on this bean
|
||||
definition. Often this will be the same class as that of the constructed
|
||||
object - for example, when the factory method is used as an alternative
|
||||
to a constructor. However, it may be on a different class. In that case,
|
||||
the created object will *not* be of the class specified in the "class"
|
||||
attribute. This is analogous to FactoryBean behavior.
|
||||
|
||||
If the "factory-bean" attribute is present, the "class" attribute is not
|
||||
used, and the factory method will be an instance method on the object
|
||||
returned from a getBean call with the specified bean name. The factory
|
||||
bean may be defined as a singleton or a prototype.
|
||||
|
||||
The factory method can have any number of arguments. Autowiring is not
|
||||
supported. Use indexed constructor-arg elements in conjunction with the
|
||||
factory-method attribute.
|
||||
|
||||
Setter Injection can be used in conjunction with a factory method.
|
||||
Method Injection cannot, as the factory method returns an instance,
|
||||
which will be used when the container creates the bean.
|
||||
-->
|
||||
<!ATTLIST bean factory-method CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Alternative to class attribute for factory-method usage.
|
||||
If this is specified, no class attribute should be used.
|
||||
This should be set to the name of a bean in the current or
|
||||
ancestor factories that contains the relevant factory method.
|
||||
This allows the factory itself to be configured using Dependency
|
||||
Injection, and an instance (rather than static) method to be used.
|
||||
-->
|
||||
<!ATTLIST bean factory-bean CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Bean definitions can specify zero or more constructor arguments.
|
||||
This is an alternative to "autowire constructor".
|
||||
Arguments correspond to either a specific index of the constructor argument
|
||||
list or are supposed to be matched generically by type.
|
||||
|
||||
Note: A single generic argument value will just be used once, rather than
|
||||
potentially matched multiple times (as of Spring 1.1).
|
||||
|
||||
constructor-arg elements are also used in conjunction with the factory-method
|
||||
element to construct beans using static or instance factory methods.
|
||||
-->
|
||||
<!ELEMENT constructor-arg (
|
||||
description?,
|
||||
(bean | ref | idref | value | null | list | set | map | props)?
|
||||
)>
|
||||
|
||||
<!--
|
||||
The constructor-arg tag can have an optional index attribute,
|
||||
to specify the exact index in the constructor argument list. Only needed
|
||||
to avoid ambiguities, e.g. in case of 2 arguments of the same type.
|
||||
-->
|
||||
<!ATTLIST constructor-arg index CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
The constructor-arg tag can have an optional type attribute,
|
||||
to specify the exact type of the constructor argument. Only needed
|
||||
to avoid ambiguities, e.g. in case of 2 single argument constructors
|
||||
that can both be converted from a String.
|
||||
-->
|
||||
<!ATTLIST constructor-arg type CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
A short-cut alternative to a child element "ref bean=".
|
||||
-->
|
||||
<!ATTLIST constructor-arg ref CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
A short-cut alternative to a child element "value".
|
||||
-->
|
||||
<!ATTLIST constructor-arg value CDATA #IMPLIED>
|
||||
|
||||
|
||||
<!--
|
||||
Bean definitions can have zero or more properties.
|
||||
Property elements correspond to JavaBean setter methods exposed
|
||||
by the bean classes. Spring supports primitives, references to other
|
||||
beans in the same or related factories, lists, maps and properties.
|
||||
-->
|
||||
<!ELEMENT property (
|
||||
description?, meta*,
|
||||
(bean | ref | idref | value | null | list | set | map | props)?
|
||||
)>
|
||||
|
||||
<!--
|
||||
The property name attribute is the name of the JavaBean property.
|
||||
This follows JavaBean conventions: a name of "age" would correspond
|
||||
to setAge()/optional getAge() methods.
|
||||
-->
|
||||
<!ATTLIST property name CDATA #REQUIRED>
|
||||
|
||||
<!--
|
||||
A short-cut alternative to a child element "ref bean=".
|
||||
-->
|
||||
<!ATTLIST property ref CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
A short-cut alternative to a child element "value".
|
||||
-->
|
||||
<!ATTLIST property value CDATA #IMPLIED>
|
||||
|
||||
|
||||
<!--
|
||||
A lookup method causes the IoC container to override the given method and return
|
||||
the bean with the name given in the bean attribute. This is a form of Method Injection.
|
||||
It's particularly useful as an alternative to implementing the BeanFactoryAware
|
||||
interface, in order to be able to make getBean() calls for non-singleton instances
|
||||
at runtime. In this case, Method Injection is a less invasive alternative.
|
||||
-->
|
||||
<!ELEMENT lookup-method EMPTY>
|
||||
|
||||
<!--
|
||||
Name of a lookup method. This method should take no arguments.
|
||||
-->
|
||||
<!ATTLIST lookup-method name CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Name of the bean in the current or ancestor factories that the lookup method
|
||||
should resolve to. Often this bean will be a prototype, in which case the
|
||||
lookup method will return a distinct instance on every invocation. This
|
||||
is useful for single-threaded objects.
|
||||
-->
|
||||
<!ATTLIST lookup-method bean CDATA #IMPLIED>
|
||||
|
||||
|
||||
<!--
|
||||
Similar to the lookup method mechanism, the replaced-method element is used to control
|
||||
IoC container method overriding: Method Injection. This mechanism allows the overriding
|
||||
of a method with arbitrary code.
|
||||
-->
|
||||
<!ELEMENT replaced-method (
|
||||
(arg-type)*
|
||||
)>
|
||||
|
||||
<!--
|
||||
Name of the method whose implementation should be replaced by the IoC container.
|
||||
If this method is not overloaded, there's no need to use arg-type subelements.
|
||||
If this method is overloaded, arg-type subelements must be used for all
|
||||
override definitions for the method.
|
||||
-->
|
||||
<!ATTLIST replaced-method name CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Bean name of an implementation of the MethodReplacer interface in the current
|
||||
or ancestor factories. This may be a singleton or prototype bean. If it's
|
||||
a prototype, a new instance will be used for each method replacement.
|
||||
Singleton usage is the norm.
|
||||
-->
|
||||
<!ATTLIST replaced-method replacer CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Subelement of replaced-method identifying an argument for a replaced method
|
||||
in the event of method overloading.
|
||||
-->
|
||||
<!ELEMENT arg-type (#PCDATA)>
|
||||
|
||||
<!--
|
||||
Specification of the type of an overloaded method argument as a String.
|
||||
For convenience, this may be a substring of the FQN. E.g. all the
|
||||
following would match "java.lang.String":
|
||||
- java.lang.String
|
||||
- String
|
||||
- Str
|
||||
|
||||
As the number of arguments will be checked also, this convenience can often
|
||||
be used to save typing.
|
||||
-->
|
||||
<!ATTLIST arg-type match CDATA #IMPLIED>
|
||||
|
||||
|
||||
<!--
|
||||
Defines a reference to another bean in this factory or an external
|
||||
factory (parent or included factory).
|
||||
-->
|
||||
<!ELEMENT ref EMPTY>
|
||||
|
||||
<!--
|
||||
References must specify a name of the target bean.
|
||||
The "bean" attribute can reference any name from any bean in the context,
|
||||
to be checked at runtime.
|
||||
Local references, using the "local" attribute, have to use bean ids;
|
||||
they can be checked by this DTD, thus should be preferred for references
|
||||
within the same bean factory XML file.
|
||||
-->
|
||||
<!ATTLIST ref bean CDATA #IMPLIED>
|
||||
<!ATTLIST ref local IDREF #IMPLIED>
|
||||
<!ATTLIST ref parent CDATA #IMPLIED>
|
||||
|
||||
|
||||
<!--
|
||||
Defines a string property value, which must also be the id of another
|
||||
bean in this factory or an external factory (parent or included factory).
|
||||
While a regular 'value' element could instead be used for the same effect,
|
||||
using idref in this case allows validation of local bean ids by the XML
|
||||
parser, and name completion by supporting tools.
|
||||
-->
|
||||
<!ELEMENT idref EMPTY>
|
||||
|
||||
<!--
|
||||
ID refs must specify a name of the target bean.
|
||||
The "bean" attribute can reference any name from any bean in the context,
|
||||
potentially to be checked at runtime by bean factory implementations.
|
||||
Local references, using the "local" attribute, have to use bean ids;
|
||||
they can be checked by this DTD, thus should be preferred for references
|
||||
within the same bean factory XML file.
|
||||
-->
|
||||
<!ATTLIST idref bean CDATA #IMPLIED>
|
||||
<!ATTLIST idref local IDREF #IMPLIED>
|
||||
|
||||
|
||||
<!--
|
||||
Contains a string representation of a property value.
|
||||
The property may be a string, or may be converted to the required
|
||||
type using the JavaBeans PropertyEditor machinery. This makes it
|
||||
possible for application developers to write custom PropertyEditor
|
||||
implementations that can convert strings to arbitrary target objects.
|
||||
|
||||
Note that this is recommended for simple objects only.
|
||||
Configure more complex objects by populating JavaBean
|
||||
properties with references to other beans.
|
||||
-->
|
||||
<!ELEMENT value (#PCDATA)>
|
||||
|
||||
<!--
|
||||
The value tag can have an optional type attribute, to specify the
|
||||
exact type that the value should be converted to. Only needed
|
||||
if the type of the target property or constructor argument is
|
||||
too generic: for example, in case of a collection element.
|
||||
-->
|
||||
<!ATTLIST value type CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Denotes a Java null value. Necessary because an empty "value" tag
|
||||
will resolve to an empty String, which will not be resolved to a
|
||||
null value unless a special PropertyEditor does so.
|
||||
-->
|
||||
<!ELEMENT null (#PCDATA)>
|
||||
|
||||
|
||||
<!--
|
||||
A list can contain multiple inner bean, ref, collection, or value elements.
|
||||
Java lists are untyped, pending generics support in Java 1.5,
|
||||
although references will be strongly typed.
|
||||
A list can also map to an array type. The necessary conversion
|
||||
is automatically performed by the BeanFactory.
|
||||
-->
|
||||
<!ELEMENT list (
|
||||
(bean | ref | idref | value | null | list | set | map | props)*
|
||||
)>
|
||||
|
||||
<!--
|
||||
Enable/disable merging for collections when using parent/child beans.
|
||||
-->
|
||||
<!ATTLIST list merge (true | false | default) "default">
|
||||
|
||||
<!--
|
||||
Specify the default Java type for nested values.
|
||||
-->
|
||||
<!ATTLIST list value-type CDATA #IMPLIED>
|
||||
|
||||
|
||||
<!--
|
||||
A set can contain multiple inner bean, ref, collection, or value elements.
|
||||
Java sets are untyped, pending generics support in Java 1.5,
|
||||
although references will be strongly typed.
|
||||
-->
|
||||
<!ELEMENT set (
|
||||
(bean | ref | idref | value | null | list | set | map | props)*
|
||||
)>
|
||||
|
||||
<!--
|
||||
Enable/disable merging for collections when using parent/child beans.
|
||||
-->
|
||||
<!ATTLIST set merge (true | false | default) "default">
|
||||
|
||||
<!--
|
||||
Specify the default Java type for nested values.
|
||||
-->
|
||||
<!ATTLIST set value-type CDATA #IMPLIED>
|
||||
|
||||
|
||||
<!--
|
||||
A Spring map is a mapping from a string key to object.
|
||||
Maps may be empty.
|
||||
-->
|
||||
<!ELEMENT map (
|
||||
(entry)*
|
||||
)>
|
||||
|
||||
<!--
|
||||
Enable/disable merging for collections when using parent/child beans.
|
||||
-->
|
||||
<!ATTLIST map merge (true | false | default) "default">
|
||||
|
||||
<!--
|
||||
Specify the default Java type for nested entry keys.
|
||||
-->
|
||||
<!ATTLIST map key-type CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Specify the default Java type for nested entry values.
|
||||
-->
|
||||
<!ATTLIST map value-type CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
A map entry can be an inner bean, ref, value, or collection.
|
||||
The key of the entry is given by the "key" attribute or child element.
|
||||
-->
|
||||
<!ELEMENT entry (
|
||||
key?,
|
||||
(bean | ref | idref | value | null | list | set | map | props)?
|
||||
)>
|
||||
|
||||
<!--
|
||||
Each map element must specify its key as attribute or as child element.
|
||||
A key attribute is always a String value.
|
||||
-->
|
||||
<!ATTLIST entry key CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
A short-cut alternative to a "key" element with a "ref bean=" child element.
|
||||
-->
|
||||
<!ATTLIST entry key-ref CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
A short-cut alternative to a child element "value".
|
||||
-->
|
||||
<!ATTLIST entry value CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
A short-cut alternative to a child element "ref bean=".
|
||||
-->
|
||||
<!ATTLIST entry value-ref CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
A key element can contain an inner bean, ref, value, or collection.
|
||||
-->
|
||||
<!ELEMENT key (
|
||||
(bean | ref | idref | value | null | list | set | map | props)
|
||||
)>
|
||||
|
||||
|
||||
<!--
|
||||
Props elements differ from map elements in that values must be strings.
|
||||
Props may be empty.
|
||||
-->
|
||||
<!ELEMENT props (
|
||||
(prop)*
|
||||
)>
|
||||
|
||||
<!--
|
||||
Enable/disable merging for collections when using parent/child beans.
|
||||
-->
|
||||
<!ATTLIST props merge (true | false | default) "default">
|
||||
|
||||
<!--
|
||||
Element content is the string value of the property.
|
||||
Note that whitespace is trimmed off to avoid unwanted whitespace
|
||||
caused by typical XML formatting.
|
||||
-->
|
||||
<!ELEMENT prop (#PCDATA)>
|
||||
|
||||
<!--
|
||||
Each property element must specify its key.
|
||||
-->
|
||||
<!ATTLIST prop key CDATA #REQUIRED></programlisting></para>
|
||||
</appendix>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,432 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<chapter id="ejb">
|
||||
<title>Enterprise Java Beans (EJB) integration</title>
|
||||
|
||||
<section id="ejb-introduction">
|
||||
<title>Introduction</title>
|
||||
<para>
|
||||
As a lightweight container, Spring is often considered an EJB
|
||||
replacement. We do believe that for many if not most applications and use
|
||||
cases, Spring as a container, combined with its rich supporting
|
||||
functionality in the area of transactions, ORM and JDBC access, is a better
|
||||
choice than implementing equivalent functionality via an EJB container and
|
||||
EJBs.
|
||||
</para>
|
||||
<para>
|
||||
However, it is important to note that using Spring does not prevent
|
||||
you from using EJBs. In fact, Spring makes it much easier to access EJBs and
|
||||
implement EJBs and functionality within them. Additionally, using Spring to
|
||||
access services provided by EJBs allows the implementation of those services
|
||||
to later transparently be switched between local EJB, remote EJB, or POJO
|
||||
(plain old Java object) variants, without the client code having to
|
||||
be changed.
|
||||
</para>
|
||||
<para>
|
||||
In this chapter, we look at how Spring can help you access and
|
||||
implement EJBs. Spring provides particular value when accessing stateless
|
||||
session beans (SLSBs), so we'll begin by discussing this.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="ejb-access">
|
||||
<title>Accessing EJBs</title>
|
||||
|
||||
<section id="ejb-access-concepts">
|
||||
<title>Concepts</title>
|
||||
<para>
|
||||
To invoke a method on a local or remote stateless session bean,
|
||||
client code must normally perform a JNDI lookup to obtain the (local or
|
||||
remote) EJB Home object, then use a 'create' method call on that object
|
||||
to obtain the actual (local or remote) EJB object. One or more methods
|
||||
are then invoked on the EJB.
|
||||
</para>
|
||||
<para>
|
||||
To avoid repeated low-level code, many EJB applications use the
|
||||
Service Locator and Business Delegate patterns. These are better than
|
||||
spraying JNDI lookups throughout client code, but their usual
|
||||
implementations have significant disadvantages. For example:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Typically code using EJBs depends on Service Locator or
|
||||
Business Delegate singletons, making it hard to test.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
In the case of the Service Locator pattern used without a
|
||||
Business Delegate, application code still ends up having to invoke
|
||||
the create() method on an EJB home, and deal with the resulting
|
||||
exceptions. Thus it remains tied to the EJB API and the complexity
|
||||
of the EJB programming model.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Implementing the Business Delegate pattern typically results
|
||||
in significant code duplication, where we have to write numerous
|
||||
methods that simply call the same method on the EJB.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
The Spring approach is to allow the creation and use of proxy objects,
|
||||
normally configured inside a Spring container, which act as codeless
|
||||
business delegates. You do not need to write another Service Locator, another
|
||||
JNDI lookup, or duplicate methods in a hand-coded Business Delegate unless
|
||||
you are actually adding real value in such code.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="ejb-access-local">
|
||||
<title>Accessing local SLSBs</title>
|
||||
<para>
|
||||
Assume that we have a web controller that needs to use a local
|
||||
EJB. We’ll follow best practice and use the EJB Business Methods
|
||||
Interface pattern, so that the EJB’s local interface extends a non
|
||||
EJB-specific business methods interface. Let’s call this business
|
||||
methods interface <classname>MyComponent</classname>.
|
||||
</para>
|
||||
<programlisting><![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><![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><![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><![CDATA[<jee:local-slsb id="myComponent" jndi-name="ejb/myBean"
|
||||
business-interface="com.mycom.MyComponent"/>
|
||||
|
||||
<bean id="myController" class="com.mycom.myController">
|
||||
<property name="myComponent" ref="myComponent"/>
|
||||
</bean>]]></programlisting>
|
||||
<para>
|
||||
This EJB access mechanism delivers huge simplification of
|
||||
application code: the web tier code (or other EJB client code) has no
|
||||
dependence on the use of EJB. If we want to replace this EJB reference
|
||||
with a POJO or a mock object or other test stub, we could simply change
|
||||
the <literal>myComponent</literal> bean definition without changing a
|
||||
line of Java code. Additionally, we haven’t had to write a single line of
|
||||
JNDI lookup or other EJB plumbing code as part of our application.
|
||||
</para>
|
||||
<para>
|
||||
Benchmarks and experience in real applications indicate that the
|
||||
performance overhead of this approach (which involves reflective
|
||||
invocation of the target EJB) is minimal, and is typically undetectable
|
||||
in typical use. Remember that we don’t want to make fine-grained calls
|
||||
to EJBs anyway, as there’s a cost associated with the EJB infrastructure
|
||||
in the application server.
|
||||
</para>
|
||||
<para>
|
||||
There is one caveat with regards to the JNDI lookup. In a bean
|
||||
container, this class is normally best used as a singleton (there simply
|
||||
is no reason to make it a prototype). However, if that bean container
|
||||
pre-instantiates singletons (as do the various XML
|
||||
<classname>ApplicationContext</classname> variants)
|
||||
you may have a problem if the bean container is loaded before the EJB
|
||||
container loads the target EJB. That is because the JNDI lookup will be
|
||||
performed in the <literal>init()</literal> method of this class and then
|
||||
cached, but the EJB will not have been bound at the target location yet.
|
||||
The solution is to not pre-instantiate this factory object, but allow it
|
||||
to be created on first use. In the XML containers, this is controlled via
|
||||
the <literal>lazy-init</literal> attribute.
|
||||
</para>
|
||||
<para>
|
||||
Although this will not be of interest to the majority of Spring
|
||||
users, those doing programmatic AOP work with EJBs may want to look at
|
||||
<classname>LocalSlsbInvokerInterceptor</classname>.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="ejb-access-remote">
|
||||
<title>Accessing remote SLSBs</title>
|
||||
<para>
|
||||
Accessing remote EJBs is essentially identical to accessing local
|
||||
EJBs, except that the
|
||||
<classname>SimpleRemoteStatelessSessionProxyFactoryBean</classname> or
|
||||
<literal><jee:remote-slsb></literal> configuration element is used.
|
||||
Of course, with or without Spring, remote invocation semantics apply; a
|
||||
call to a method on an object in another VM in another computer does
|
||||
sometimes have to be treated differently in terms of usage scenarios and
|
||||
failure handling.
|
||||
</para>
|
||||
<para>
|
||||
Spring's EJB client support adds one more advantage over the
|
||||
non-Spring approach. Normally it is problematic for EJB client code to
|
||||
be easily switched back and forth between calling EJBs locally or
|
||||
remotely. This is because the remote interface methods must declare that
|
||||
they throw <classname>RemoteException</classname>, and client code must deal
|
||||
with this, while the local interface methods don't. Client code
|
||||
written for local EJBs which needs to be moved to remote EJBs
|
||||
typically has to be modified to add handling for the remote exceptions,
|
||||
and client code written for remote EJBs which needs to be moved to local
|
||||
EJBs, can either stay the same but do a lot of unnecessary handling of
|
||||
remote exceptions, or needs to be modified to remove that code. With the
|
||||
Spring remote EJB proxy, you can instead not declare any thrown
|
||||
<classname>RemoteException</classname> in your Business Method Interface and
|
||||
implementing EJB code, have a remote interface which is identical except
|
||||
that it does throw <classname>RemoteException</classname>, and rely on the
|
||||
proxy to dynamically treat the two interfaces as if they were the same.
|
||||
That is, client code does not have to deal with the checked
|
||||
<classname>RemoteException</classname> class. Any actual
|
||||
<classname>RemoteException</classname> that is thrown during the EJB
|
||||
invocation will be re-thrown as the non-checked
|
||||
<classname>RemoteAccessException</classname> class, which is a subclass of
|
||||
<classname>RuntimeException</classname>. The target service can then be
|
||||
switched at will between a local EJB or remote EJB (or even plain Java
|
||||
object) implementation, without the client code knowing or caring. Of
|
||||
course, this is optional; there is nothing stopping you from declaring
|
||||
<classname>RemoteExceptions</classname> in your business interface.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="ejb-access-ejb2-ejb3">
|
||||
<title>Accessing EJB 2.x SLSBs versus EJB 3 SLSBs</title>
|
||||
<para>
|
||||
Accessing EJB 2.x Session Beans and EJB 3 Session Beans via Spring
|
||||
is largely transparent. Spring's EJB accessors, including the
|
||||
<literal><jee:local-slsb></literal> and <literal><jee:remote-slsb></literal>
|
||||
facilities, transparently adapt to the actual component at runtime.
|
||||
They handle a home interface if found (EJB 2.x style), or perform straight
|
||||
component invocations if no home interface is available (EJB 3 style).
|
||||
</para>
|
||||
<para>
|
||||
Note: For EJB 3 Session Beans, you could effectively use a
|
||||
<classname>JndiObjectFactoryBean</classname> / <literal><jee:jndi-lookup></literal>
|
||||
as well, since fully usable component references are exposed for plain
|
||||
JNDI lookups there. Defining explicit <literal><jee:local-slsb></literal>
|
||||
/ <literal><jee:remote-slsb></literal> lookups simply provides
|
||||
consistent and more explicit EJB access configuration.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="ejb-implementation">
|
||||
<title>Using Spring's EJB implementation support classes</title>
|
||||
|
||||
<section id="ejb-implementation-ejb2">
|
||||
<title>EJB 2.x base classes</title>
|
||||
<para>
|
||||
Spring provides convenience classes to help you implement EJBs.
|
||||
These are designed to encourage the good practice of putting business
|
||||
logic behind EJBs in POJOs, leaving EJBs responsible for transaction
|
||||
demarcation and (optionally) remoting.
|
||||
</para>
|
||||
<para>
|
||||
To implement a Stateless or Stateful session bean, or a Message Driven
|
||||
bean, you need only derive your implementation class from
|
||||
<classname>AbstractStatelessSessionBean</classname>,
|
||||
<classname>AbstractStatefulSessionBean</classname>, and
|
||||
<classname>AbstractMessageDrivenBean</classname>/<classname>AbstractJmsMessageDrivenBean</classname>,
|
||||
respectively.
|
||||
</para>
|
||||
<para>
|
||||
Consider an example Stateless Session bean which actually delegates
|
||||
the implementation to a plain java service object. We have the business interface:
|
||||
</para>
|
||||
<programlisting><![CDATA[public interface MyComponent {
|
||||
public void myMethod(...);
|
||||
...
|
||||
}]]></programlisting>
|
||||
<para>We also have the plain Java implementation object:</para>
|
||||
<programlisting><![CDATA[public class MyComponentImpl implements MyComponent {
|
||||
public String myMethod(...) {
|
||||
...
|
||||
}
|
||||
...
|
||||
}]]></programlisting>
|
||||
<para>And finally the Stateless Session Bean itself:</para>
|
||||
<programlisting><![CDATA[public class MyFacadeEJB extends AbstractStatelessSessionBean
|
||||
implements MyFacadeLocal {
|
||||
|
||||
private MyComponent myComp;
|
||||
|
||||
/**
|
||||
* Obtain our POJO service object from the BeanFactory/ApplicationContext
|
||||
* @see org.springframework.ejb.support.AbstractStatelessSessionBean#onEjbCreate()
|
||||
*/
|
||||
protected void onEjbCreate() throws CreateException {
|
||||
myComp = (MyComponent) getBeanFactory().getBean(
|
||||
ServicesConstants.CONTEXT_MYCOMP_ID);
|
||||
}
|
||||
|
||||
// for business method, delegate to POJO service impl.
|
||||
public String myFacadeMethod(...) {
|
||||
return myComp.myMethod(...);
|
||||
}
|
||||
...
|
||||
}]]></programlisting>
|
||||
<para>
|
||||
The Spring EJB support base classes will by default create and load
|
||||
a Spring IoC container as part of their lifecycle, which is then available
|
||||
to the EJB (for example, as used in the code above to obtain the POJO
|
||||
service object). The loading is done via a strategy object which is a subclass of
|
||||
<classname>BeanFactoryLocator</classname>. The actual implementation of
|
||||
<classname>BeanFactoryLocator</classname> used by default is
|
||||
<classname>ContextJndiBeanFactoryLocator</classname>, which creates the
|
||||
ApplicationContext from a resource locations specified as a JNDI
|
||||
environment variable (in the case of the EJB classes, at
|
||||
<literal>java:comp/env/ejb/BeanFactoryPath</literal>). If there is a need
|
||||
to change the BeanFactory/ApplicationContext loading strategy, the default
|
||||
<classname>BeanFactoryLocator</classname> implementation used may be overridden
|
||||
by calling the <literal>setBeanFactoryLocator()</literal> method, either
|
||||
in <literal>setSessionContext()</literal>, or in the actual constructor of
|
||||
the EJB. Please see the Javadocs for more details.
|
||||
</para>
|
||||
<para>
|
||||
As described in the Javadocs, Stateful Session beans expecting to be
|
||||
passivated and reactivated as part of their lifecycle, and which use a
|
||||
non-serializable container instance (which is the normal case) will have
|
||||
to manually call <literal>unloadBeanFactory()</literal> and
|
||||
<literal>loadBeanFactory</literal> from <literal>ejbPassivate</literal>
|
||||
and <literal>ejbActivate</literal>, respectively, to unload and reload the
|
||||
BeanFactory on passivation and activation, since it can not be saved by
|
||||
the EJB container.
|
||||
</para>
|
||||
<para>
|
||||
The default behavior of the <classname>ContextJndiBeanFactoryLocator</classname>
|
||||
classes which is to load an <classname>ApplicationContext</classname> for the
|
||||
use of the EJB is adequate for some situations. However, it is problematic when
|
||||
the <classname>ApplicationContext</classname> is loading a number
|
||||
of beans, or the initialization of those beans is time consuming or memory
|
||||
intensive (such as a Hibernate <classname>SessionFactory</classname> initialization, for
|
||||
example), since every EJB will have their own copy. In this case, the user
|
||||
may want to override the default <classname>ContextJndiBeanFactoryLocator</classname>
|
||||
usage and use another <classname>BeanFactoryLocator</classname> variant, such as the
|
||||
<classname>ContextSingletonBeanFactoryLocator</classname> which can load and use a
|
||||
shared container to be used by multiple EJBs or other clients. Doing this is relatively
|
||||
simple, by adding code similar to this to the EJB:
|
||||
</para>
|
||||
<programlisting><![CDATA[ /**
|
||||
* Override default BeanFactoryLocator implementation
|
||||
* @see javax.ejb.SessionBean#setSessionContext(javax.ejb.SessionContext)
|
||||
*/
|
||||
public void setSessionContext(SessionContext sessionContext) {
|
||||
super.setSessionContext(sessionContext);
|
||||
setBeanFactoryLocator(ContextSingletonBeanFactoryLocator.getInstance());
|
||||
setBeanFactoryLocatorKey(ServicesConstants.PRIMARY_CONTEXT_ID);
|
||||
}]]></programlisting>
|
||||
<para>
|
||||
You would then need to create a bean definition file named <literal>beanRefContext.xml</literal>.
|
||||
This file defines all bean factories (usually in the form of application contexts) that may be used
|
||||
in the EJB. In many cases, this file will only contain a single bean definition such as this (where
|
||||
<literal>businessApplicationContext.xml</literal> contains the bean definitions for all business
|
||||
service POJOs):
|
||||
</para>
|
||||
<programlisting><![CDATA[<beans>
|
||||
<bean id="businessBeanFactory" class="org.springframework.context.support.ClassPathXmlApplicationContext">
|
||||
<constructor-arg value="businessApplicationContext.xml" />
|
||||
</bean>
|
||||
</beans>]]></programlisting>
|
||||
<para>
|
||||
In the above example, the <literal>ServicesConstants.PRIMARY_CONTEXT_ID</literal> constant
|
||||
would be defined as follows:
|
||||
</para>
|
||||
<programlisting><![CDATA[public static final String ServicesConstants.PRIMARY_CONTEXT_ID = "businessBeanFactory";]]></programlisting>
|
||||
<para>
|
||||
Please see the respective Javadocs for the <classname>BeanFactoryLocator</classname> and
|
||||
<classname>ContextSingletonBeanFactoryLocator</classname> classes for more information on
|
||||
their usage.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="ejb-implementation-ejb3">
|
||||
<title>EJB 3 injection interceptor</title>
|
||||
<para>
|
||||
For EJB 3 Session Beans and Message-Driven Beans, Spring provides a convenient
|
||||
interceptor that resolves Spring 2.5's <literal>@Autowired</literal> annotation
|
||||
in the EJB component class:
|
||||
<classname>org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor</classname>.
|
||||
This interceptor can be applied through an <code>@Interceptors</code> annotation
|
||||
in the EJB component class, or through an <literal>interceptor-binding</literal>
|
||||
XML element in the EJB deployment descriptor.
|
||||
</para>
|
||||
<programlisting><![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
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,403 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter id="mail">
|
||||
<title>Email</title>
|
||||
|
||||
<section id="mail-introduction">
|
||||
<title>Introduction</title>
|
||||
<sidebar>
|
||||
<title>Library dependencies</title>
|
||||
<para>The following additional jars to be on the classpath of your
|
||||
application in order to be able to use the Spring Framework's email library.</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>The <ulink url="http://java.sun.com/products/javamail/">JavaMail</ulink> <filename class="libraryfile">mail.jar</filename> library</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>The <ulink url="http://java.sun.com/products/javabeans/jaf/downloads/index.html">JAF</ulink> <filename class="libraryfile">activation.jar</filename> library</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>All of these libraries are available in the Spring-with-dependencies
|
||||
distribution of the Spring Framework (in addition to also being freely
|
||||
available on the web).</para>
|
||||
</sidebar>
|
||||
|
||||
<para>The Spring Framework provides a helpful utility library for sending
|
||||
email that shields the user from the specifics of the underlying mailing
|
||||
system and is responsible for low level resource handling on behalf of
|
||||
the client.</para>
|
||||
|
||||
<para>The <literal>org.springframework.mail</literal> package is the root level package
|
||||
for the Spring Framework's email support. The central interface for sending
|
||||
emails is the <interfacename>MailSender</interfacename> interface; a simple value object
|
||||
encapsulating the properties of a simple mail such as <emphasis>from</emphasis> and
|
||||
<emphasis>to</emphasis> (plus many others) is the <classname>SimpleMailMessage</classname> class.
|
||||
This package also contains a hierarchy of checked exceptions which provide
|
||||
a higher level of abstraction over the lower level mail system exceptions
|
||||
with the root exception being <exceptionname>MailException</exceptionname>. Please
|
||||
refer to the Javadocs for more information on the rich mail exception hierarchy.</para>
|
||||
|
||||
<para>The <interfacename>org.springframework.mail.javamail.JavaMailSender</interfacename>
|
||||
interface adds specialized <emphasis>JavaMail</emphasis> features such as MIME
|
||||
message support to the <interfacename>MailSender</interfacename> interface
|
||||
(from which it inherits). <interfacename>JavaMailSender</interfacename> also provides a
|
||||
callback interface for preparation of JavaMail MIME messages, called
|
||||
<interfacename>org.springframework.mail.javamail.MimeMessagePreparator</interfacename></para>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="mail-usage">
|
||||
<title>Usage</title>
|
||||
<para>Let's assume there is a business interface called <interfacename>OrderManager</interfacename>:</para>
|
||||
<programlisting><![CDATA[public interface OrderManager {
|
||||
|
||||
void placeOrder(Order order);
|
||||
}]]></programlisting>
|
||||
|
||||
<para>Let us also assume that there is a requirement stating that an email message
|
||||
with an order number needs to be generated and sent to a customer placing the
|
||||
relevant order.</para>
|
||||
|
||||
<section id="mail-usage-simple">
|
||||
<title>Basic <interfacename>MailSender</interfacename> and <classname>SimpleMailMessage</classname> usage</title>
|
||||
<programlisting><![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><![CDATA[<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
|
||||
<property name="host" value="mail.mycompany.com"/>
|
||||
</bean>
|
||||
|
||||
]]><lineannotation><!-- this is a template message that we can pre-load with default state --></lineannotation><![CDATA[
|
||||
<bean id="templateMessage" class="org.springframework.mail.SimpleMailMessage">
|
||||
<property name="from" value="customerservice@mycompany.com"/>
|
||||
<property name="subject" value="Your order"/>
|
||||
</bean>
|
||||
|
||||
<bean id="orderManager" class="com.mycompany.businessapp.support.SimpleOrderManager">
|
||||
<property name="mailSender" ref="mailSender"/>
|
||||
<property name="templateMessage" ref="templateMessage"/>
|
||||
</bean>]]></programlisting>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="mail-usage-mime">
|
||||
<title>Using the <interfacename>JavaMailSender</interfacename> and the <classname>MimeMessagePreparator</classname></title>
|
||||
<para>Here is another implementation of <interfacename>OrderManager</interfacename> using
|
||||
the <interfacename>MimeMessagePreparator</interfacename> callback interface. Please note
|
||||
in this case that the <literal>mailSender</literal> property is of type
|
||||
<interfacename>JavaMailSender</interfacename> so that we are able to use the JavaMail
|
||||
<classname>MimeMessage</classname> class:</para>
|
||||
|
||||
<programlisting><![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 two
|
||||
<interfacename>MailSender</interfacename> implementations. The standard JavaMail
|
||||
implementation and the implementation on top of Jason Hunter's
|
||||
<classname>MailMessage</classname> class that is included in
|
||||
<ulink url="http://servlets.com/cos">the <literal>com.oreilly.servlet</literal>
|
||||
package</ulink>. Please refer to the relevant Javadocs for more information.</para>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="mail-javamail-mime">
|
||||
<title>Using the JavaMail <classname>MimeMessageHelper</classname></title>
|
||||
|
||||
<para>A class that comes in pretty handy when dealing with JavaMail messages is
|
||||
the <classname>org.springframework.mail.javamail.MimeMessageHelper</classname> class,
|
||||
which shields you from having to use the verbose JavaMail API. Using
|
||||
the <classname>MimeMessageHelper</classname> it is pretty easy to
|
||||
create a <classname>MimeMessage</classname>:</para>
|
||||
<programlisting><lineannotation>// of course you would use DI in any real-world cases</lineannotation><![CDATA[
|
||||
JavaMailSenderImpl sender = new JavaMailSenderImpl();
|
||||
sender.setHost("mail.host.com");
|
||||
|
||||
MimeMessage message = sender.createMimeMessage();
|
||||
MimeMessageHelper helper = new MimeMessageHelper(message);
|
||||
helper.setTo("test@host.com");
|
||||
helper.setText("Thank you for ordering!");
|
||||
|
||||
sender.send(message);]]></programlisting>
|
||||
|
||||
<section id="mail-javamail-mime-attachments">
|
||||
<title>Sending attachments and inline resources</title>
|
||||
<para>Multipart email messages allow for both attachments and inline resources.
|
||||
Examples of inline resources would be be images or a stylesheet you want to use
|
||||
in your message, but that you don't want displayed as an attachment.</para>
|
||||
<section id="mail-javamail-mime-attachments-attachment">
|
||||
<title>Attachments</title>
|
||||
<para>The following example shows you how to use the
|
||||
<classname>MimeMessageHelper</classname> to send an email along with a
|
||||
single JPEG image attachment.</para>
|
||||
<programlisting><![CDATA[JavaMailSenderImpl sender = new JavaMailSenderImpl();
|
||||
sender.setHost("mail.host.com");
|
||||
|
||||
MimeMessage message = sender.createMimeMessage();
|
||||
|
||||
]]><lineannotation>// use the true flag to indicate you need a multipart message</lineannotation><![CDATA[
|
||||
MimeMessageHelper helper = new MimeMessageHelper(message, true);
|
||||
helper.setTo("test@host.com");
|
||||
|
||||
helper.setText("Check out this image!");
|
||||
|
||||
]]><lineannotation>// let's attach the infamous windows Sample file (this time copied to c:/)</lineannotation><![CDATA[
|
||||
FileSystemResource file = new FileSystemResource(new File("c:/Sample.jpg"));
|
||||
helper.addAttachment("CoolImage.jpg", file);
|
||||
|
||||
sender.send(message);]]></programlisting>
|
||||
</section>
|
||||
<section id="mail-javamail-mime-attachments-inline">
|
||||
<title>Inline resources</title>
|
||||
<para>The following example shows you how to use the
|
||||
<classname>MimeMessageHelper</classname> to send an email along with an
|
||||
inline image.</para>
|
||||
<programlisting><![CDATA[JavaMailSenderImpl sender = new JavaMailSenderImpl();
|
||||
sender.setHost("mail.host.com");
|
||||
|
||||
MimeMessage message = sender.createMimeMessage();
|
||||
|
||||
]]><lineannotation>// use the true flag to indicate you need a multipart message</lineannotation><![CDATA[
|
||||
MimeMessageHelper helper = new MimeMessageHelper(message, true);
|
||||
helper.setTo("test@host.com");
|
||||
|
||||
]]><lineannotation>// use the true flag to indicate the text included is HTML</lineannotation><![CDATA[
|
||||
helper.setText("<html><body><img src='cid:identifier1234'></body></html>", true);
|
||||
|
||||
]]><lineannotation>// let's include the infamous windows Sample file (this time copied to c:/)</lineannotation><![CDATA[
|
||||
FileSystemResource res = new FileSystemResource(new File("c:/Sample.jpg"));
|
||||
helper.addInline("identifier1234", res);
|
||||
|
||||
sender.send(message);]]></programlisting>
|
||||
<warning>
|
||||
<para>Inline resources are added to the mime message using the
|
||||
specified <literal>Content-ID</literal> (<literal>identifier1234</literal>
|
||||
in the above example). The order in which you are adding the text and the
|
||||
resource are <emphasis role="bold">very</emphasis> important. Be sure to
|
||||
<emphasis>first add the text</emphasis> and after that the resources. If
|
||||
you are doing it the other way around, it won't work!</para>
|
||||
</warning>
|
||||
</section>
|
||||
</section>
|
||||
<section id="mail-templates">
|
||||
<title>Creating email content using a templating library</title>
|
||||
<para>The code in the previous examples explicitly has been creating the
|
||||
content of the email message, using methods calls such as
|
||||
<methodname>message.setText(..)</methodname>. This is fine for
|
||||
simple cases, and it is okay in the context of the aforementioned
|
||||
examples, where the intent was to show you the very basics of the API.</para>
|
||||
<para>In your typical enterprise application though, you are not going
|
||||
to create the content of your emails using the above approach for a number
|
||||
of reasons.</para>
|
||||
<para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Creating HTML-based email content in Java code is tedious and error prone</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>There is no clear separation between display logic and business logic</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Changing the display structure of the email content requires writing Java code, recompiling, redeploying...</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<para>Typically the approach taken to address these issues is to use a template library
|
||||
such as FreeMarker or Velocity to define the display structure of email content. This leaves
|
||||
your code tasked only with creating the data that is to be rendered in the email
|
||||
template and sending the email. It is definitely a best practice for when
|
||||
the content of your emails becomes even moderately complex, and with
|
||||
the Spring Framework's support classes for FreeMarker and Velocity becomes
|
||||
quite easy to do. Find below an example of using the Velocity template library
|
||||
to create email content.</para>
|
||||
<section id="mail-templates-example">
|
||||
<title>A Velocity-based example</title>
|
||||
<para>To use <ulink url="http://velocity.apache.org">Velocity</ulink> to
|
||||
create your email template(s), you will need to have the Velocity libraries
|
||||
available on your classpath. You will also need to create one or more Velocity templates
|
||||
for the email content that your application needs. Find below the Velocity
|
||||
template that this example will be using... as you can see it is HTML-based,
|
||||
and since it is plain text it can be created using your favorite HTML editor
|
||||
without recourse to having to know Java.</para>
|
||||
<programlisting><lineannotation># in the <literal>com/foo/package</literal></lineannotation><![CDATA[
|
||||
<html>
|
||||
<body>
|
||||
<h3>Hi ${user.userName}, welcome to the Chipping Sodbury On-the-Hill message boards!</h3>
|
||||
|
||||
<div>
|
||||
Your email address is <a href="mailto:${user.emailAddress}">${user.emailAddress}</a>.
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>]]></programlisting>
|
||||
<para>Find below some simple code and Spring XML configuration that
|
||||
makes use of the above Velocity template to create email content and
|
||||
send email(s).</para>
|
||||
<programlisting><![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><![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-2.5.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>
|
||||
@@ -0,0 +1,503 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<chapter id="metadata">
|
||||
<title>Annotations and Source Level Metadata Support</title>
|
||||
<section id="metadata-introduction">
|
||||
<title>Introduction</title>
|
||||
<para>Source-level metadata is the addition of <emphasis>attributes</emphasis> or
|
||||
<emphasis>annotations</emphasis> to program elements - usually, classes
|
||||
and/or methods.</para>
|
||||
<para>For example, we might add metadata to a class as follows:</para>
|
||||
<programlisting><![CDATA[/**
|
||||
* Normal comments here
|
||||
* @@org.springframework.transaction.interceptor.DefaultTransactionAttribute()
|
||||
*/
|
||||
public class PetStoreImpl implements PetStoreFacade, OrderService {]]></programlisting>
|
||||
<para>We could add metadata to a method as follows:</para>
|
||||
<programlisting><![CDATA[/**
|
||||
* Normal comments here
|
||||
* @@org.springframework.transaction.interceptor.RuleBasedTransactionAttribute()
|
||||
* @@org.springframework.transaction.interceptor.RollbackRuleAttribute(Exception.class)
|
||||
* @@org.springframework.transaction.interceptor.NoRollbackRuleAttribute("ServletException")
|
||||
*/
|
||||
public void echoException(Exception ex) throws Exception {
|
||||
....
|
||||
}]]></programlisting>
|
||||
<para>Both of these examples use Jakarta Commons Attributes syntax.</para>
|
||||
<para>
|
||||
Source-level metadata was introduced to the mainstream by XDoclet
|
||||
(in the Java world) and by the release of Microsoft's .NET platform, which
|
||||
uses source-level attributes to control transactions, pooling and other
|
||||
behavior.
|
||||
</para>
|
||||
<para>
|
||||
The value in this approach has been recognized in the J2EE
|
||||
community. For example, it's much less verbose than the traditional XML
|
||||
deployment descriptors used exclusively by EJB. While it is desirable to
|
||||
externalize some things from program source code, some important
|
||||
enterprise settings - notably transaction characteristics - arguably belong
|
||||
in program source. Contrary to the assumptions of the EJB spec, it seldom
|
||||
makes sense to modify the transactional characteristics of a method
|
||||
(although parameters like transaction timeouts might change!).
|
||||
</para>
|
||||
<para>
|
||||
Although metadata attributes are typically used mainly by framework
|
||||
infrastructure to describe the services application classes require, it
|
||||
should also be possible for metadata attributes to be queried at runtime.
|
||||
This is a key distinction from solutions such as XDoclet, which
|
||||
view metadata primarily as a way of generating code such as EJB artefacts.
|
||||
</para>
|
||||
<para>
|
||||
There are a number of solutions in this space, including:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><emphasis role="bold">Standard Java Annotations</emphasis>: the
|
||||
standard Java metadata implementation (developed as JSR-175 and available
|
||||
in Java 5). Spring has specific Java 5 annotations for transactional
|
||||
demarcation, JMX, and aspects (to be precise they are AspectJ annotations).
|
||||
However, since Spring supports Java 1.4 as well, a solution for said
|
||||
JVM versions is needed too. Spring metadata support provides such a
|
||||
solution.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><emphasis role="bold">XDoclet</emphasis>: well-established
|
||||
solution, primarily intended for code generation.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Various <emphasis role="bold">open source attribute
|
||||
implementations</emphasis>, for Java 1.4, of which Commons
|
||||
Attributes is the most complete implementation. All these require
|
||||
a special pre- or post-compilation step.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
<section id="metadata-spring">
|
||||
<title>Spring's metadata support</title>
|
||||
<para>In keeping with its provision of abstractions over important
|
||||
concepts, Spring provides a facade to metadata implementations, in the
|
||||
form of the <interfacename>org.springframework.metadata.Attributes</interfacename>
|
||||
interface. Such a facade adds value for several reasons:</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Even though Java 5 provides metadata support at language level, there will
|
||||
still be value in providing such an abstraction:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Java 5 metadata is static. It is associated with a class
|
||||
at compile time, and cannot be changed in a deployed
|
||||
environment (annotation state can actually be changed
|
||||
at runtime using reflection, but doing so would really be
|
||||
a bad practice). There is a need for hierarchical metadata,
|
||||
providing the ability to override certain attribute values in
|
||||
deployment - for example, in an XML file.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Java 5 metadata is returned through the Java reflection
|
||||
API. This makes it impossible to mock during test time. Spring
|
||||
provides a simple interface to allow this.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>There will be a need for metadata support in 1.3 and 1.4
|
||||
applications for at least two years. Spring aims to provide
|
||||
working solutions <emphasis>now</emphasis>; forcing the use of
|
||||
Java 5 is not an option in such an important area.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Current metadata APIs, such as Commons Attributes (used by
|
||||
Spring 1.0-1.2) are hard to test. Spring provides a simple metadata
|
||||
interface that is much easier to mock.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>The Spring <interfacename>Attributes</interfacename> interface looks like this:</para>
|
||||
<programlisting><![CDATA[public interface Attributes {
|
||||
|
||||
Collection getAttributes(Class targetClass);
|
||||
|
||||
Collection getAttributes(Class targetClass, Class filter);
|
||||
|
||||
Collection getAttributes(Method targetMethod);
|
||||
|
||||
Collection getAttributes(Method targetMethod, Class filter);
|
||||
|
||||
Collection getAttributes(Field targetField);
|
||||
|
||||
Collection getAttributes(Field targetField, Class filter);
|
||||
}]]></programlisting>
|
||||
<para>
|
||||
This is a lowest common denominator interface. JSR-175 offers more
|
||||
capabilities than this, such as attributes on method arguments.
|
||||
</para>
|
||||
<para>
|
||||
Note that this interface offers <classname>Object</classname>
|
||||
attributes, like .NET. This distinguishes it from attribute systems such
|
||||
as that of Nanning Aspects, which offer only <classname>String</classname>
|
||||
attributes. There is a significant advantage in supporting
|
||||
<classname>Object</classname> attributes, namely that it enables
|
||||
attributes to participate in class hierarchies and allows such
|
||||
attributes to react intelligently to their configuration parameters.
|
||||
</para>
|
||||
<para>
|
||||
With most attribute providers, attribute classes are configured
|
||||
via constructor arguments or JavaBean properties. Commons Attributes
|
||||
supports both.
|
||||
</para>
|
||||
<para>As with all Spring abstraction APIs, <interfacename>Attributes</interfacename>
|
||||
is an interface. This makes it easy to mock attribute implementations for unit tests.</para>
|
||||
</section>
|
||||
<section id="metadata-annotations">
|
||||
<title>Annotations</title>
|
||||
<para>
|
||||
The Spring Framework ships with a number of custom Java 5+ annotations.
|
||||
</para>
|
||||
<section id="metadata-annotations-required">
|
||||
<title><interfacename>@Required</interfacename></title>
|
||||
<para>The <interfacename>@Required</interfacename> annotation in the
|
||||
<literal>org.springframework.beans.factory.annotation</literal>
|
||||
package can be used to <emphasis>mark</emphasis> a property as
|
||||
being <emphasis>'required-to-be-set'</emphasis> (i.e. an
|
||||
annotated (setter) method of a class must be configured to be
|
||||
dependency injected with a value), else an
|
||||
<classname>Exception</classname> will be thrown by the container
|
||||
at runtime.</para>
|
||||
<para>The best way to illustrate the usage of this annotation is to
|
||||
show an example:</para>
|
||||
<programlisting><![CDATA[public class SimpleMovieLister {
|
||||
|
||||
]]><lineannotation>// the <classname>SimpleMovieLister</classname> has a dependency on the <interfacename>MovieFinder</interfacename></lineannotation><![CDATA[
|
||||
private MovieFinder movieFinder;
|
||||
|
||||
]]><lineannotation>// a setter method so that the Spring container can 'inject' a <interfacename>MovieFinder</interfacename></lineannotation><![CDATA[
|
||||
@Required
|
||||
public void setMovieFinder(MovieFinder movieFinder) {
|
||||
this.movieFinder = movieFinder;
|
||||
}
|
||||
|
||||
]]><lineannotation>// business logic that actually 'uses' the injected <interfacename>MovieFinder</interfacename> is omitted...</lineannotation><![CDATA[
|
||||
}]]></programlisting>
|
||||
<para>
|
||||
Hopefully the above class definition reads easy on the eye.
|
||||
Any and all <interfacename>BeanDefinitions</interfacename> for the
|
||||
<classname>SimpleMovieLister</classname> class must be provided
|
||||
with a value.
|
||||
</para>
|
||||
<para>
|
||||
Let's look at an example of some XML configuration that will
|
||||
<emphasis role="bold">not</emphasis> pass validation.
|
||||
</para>
|
||||
<programlisting><![CDATA[<bean id="movieLister" class="x.y.SimpleMovieLister">
|
||||
]]><lineannotation><!-- whoops, no MovieFinder is set (and this property is <interfacename>@Required</interfacename>) --></lineannotation><![CDATA[
|
||||
</bean>]]></programlisting>
|
||||
<para>
|
||||
At runtime the following message will be generated by the Spring container
|
||||
(the rest of the stack trace has been truncated).
|
||||
</para>
|
||||
<programlisting><![CDATA[Exception in thread "main" java.lang.IllegalArgumentException:
|
||||
Property 'movieFinder' is required for bean 'movieLister'.]]></programlisting>
|
||||
<para>
|
||||
There is one last little (small, tiny) piece of Spring configuration
|
||||
that is required to actually <emphasis>'switch on'</emphasis> this
|
||||
behavior. Simply annotating the <emphasis>'setter'</emphasis> properties
|
||||
of your classes is not enough to get this behavior. You need
|
||||
to enable a component that is aware of the <interfacename>@Required</interfacename>
|
||||
annotation and that can process it appropriately.
|
||||
</para>
|
||||
<para>
|
||||
This component is the <classname>RequiredAnnotationBeanPostProcessor</classname> class.
|
||||
This is a special <interfacename>BeanPostProcessor</interfacename>
|
||||
implementation that is <interfacename>@Required</interfacename>-aware
|
||||
and actually provides the <emphasis>'blow up if this required property
|
||||
has not been set'</emphasis> logic. It is <emphasis>very</emphasis> easy
|
||||
to configure; simply drop the following bean definition into your Spring
|
||||
XML configuration.
|
||||
</para>
|
||||
<programlisting><![CDATA[<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/>]]></programlisting>
|
||||
<para>
|
||||
Finally, one can configure an instance of the
|
||||
<classname>RequiredAnnotationBeanPostProcessor</classname> class to look
|
||||
for <emphasis>another</emphasis> <interfacename>Annotation</interfacename> type.
|
||||
This is great if you already have your own
|
||||
<interfacename>@Required</interfacename>-style annotation. Simply plug it into
|
||||
the definition of a <classname>RequiredAnnotationBeanPostProcessor</classname> and
|
||||
you are good to go.
|
||||
</para>
|
||||
<para>
|
||||
By way of an example, let's suppose you (or your organization / team) have
|
||||
defined an attribute called @ <interfacename>Mandatory</interfacename>.
|
||||
You can make a <classname>RequiredAnnotationBeanPostProcessor</classname>
|
||||
instance <interfacename>@Mandatory</interfacename>-aware like so:
|
||||
</para>
|
||||
<programlisting><![CDATA[<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor">
|
||||
<property name="requiredAnnotationType" value="your.company.package.Mandatory"/>
|
||||
</bean>]]></programlisting>
|
||||
<para>
|
||||
Here is the source code for the <interfacename>@Mandatory</interfacename>
|
||||
annotation. You will need to ensure that your custom annotation type
|
||||
is itself annotated with appropriate annotations for its target
|
||||
and runtime retention policy.
|
||||
</para>
|
||||
<programlisting><![CDATA[package your.company.package;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface Mandatory {
|
||||
}]]></programlisting>
|
||||
</section>
|
||||
<section id="metadata-annotations-other">
|
||||
<title>Other @Annotations in Spring</title>
|
||||
<para>
|
||||
Annotations are also used in a number of other places throughout Spring.
|
||||
Rather than being described here, these annotations are described in that
|
||||
section or chapter of the reference documentation to which they are most
|
||||
relevant.
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><xref linkend="transaction-declarative-annotations"/></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><xref linkend="aop-atconfigurable"/></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><xref linkend="aop-ataspectj"/></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><xref linkend="beans-annotation-config"/></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><xref linkend="beans-classpath-scanning"/></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
</section>
|
||||
<section id="metadata-commons">
|
||||
<title>Integration with Jakarta Commons Attributes</title>
|
||||
<para>
|
||||
Presently Spring supports only Jakarta Commons Attributes out of the
|
||||
box, although it is easy to provide implementations of the
|
||||
<interfacename>org.springframework.metadata.Attributes</interfacename> interface for
|
||||
other metadata providers.
|
||||
</para>
|
||||
<para>
|
||||
<emphasis role="bold">Commons Attributes 2.2</emphasis>
|
||||
(<ulink url="http://jakarta.apache.org/commons/attributes/">http://jakarta.apache.org/commons/attributes/</ulink>)
|
||||
is a capable attributes solution. It supports attribute configuration via
|
||||
constructor arguments and JavaBean properties, which offers better
|
||||
self-documentation in attribute definitions. (Support for JavaBean
|
||||
properties was added at the request of the Spring team.)
|
||||
</para>
|
||||
<para>
|
||||
We've already seen two examples of Commons Attributes attributes
|
||||
definitions. In general, we will need to express:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>The name of the attribute class</emphasis>. This can
|
||||
be a fully qualified name (FQN), as shown above. If the relevant attribute class has already
|
||||
been imported, the FQN isn't required. It's also possible to specify
|
||||
"attribute packages" in attribute compiler configuration.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>Any necessary parameterization.</emphasis> This is done via
|
||||
constructor arguments or JavaBean properties.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>Bean properties look as follows:</para>
|
||||
<programlisting><![CDATA[/**
|
||||
* @@MyAttribute(myBooleanJavaBeanProperty=true)
|
||||
*/]]></programlisting>
|
||||
<para>
|
||||
It's possible to combine constructor arguments and JavaBean
|
||||
properties (as in Spring IoC).
|
||||
</para>
|
||||
<para>
|
||||
Because, unlike Java 1.5 attributes, Commons Attributes is not
|
||||
integrated with the Java language, it is necessary to run a special
|
||||
<emphasis>attribute compilation</emphasis> step as part of the build
|
||||
process.
|
||||
</para>
|
||||
<para>
|
||||
To run Commons Attributes as part of the build process, you will
|
||||
need to do the following:
|
||||
</para>
|
||||
<para>
|
||||
1. Copy the necessary library jars to
|
||||
<literal>$ANT_HOME/lib</literal>. Four Jars are required, and all are
|
||||
distributed with Spring:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>the Commons Attributes compiler jar and API jar</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>xJavadoc.jar from XDoclet</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>commons-collections.jar from Jakarta Commons</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
2. Import the Commons Attributes ant tasks into your project build
|
||||
script, as follows:
|
||||
</para>
|
||||
<programlisting><![CDATA[<taskdef resource="org/apache/commons/attributes/anttasks.properties"/>]]></programlisting>
|
||||
<para>
|
||||
3. Next, define an attribute compilation task, which will use the
|
||||
Commons Attributes attribute-compiler task to "compile" the attributes in
|
||||
the source. This process results in the generation of additional sources,
|
||||
to a location specified by the <literal>destdir</literal> attribute. Here we show the use of
|
||||
a temporary directory for storing the generated files:
|
||||
</para>
|
||||
<programlisting><![CDATA[<target name="compileAttributes">
|
||||
|
||||
<attribute-compiler destdir="${commons.attributes.tempdir}">
|
||||
<fileset dir="${src.dir}" includes="**/*.java"/>
|
||||
</attribute-compiler>
|
||||
|
||||
</target>]]></programlisting>
|
||||
<para>
|
||||
The compile target that runs javac over the sources should depend on
|
||||
this attribute compilation task, and must also compile the generated
|
||||
sources, which we output to our destination temporary directory. If there
|
||||
are syntax errors in your attribute definitions, they will normally be
|
||||
caught by the attribute compiler. However, if the attribute definitions
|
||||
are syntactically plausible, but specify invalid types or class names, the
|
||||
compilation of the generated attribute classes may fail. In this case, you
|
||||
can look at the generated classes to establish the cause of the
|
||||
problem.
|
||||
</para>
|
||||
<remark>
|
||||
Commons Attributes also provides Maven support. Please refer to
|
||||
Commons Attributes documentation for further information.
|
||||
</remark>
|
||||
<para>
|
||||
While this attribute compilation process may look complex, in fact
|
||||
it's a one-off cost. Once set up, attribute compilation is incremental, so
|
||||
it doesn't usually noticeably slow the build process. And once the
|
||||
compilation process is set up, you may find that use of attributes as
|
||||
described in this chapter can save you a lot of time in other
|
||||
areas.
|
||||
</para>
|
||||
<para>
|
||||
If you require attribute indexing support (only currently required
|
||||
by Spring for attribute-targeted web controllers, discussed below), you
|
||||
will need an additional step, which must be performed on a jar file of
|
||||
your compiled classes. In this additional step, Commons Attributes will
|
||||
create an index of all the attributes defined on your sources, for
|
||||
efficient lookup at runtime. The step looks like this:
|
||||
</para>
|
||||
<programlisting><![CDATA[<attribute-indexer jarFile="myCompiledSources.jar">
|
||||
|
||||
<classpath refid="master-classpath"/>
|
||||
|
||||
</attribute-indexer>]]></programlisting>
|
||||
<remark>
|
||||
See the <literal>/attributes</literal> directory of the Spring JPetStore sample
|
||||
application for an example of this build process. You can take the build
|
||||
script it contains and modify it for your own projects.
|
||||
</remark>
|
||||
<para>
|
||||
If your unit tests depend on attributes, try to express the
|
||||
dependency on the Spring Attributes abstraction, rather than Commons
|
||||
Attributes. Not only is this more portable - for example, your tests will
|
||||
still work if you switch to Java 1.5 attributes in future - it simplifies
|
||||
testing. Also, Commons Attributes is a static API, while Spring provides a
|
||||
metadata interface that you can easily mock.
|
||||
</para>
|
||||
</section>
|
||||
<section id="metadata-uses">
|
||||
<title>Metadata and Spring AOP autoproxying</title>
|
||||
<para>
|
||||
The most important uses of metadata attributes are in conjunction
|
||||
with Spring AOP. This provides a .NET-like programming model, where
|
||||
declarative services are automatically provided to application objects
|
||||
that declare metadata attributes. Such metadata attributes can be
|
||||
supported out of the box by the framework, as in the case of declarative
|
||||
transaction management, or can be custom.
|
||||
</para>
|
||||
<section id="metadata-fundamentals">
|
||||
<title>Fundamentals</title>
|
||||
<para>
|
||||
This builds on the Spring AOP autoproxy functionality.
|
||||
Configuration might look like this:
|
||||
</para>
|
||||
<programlisting><![CDATA[<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
|
||||
|
||||
<bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">
|
||||
<property name="transactionInterceptor" ref="txInterceptor" />
|
||||
</bean>
|
||||
|
||||
<bean id="txInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
|
||||
<property name="transactionManager" ref="transactionManager" />
|
||||
<property name="transactionAttributeSource">
|
||||
<bean class="org.springframework.transaction.interceptor.AttributesTransactionAttributeSource">
|
||||
<property name="attributes" ref="attributes" />
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="attributes" class="org.springframework.metadata.commons.CommonsAttributes" />]]></programlisting>
|
||||
<para>
|
||||
The basic concepts here should be familiar from the discussion of
|
||||
autoproxying in the AOP chapter.
|
||||
</para>
|
||||
<para>
|
||||
The most important bean definitions are the auto-proxy creator
|
||||
and the advisor. Note that the actual bean names are not important;
|
||||
what matters is their class.
|
||||
</para>
|
||||
<para>
|
||||
The bean definition of class
|
||||
<classname>org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator</classname>
|
||||
will automatically advise ("auto-proxy") all bean instances in the
|
||||
current factory based on matching advisor implementations. This class
|
||||
knows nothing about attributes, but relies on advisors' pointcuts
|
||||
matching. The pointcuts, however, do know about attributes.
|
||||
</para>
|
||||
<para>
|
||||
Thus we simply need an AOP advisor that will provide declarative
|
||||
transaction management based on attributes.
|
||||
</para>
|
||||
<para>
|
||||
It is possible to add arbitrary custom advisor implementations as
|
||||
well, and they will also be evaluated and applied automatically. (You
|
||||
can use advisors whose pointcuts match on criteria besides attributes in
|
||||
the same autoproxy configuration, if necessary.)
|
||||
</para>
|
||||
<para>
|
||||
Finally, the <literal>attributes</literal> bean is the Commons
|
||||
Attributes Attributes implementation. Replace it with another
|
||||
implementation of the
|
||||
<interfacename>org.springframework.metadata.Attributes</interfacename>
|
||||
interface to source attributes from a different source.
|
||||
</para>
|
||||
</section>
|
||||
<section id="metadata-tx">
|
||||
<title>Declarative transaction management</title>
|
||||
<para>
|
||||
The most common use of source-level attributes is to provide
|
||||
declarative transaction management. Once the bean definitions
|
||||
shown above are in place, you can define any number of application
|
||||
objects requiring declarative transactions. Only those classes or
|
||||
methods with transaction attributes will be given transaction advice.
|
||||
You need to do nothing except define the required transaction
|
||||
attributes.
|
||||
</para>
|
||||
<para>Please note that you can specify transaction attributes at either class
|
||||
or method level. Class-level attributes, if specified, will be "inherited"
|
||||
by all methods whereas method attributes will wholly override any
|
||||
class-level attributes.</para>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,796 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter id="new-in-2">
|
||||
<title>What's new in Spring 2.0 and 2.5?</title>
|
||||
|
||||
<section id="new-in-2-intro">
|
||||
<title>Introduction</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.</para>
|
||||
|
||||
<sidebar id="new-in-2-intro-java">
|
||||
<title>Java SE and Java EE Support</title>
|
||||
|
||||
<para>The Spring Framework continues to be compatible with all versions
|
||||
of Java since (and including) Java 1.4.2. This means that Java 1.4.2,
|
||||
Java 5 and Java 6 are supported, although some advanced functionality of
|
||||
the Spring Framework will not be available to you if you are committed to
|
||||
using Java 1.4.2. Spring 2.5 introduces dedicated support for Java 6,
|
||||
after Spring 2.0's in-depth support for Java 5 throughout the
|
||||
framework.</para>
|
||||
|
||||
<para>Furthermore, Spring remains compatible with J2EE 1.3 and higher,
|
||||
while at the same time introducing dedicated support for Java EE 5. This
|
||||
means that Spring can be consistently used on application servers such
|
||||
as BEA WebLogic 8.1, 9.0, 9.2 and 10, IBM WebSphere 5.1, 6.0, 6.1 and 7,
|
||||
Oracle OC4J 10.1.3 and 11, JBoss 3.2, 4.0, 4.2 and 5.0, as well as Tomcat
|
||||
4.1, 5.0, 5.5 and 6.0, Jetty 4.2, 5.1 and 6.1, Resin 2.1, 3.0 and 3.1
|
||||
and GlassFish V1 and V2.</para>
|
||||
|
||||
<para><emphasis>NOTE: We generally recommend using the most recent
|
||||
version of each application server generation. In particular,
|
||||
make sure you are using BEA WebLogic 8.1 SP6 or higher and
|
||||
WebSphere 6.0.2.19 / 6.1.0.9 or higher, respectively, when using
|
||||
those WebLogic and WebSphere generations with Spring 2.5.</emphasis></para>
|
||||
</sidebar>
|
||||
|
||||
<para>This chapter is a guide to the new and improved features of Spring
|
||||
2.0 and 2.5. It is intended to provide a high-level summary so that
|
||||
seasoned Spring architects and developers can become immediately familiar
|
||||
with the new Spring 2.x functionality. For more in-depth information on
|
||||
the features, please refer to the corresponding sections hyperlinked from
|
||||
within this chapter.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-ioc">
|
||||
<title>The Inversion of Control (IoC) container</title>
|
||||
|
||||
<para>One of the areas that contains a considerable number of 2.0
|
||||
and 2.5 improvements is Spring's IoC container.</para>
|
||||
|
||||
<section id="new-in-2-ioc-scopes">
|
||||
<title>New bean scopes</title>
|
||||
|
||||
<para>Previous versions of Spring had IoC container level support for
|
||||
exactly two distinct bean scopes (singleton and prototype). Spring 2.0
|
||||
improves on this by not only providing a number of additional scopes
|
||||
depending on the environment in which Spring is being deployed (for
|
||||
example, request and session scoped beans in a web environment), but
|
||||
also by providing integration points so that Spring users can create
|
||||
their own scopes.</para>
|
||||
|
||||
<para>It should be noted that although the underlying (and internal)
|
||||
implementation for singleton- and prototype-scoped beans has been
|
||||
changed, this change is totally transparent to the end user... no
|
||||
existing configuration needs to change, and no existing configuration
|
||||
will break.</para>
|
||||
|
||||
<para>Both the new and the original scopes are detailed in the section
|
||||
entitled <xref linkend="beans-factory-scopes"/>.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-ioc-configuration">
|
||||
<title>Easier XML configuration</title>
|
||||
|
||||
<para>Spring XML configuration is now even easier, thanks to the advent
|
||||
of the new XML configuration syntax based on XML Schema. If you want to
|
||||
take advantage of the new tags that Spring provides (and the Spring team
|
||||
certainly suggest that you do because they make configuration less
|
||||
verbose and easier to read), then do read the section entitled <xref
|
||||
linkend="xsd-config"/>.</para>
|
||||
|
||||
<para>On a related note, there is a new, updated DTD for Spring 2.0 that
|
||||
you may wish to reference if you cannot take advantage of the XML
|
||||
Schema-based configuration. The DOCTYPE declaration is included below
|
||||
for your convenience, but the interested reader should definitely read
|
||||
the <filename>'spring-beans-2.0.dtd'</filename> DTD included in the
|
||||
<filename class="directory">'dist/resources'</filename> directory of the
|
||||
Spring 2.5 distribution.</para>
|
||||
|
||||
<programlisting><!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
|
||||
"http://www.springframework.org/dtd/spring-beans-2.0.dtd"></programlisting>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-ioc-custom-configuration">
|
||||
<title>Extensible XML authoring</title>
|
||||
|
||||
<para>Not only is XML configuration easier to write, it is now also
|
||||
extensible.</para>
|
||||
|
||||
<para>What 'extensible' means in this context is that you, as an
|
||||
application developer, or (more likely) as a third party framework or
|
||||
product vendor, can write custom tags that other developers can then
|
||||
plug into their own Spring configuration files. This allows you to have
|
||||
your own domain specific language (the term is used loosely here) of
|
||||
sorts be reflected in the specific configuration of your own
|
||||
components.</para>
|
||||
|
||||
<para>Implementing custom Spring tags may not be of interest to every
|
||||
single application developer or enterprise architect using Spring in
|
||||
their own projects. We expect third-party vendors to be highly
|
||||
interested in developing custom configuration tags for use in Spring
|
||||
configuration files.</para>
|
||||
|
||||
<para>The extensible configuration mechanism is documented in <xref
|
||||
linkend="extensible-xml"/>.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-ioc-annotations">
|
||||
<title>Annotation-driven configuration</title>
|
||||
|
||||
<para>Spring 2.0 introduced support for various annotations for
|
||||
configuration purposes, such as <interfacename>@Transactional</interfacename>,
|
||||
<interfacename>@Required</interfacename> and <interfacename>@PersistenceContext</interfacename>
|
||||
/<interfacename>@PersistenceUnit</interfacename>.</para>
|
||||
|
||||
<para>Spring 2.5 introduces support for a complete set of configuration
|
||||
annotations: <interfacename>@Autowired</interfacename> in combination
|
||||
with support for the JSR-250 annotations <interfacename>@Resource</interfacename>,
|
||||
<interfacename>@PostConstruct</interfacename> and <interfacename>@PreDestroy</interfacename>
|
||||
.</para>
|
||||
|
||||
<para>Annotation-driven bean configuration is discussed in <xref
|
||||
linkend="beans-annotation-config"/>. Check out annotation support
|
||||
for Spring MVC as well: <xref linkend="new-in-2-web-annotations"/></para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-ioc-component-scanning">
|
||||
<title>Autodetecting components in the classpath</title>
|
||||
|
||||
<para>Spring 2.5 introduces support component scanning: autodetecting
|
||||
annotated components in the classpath. Typically, such component classes
|
||||
will be annotated with stereotypes such as <interfacename>@Component</interfacename>,
|
||||
<interfacename>@Repository</interfacename>, <interfacename>@Service</interfacename>,
|
||||
<interfacename>@Controller</interfacename>. Depending on the application
|
||||
context configuration, such component classes will be autodetected and
|
||||
turned into Spring bean definitions, not requiring explicit configuration
|
||||
for each such bean.</para>
|
||||
|
||||
<para>Annotation-driven bean configuration is discussed in <xref
|
||||
linkend="beans-stereotype-annotations"/>.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-aop">
|
||||
<title>Aspect Oriented Programming (AOP)</title>
|
||||
|
||||
<para>Spring 2.0 has a much improved AOP offering. The Spring AOP
|
||||
framework itself is markedly easier to configure in XML, and significantly
|
||||
less verbose as a result; and Spring 2.0 integrates with the AspectJ
|
||||
pointcut language and @AspectJ aspect declaration style. The chapter
|
||||
entitled <xref linkend="aop"/> is dedicated to describing this new
|
||||
support.</para>
|
||||
|
||||
<section id="new-in-2-aop-configuration">
|
||||
<title>Easier AOP XML configuration</title>
|
||||
|
||||
<para>Spring 2.0 introduces new schema support for defining aspects
|
||||
backed by regular Java objects. This support takes advantage of the
|
||||
AspectJ pointcut language and offers fully typed advice (i.e. no more
|
||||
casting and <literal>Object[]</literal> argument manipulation). Details
|
||||
of this support can be found in the section entitled <xref
|
||||
linkend="aop-schema"/>.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-aop-aspectj">
|
||||
<title>Support for @AspectJ aspects</title>
|
||||
|
||||
<para>Spring 2.0 also supports aspects defined using the @AspectJ
|
||||
annotations. These aspects can be shared between AspectJ and Spring AOP,
|
||||
and require (honestly!) only some simple configuration. Said support for
|
||||
@AspectJ aspects is discussed in <xref
|
||||
linkend="aop-ataspectj"/>.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-aop-bean-pointcuts">
|
||||
<title>Support for bean name pointcut element</title>
|
||||
|
||||
<para>Spring 2.5 introduces support for the <literal>bean(...)</literal>
|
||||
pointcut element, matching specific named beans according to Spring-defined
|
||||
bean names. See <xref linkend="aop-pointcuts-designators"/> for details.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-aop-load-time-weaving">
|
||||
<title>Support for AspectJ load-time weaving</title>
|
||||
|
||||
<para>Spring 2.5 introduces explicit support AspectJ load-time weaving,
|
||||
as alternative to the proxy-based AOP framework. The new
|
||||
<literal>context:load-time-weaver</literal> configuration element
|
||||
automatically activates AspectJ aspects as defined in AspectJ's
|
||||
<literal>META-INF/aop.xml</literal> descriptor, applying them to the
|
||||
current application context through registering a transformer with the
|
||||
underlying ClassLoader. Note that this only works in environments with
|
||||
class transformation support. Check out <xref linkend="aop-aj-ltw"/>
|
||||
for the capabilities and limitations.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-middle-tier">
|
||||
<title>The Middle Tier</title>
|
||||
|
||||
<section id="new-in-2-middle-tier-transaction-configuration">
|
||||
<title>Easier configuration of declarative transactions in XML</title>
|
||||
|
||||
<para>The way that transactions are configured in Spring 2.0 has been
|
||||
changed significantly. The previous 1.2.x style of configuration
|
||||
continues to be valid (and supported), but the new style is markedly
|
||||
less verbose and is the recommended style. Spring 2.0 also ships with an
|
||||
AspectJ aspects library that you can use to make pretty much any object
|
||||
transactional - even objects not created by the Spring IoC container.</para>
|
||||
|
||||
<para>Spring 2.5 supports convenient annotation-driven transaction
|
||||
management in combination with load-time weaving, through the use of
|
||||
<literal>context:load-time-weaver</literal> in combination with
|
||||
<literal>tx:annotation-driven mode="aspectj"</literal>.</para>
|
||||
|
||||
<para>The chapter entitled <xref linkend="transaction"/> contains all
|
||||
of the details.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-middle-tier-websphere">
|
||||
<title>Full WebSphere transaction management support</title>
|
||||
|
||||
<para>Spring 2.5 explicitly supports IBM's WebSphere Application Server,
|
||||
in particular with respect to WebSphere's transaction manager.
|
||||
Transaction suspension is now fully supported through the use of
|
||||
WebSphere's new <interfacename>UOWManager</interfacename> API, which
|
||||
is available on WAS 6.0.2.19+ and 6.0.1.9+.</para>
|
||||
|
||||
<para>So if you run a Spring-based application on the WebSphere
|
||||
Application Server, we highly recommend to use Spring 2.5's
|
||||
<classname>WebSphereUowTransactionManager</classname> as your
|
||||
<interfacename>PlatformTransactionManager</interfacename> of choice.
|
||||
This is also IBM's official recommendation.</para>
|
||||
|
||||
<para>For automatic detection of the underlying JTA-based transaction
|
||||
platform, consider the use of Spring 2.5's new
|
||||
<literal>tx:jta-transaction-manager</literal> configuration element.
|
||||
This will autodetect BEA WebLogic and IBM WebSphere, registering the
|
||||
appropriate <interfacename>PlatformTransactionManager</interfacename>.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-middle-tier-jpa">
|
||||
<title>JPA</title>
|
||||
|
||||
<para>Spring 2.0 ships with a JPA abstraction layer that is similar in
|
||||
intent to Spring's JDBC abstraction layer in terms of scope and general
|
||||
usage patterns.</para>
|
||||
|
||||
<para>If you are interested in using a JPA-implementation as the
|
||||
backbone of your persistence layer, the section entitled <xref
|
||||
linkend="orm-jpa"/> is dedicated to detailing Spring's support and
|
||||
value-add in this area.</para>
|
||||
|
||||
<para>Spring 2.5 upgrades its OpenJPA support to OpenJPA 1.0,
|
||||
with support for advanced features such as savepoints.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-middle-tier-async-jms">
|
||||
<title>Asynchronous JMS</title>
|
||||
|
||||
<para>Prior to Spring 2.0, Spring's JMS offering was limited to sending
|
||||
messages and the <emphasis>synchronous</emphasis> receiving of messages.
|
||||
This functionality (encapsulated in the
|
||||
<classname>JmsTemplate</classname> class) is great, but it doesn't
|
||||
address the requirement for the <emphasis>asynchronous</emphasis>
|
||||
receiving of messages.</para>
|
||||
|
||||
<para>Spring 2.0 now ships with full support for the reception of
|
||||
messages in an asynchronous fashion, as detailed in the section entitled
|
||||
<xref linkend="jms-asynchronousMessageReception"/>.</para>
|
||||
|
||||
<para>As of Spring 2.5, the JCA style of setting up asynchronous
|
||||
message listeners is supported as well, through the
|
||||
<classname>GenericMessageEndpointManager</classname> facility.
|
||||
This is an alternative to the standard JMS listener facility, allowing
|
||||
closer integration with message brokers such as ActiveMQ and JORAM.
|
||||
See <xref linkend="jms-jca-message-endpoint-manager"/>.</para>
|
||||
|
||||
<para>Spring 2.5 also introduces an XML namespace for simplifying JMS
|
||||
configuration, offering concise configuration of a large numbers of
|
||||
listeners. This namespace supports both the standard JMS listener facility
|
||||
as well as the JCA setup style, with minimal changes in the configuration.
|
||||
See <xref linkend="jms-namespace"/>.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-middle-tier-jdbc">
|
||||
<title>JDBC</title>
|
||||
|
||||
<para>There are some small (but nevertheless notable) new classes in the
|
||||
Spring Framework's JDBC support library. The first, <link
|
||||
linkend="jdbc-NamedParameterJdbcTemplate"><classname>NamedParameterJdbcTemplate</classname></link>,
|
||||
provides support for programming JDBC statements using named parameters
|
||||
(as opposed to programming JDBC statements using only classic
|
||||
placeholder (<literal>'?'</literal>) arguments.</para>
|
||||
|
||||
<para>Another of the new classes, the <link
|
||||
linkend="jdbc-SimpleJdbcTemplate"><classname>SimpleJdbcTemplate</classname></link>,
|
||||
is aimed at making using the <classname>JdbcTemplate</classname> even
|
||||
easier to use when you are developing against Java 5+ (Tiger).</para>
|
||||
|
||||
<para>Spring 2.5 significantly extends the functionality of
|
||||
<classname>SimpleJdbcTemplate</classname> and introduces
|
||||
<classname>SimpleJdbcCall</classname> and <classname>SimpleJdbcInsert</classname>
|
||||
operation objects.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-web">
|
||||
<title>The Web Tier</title>
|
||||
|
||||
<para>The web tier support has been <emphasis>substantially</emphasis>
|
||||
improved and expanded in Spring 2.0, with annotation-based controllers
|
||||
introduced in Spring 2.5.</para>
|
||||
|
||||
<section id="new-in-2-web-convention">
|
||||
<title>Sensible defaulting in Spring MVC</title>
|
||||
|
||||
<para>For a lot of projects, sticking to established conventions and
|
||||
having reasonable defaults is just what the projects need... this theme
|
||||
of convention-over-configuration now has explicit support in Spring MVC.
|
||||
What this means is that if you establish a set of naming conventions for
|
||||
your <literal>Controllers</literal> and views, you can
|
||||
<emphasis>substantially</emphasis> cut down on the amount of XML
|
||||
configuration that is required to setup handler mappings, view
|
||||
resolvers, <classname>ModelAndView</classname> instances, etc. This is a
|
||||
great boon with regards to rapid prototyping, and can also lend a degree
|
||||
of (always good-to-have) consistency across a codebase.</para>
|
||||
|
||||
<para>Spring MVC's convention-over-configuration support is detailed in
|
||||
the section entitled <xref linkend="mvc-coc"/></para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-web-portlet">
|
||||
<title>Portlet framework</title>
|
||||
|
||||
<para>Spring 2.0 ships with a Portlet framework that is conceptually
|
||||
similar to the Spring MVC framework. Detailed coverage of the Spring
|
||||
Portlet framework can be found in the section entitled <xref
|
||||
linkend="portlet"/>.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-web-annotations">
|
||||
<title>Annotation-based controllers</title>
|
||||
|
||||
<para>Spring 2.5 introduces an annotation-based programming model for MVC
|
||||
controllers, using annotations such as <interfacename>@RequestMapping</interfacename>,
|
||||
<interfacename>@RequestParam</interfacename>, <interfacename>@ModelAttribute</interfacename>,
|
||||
etc. This annotation support is available for both Servlet MVC and Portlet
|
||||
MVC. Controllers implemented in this style do not have to extend specific
|
||||
base classes or implement specific interfaces. Furthermore, they do not
|
||||
usually have direct dependencies on Servlet or Portlet API's, although
|
||||
they can easily get access to Servlet or Portlet facilities if desired.
|
||||
For further details, see <xref linkend="mvc-annotation"/>.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-web-form-tags">
|
||||
<title>A form tag library for Spring MVC</title>
|
||||
|
||||
<para>A rich JSP tag library for Spring MVC was <emphasis>the</emphasis>
|
||||
JIRA issue that garnered the most votes from Spring users (by a wide
|
||||
margin).</para>
|
||||
|
||||
<para>Spring 2.0 ships with a full featured JSP tag library that makes
|
||||
the job of authoring JSP pages much easier when using Spring MVC; the
|
||||
Spring team is confident it will satisfy all of those developers who
|
||||
voted for the issue on JIRA. The new tag library is itself covered in
|
||||
the section entitled <xref linkend="view-jsp-formtaglib"/>, and a quick
|
||||
reference to all of the new tags can be found in the appendix entitled
|
||||
<xref linkend="spring-form.tld"/>.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-web-tiles2">
|
||||
<title>Tiles 2 support</title>
|
||||
|
||||
<para>Spring 2.5 ships support for Tiles 2, the next generation of the
|
||||
popular Tiles templating framework. This supersedes Spring's former support
|
||||
for Tiles 1, as included in Struts 1.x. See <xref linkend="view-tiles"/>
|
||||
for details.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-web-jsf12">
|
||||
<title>JSF 1.2 support</title>
|
||||
|
||||
<para>Spring 2.5 supports JSF 1.2, providing a JSF 1.2 variant of Spring's
|
||||
<classname>DelegatingVariableResolver</classname> in the form of the new
|
||||
<classname>SpringBeanFacesELResolver</classname>.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-web-jaxws">
|
||||
<title>JAX-WS support</title>
|
||||
|
||||
<para>Spring 2.5 fully supports JAX-WS 2.0/2.1, as included in Java 6 and Java EE 5.
|
||||
JAX-WS is the successor of JAX-RPC, allowing access to WSDL/SOAP-based web
|
||||
services as well as JAX-WS style exposure of web services.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-other">
|
||||
<title>Everything else</title>
|
||||
|
||||
<para>This final section outlines all of the other new and improved Spring
|
||||
2.0/2.5 features and functionality.</para>
|
||||
|
||||
<section id="new-in-2-other-dynamic-language-support">
|
||||
<title>Dynamic language support</title>
|
||||
|
||||
<para>Spring 2.0 introduced support for beans written in languages other
|
||||
than Java, with the currently supported dynamic languages being JRuby,
|
||||
Groovy and BeanShell. This dynamic language support is comprehensively
|
||||
detailed in the section entitled <xref linkend="dynamic-language"/>.</para>
|
||||
|
||||
<para>Spring 2.5 refines the dynamic languages support with autowiring
|
||||
and support for the recently released JRuby 1.0.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-other-testing">
|
||||
<title>Enhanced testing support</title>
|
||||
|
||||
<para>Spring 2.5 introduces the <emphasis>Spring TestContext
|
||||
Framework</emphasis> which provides annotation-driven unit and integration
|
||||
testing support that is agnostic of the actual testing framework in use.
|
||||
The same techniques and annotation-based configuration used in, for
|
||||
example, a JUnit 3.8 environment can also be applied to tests written with
|
||||
JUnit 4.4, TestNG, etc.</para>
|
||||
|
||||
<para>In addition to providing generic and extensible testing
|
||||
infrastructure, the <emphasis>Spring TestContext Framework</emphasis>
|
||||
provides out-of-the-box support for Spring-specific integration testing
|
||||
functionality such as <link linkend="testcontext-ctx-management">context
|
||||
management and caching</link>, <link
|
||||
linkend="testcontext-fixture-di">dependency injection of test
|
||||
fixtures</link>, and <link linkend="testcontext-tx">transactional test
|
||||
management</link> with default rollback semantics.</para>
|
||||
|
||||
<para>To discover how this new testing support can assist you with writing
|
||||
unit and integration tests, consult <xref linkend="testcontext-framework"/>
|
||||
of the revised testing chapter.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-other-jmx">
|
||||
<title>JMX support</title>
|
||||
|
||||
<para>The Spring Framework 2.0 has support for
|
||||
<literal>Notifications</literal>; it is also possible to exercise
|
||||
declarative control over the registration behavior of MBeans with an
|
||||
<literal>MBeanServer</literal>.</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<xref linkend="jmx-notifications"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<xref linkend="jmx-exporting-registration-behavior"/>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>Furthermore, Spring 2.5 provides a
|
||||
<link linkend="jmx-context-mbeanexport"><literal>context:mbean-export</literal></link>
|
||||
configuration element for convenient registration of annotated bean classes,
|
||||
detecting Spring's <interfacename>@ManagedResource</interfacename> annotation.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-other-jca">
|
||||
<title>Deploying a Spring application context as JCA adapter</title>
|
||||
|
||||
<para>Spring 2.5 supports the deployment of a Spring application context
|
||||
as JCA resource adapter, packaged as a JCA RAR file. This allows headless
|
||||
application modules to be deployed into J2EE servers, getting access to
|
||||
all the server's infrastructure e.g. for executing scheduled tasks,
|
||||
listening for incoming messages, etc.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-other-taskexecutor">
|
||||
<title>Task scheduling</title>
|
||||
|
||||
<para>Spring 2.0 offers an abstraction around the scheduling of tasks.
|
||||
For the interested developer, the section entitled <xref
|
||||
linkend="scheduling-task-executor"/> contains all of the
|
||||
details.</para>
|
||||
|
||||
<para>The <interfacename>TaskExecutor</interfacename> abstraction is used
|
||||
throughout the framework itself as well, e.g. for the asynchronous JMS support.
|
||||
In Spring 2.5, it is also used in the JCA environment support.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-other-java5">
|
||||
<title>Java 5 (Tiger) support</title>
|
||||
|
||||
<para>Find below pointers to documentation describing some of the new
|
||||
Java 5 support in Spring 2.0 and 2.5.</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<xref linkend="beans-annotation-config"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<xref linkend="metadata-annotations-required"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<xref linkend="transaction-declarative-annotations"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<xref linkend="jdbc-SimpleJdbcTemplate"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<xref linkend="orm-jpa"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<xref linkend="aop-ataspectj"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<xref linkend="aop-atconfigurable"/>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-migrating">
|
||||
<title>Migrating to Spring 2.5</title>
|
||||
|
||||
<para>This final section details issues that may arise during any
|
||||
migration from Spring 1.2/2.0 to Spring 2.5.</para>
|
||||
|
||||
<para>Upgrading to Spring 2.5 from a Spring 2.0.x application should
|
||||
simply be a matter of dropping the Spring 2.5 jar into the appropriate
|
||||
location in your application's directory structure. We highly recommend
|
||||
upgrading to Spring 2.5 from any Spring 2.0 application that runs on
|
||||
JDK 1.4.2 or higher, in particular when running on Java 5 or higher,
|
||||
leveraging the significant configuration conveniences and performance
|
||||
improvements that Spring 2.5 has to offer.</para>
|
||||
|
||||
<para>Whether an upgrade from Spring 1.2.x will be as seamless depends on
|
||||
how much of the Spring APIs you are using in your code. Spring 2.0
|
||||
removed pretty much all of the classes and methods previously marked
|
||||
as deprecated in the Spring 1.2.x codebase, so if you have been using
|
||||
such classes and methods, you will of course have to use alternative
|
||||
classes and methods (some of which are summarized below).</para>
|
||||
|
||||
<para>With regards to configuration, Spring 1.2.x style XML configuration
|
||||
is 100%, satisfaction-guaranteed compatible with the Spring 2.5 library.
|
||||
Of course if you are still using the Spring 1.2.x DTD, then you won't be
|
||||
able to take advantage of some of the new Spring 2.0 functionality (such
|
||||
as <link linkend="new-in-2-ioc-scopes">scopes</link> and <link
|
||||
linkend="new-in-2-aop-configuration">easier AOP</link> and <link
|
||||
linkend="new-in-2-middle-tier-transaction-configuration">transaction
|
||||
configuration</link>), but nothing will blow up.</para>
|
||||
|
||||
<para>The suggested migration strategy is to drop in the Spring 2.5 jar(s)
|
||||
to benefit from the improved code present in the release (bug fixes,
|
||||
optimizations, etc.). You can then, on an incremental basis, choose to
|
||||
start using the new Spring 2.5 features and configuration. For example,
|
||||
you could choose to start configuring just your aspects in the new Spring
|
||||
2 style; it is perfectly valid to have 90% of your configuration using
|
||||
the old-school Spring 1.2.x configuration (which references the 1.2.x
|
||||
DTD), and have the other 10% using the new Spring 2 configuration (which
|
||||
references the 2.0/2.5 DTD or XSD). Bear in mind that you are not forced to
|
||||
upgrade your XML configuration should you choose to drop in the Spring 2.5
|
||||
libraries.</para>
|
||||
|
||||
<section id="new-in-2-migrating-changes">
|
||||
<title>Changes</title>
|
||||
|
||||
<para>For a comprehensive list of changes, consult the
|
||||
<filename>'changelog.txt'</filename> file that is located in the top
|
||||
level directory of the Spring Framework distribution.</para>
|
||||
|
||||
<section id="new-in-2-migrating-jdk">
|
||||
<title>Supported JDK versions</title>
|
||||
|
||||
<para>As of Spring 2.5, support for JDK 1.3 has been removed,
|
||||
following Sun's official deprecation of JDK 1.3 in late 2006.
|
||||
If you haven't done so already, upgrade to JDK 1.4.2 or higher.</para>
|
||||
|
||||
<para>If you need to stick with an application server that only supports
|
||||
JDK 1.3, such as WebSphere 4.0 or 5.0, we recommend using the
|
||||
Spring Framework version 2.0.7/2.0.8 which still supports JDK 1.3.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-migrating-packaging">
|
||||
<title>Jar packaging in Spring 2.5</title>
|
||||
|
||||
<para>As of Spring 2.5, Spring Web MVC is no longer part of the
|
||||
<filename class="libraryfile">'spring.jar'</filename> file. Spring MVC
|
||||
can be found in <filename class="libraryfile">'spring-webmvc.jar'</filename>
|
||||
and <filename class="libraryfile">'spring-webmvc-portlet.jar'</filename>
|
||||
in the <literal>lib/modules</literal> directory of the distribution.
|
||||
Furthermore, the Struts 1.x support has been factored out into
|
||||
<filename class="libraryfile">'spring-webmvc-struts.jar'</filename>.</para>
|
||||
|
||||
<para><emphasis>Note: The commonly used Spring's <classname>DispatcherServlet</classname>
|
||||
is part of Spring's Web MVC framework.</emphasis> As a consequence,
|
||||
you need to add <filename class="libraryfile">'spring-webmvc.jar'</filename>
|
||||
(or <filename class="libraryfile">'spring-webmvc-portlet/struts.jar'</filename>)
|
||||
to a <filename class="libraryfile">'spring.jar'</filename> scenario,
|
||||
even if you are just using <classname>DispatcherServlet</classname>
|
||||
for remoting purposes (e.g. exporting Hessian or HTTP invoker services).</para>
|
||||
|
||||
<para>Spring 2.0's <filename class="libraryfile">'spring-jmx.jar'</filename>
|
||||
and <filename class="libraryfile">'spring-remoting.jar'</filename> have been
|
||||
merged into Spring 2.5's <filename class="libraryfile">'spring-context.jar'</filename>
|
||||
(for the JMX and non-HTTP remoting support) and partly into
|
||||
<filename class="libraryfile">'spring-web.jar'</filename>
|
||||
(for the HTTP remoting support).</para>
|
||||
|
||||
<para>Spring 2.0's <filename class="libraryfile">'spring-support.jar'</filename>
|
||||
has been renamed to <filename class="libraryfile">'spring-context-support.jar'</filename>,
|
||||
expressing the actual support relationship more closely.
|
||||
<filename class="libraryfile">'spring-portlet.jar'</filename> has been
|
||||
renamed to <filename class="libraryfile">'spring-webmvc-portlet.jar'</filename>,
|
||||
since it is technically a submodule of Spring's Web MVC framework.
|
||||
Analogously, <filename class="libraryfile">'spring-struts.jar'</filename>
|
||||
has been renamed to <filename class="libraryfile">'spring-webmvc-struts.jar'</filename>.
|
||||
</para>
|
||||
|
||||
<para>Spring 2.0's <filename class="libraryfile">'spring-jdo.jar'</filename>,
|
||||
<filename class="libraryfile">'spring-jpa.jar'</filename>,
|
||||
<filename class="libraryfile">'spring-hibernate3.jar'</filename>,
|
||||
<filename class="libraryfile">'spring-toplink.jar'</filename>
|
||||
and <filename class="libraryfile">'spring-ibatis.jar'</filename>
|
||||
have been combined into Spring 2.5's coarse-granular
|
||||
<filename class="libraryfile">'spring-orm.jar'</filename>.</para>
|
||||
|
||||
<para>Spring 2.5's <filename class="libraryfile">'spring-test.jar'</filename>
|
||||
supersedes the previous <filename class="libraryfile">'spring-mock.jar'</filename>,
|
||||
indicating the stronger focus on the test context framework.
|
||||
Note that <filename class="libraryfile">'spring-test.jar'</filename>
|
||||
contains everything <filename class="libraryfile">'spring-mock.jar'</filename>
|
||||
contained in previous Spring versions; hence it can be used as a
|
||||
straightforward replacement for unit and integration testing purposes.</para>
|
||||
|
||||
<para>Spring 2.5's <filename class="libraryfile">'spring-tx.jar'</filename>
|
||||
supersedes the previous <filename class="libraryfile">'spring-dao.jar'</filename>
|
||||
and <filename class="libraryfile">'spring-jca.jar'</filename> files,
|
||||
indicating the stronger focus on the transaction framework.</para>
|
||||
|
||||
<para>Spring 2.5 ships its framework jars as OSGi-compliant bundles
|
||||
out of the box. This facilitates use of Spring in OSGi environments,
|
||||
not requiring custom packaging anymore.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-migrating-xml-configuration">
|
||||
<title>XML configuration</title>
|
||||
|
||||
<para>Spring 2.0 ships with XSDs that describe Spring's XML metadata
|
||||
format in a much richer fashion than the DTD that shipped with
|
||||
previous versions. The old DTD is still fully supported, but if
|
||||
possible you are encouraged to reference the XSD files at the top of
|
||||
your bean definition files.</para>
|
||||
|
||||
<para>One thing that has changed in a (somewhat) breaking fashion is
|
||||
the way that bean scopes are defined. If you are using the Spring 1.2
|
||||
DTD you can continue to use the <literal>'singleton'</literal>
|
||||
attribute. You can however choose to <link
|
||||
linkend="new-in-2-ioc-configuration">reference the new Spring 2.0
|
||||
DTD</link> which does not permit the use of the
|
||||
<literal>'singleton'</literal> attribute, but rather uses the
|
||||
<literal>'scope'</literal> attribute to define the bean lifecycle
|
||||
scope.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-migrating-deprecated">
|
||||
<title>Deprecated classes and methods</title>
|
||||
|
||||
<para>A number of classes and methods that previously were marked as
|
||||
<literal>@deprecated</literal> have been removed from the Spring 2.0
|
||||
codebase. The Spring team decided that the 2.0 release marked a fresh
|
||||
start of sorts, and that any deprecated 'cruft' was better excised now
|
||||
instead of continuing to haunt the codebase for the foreseeable
|
||||
future.</para>
|
||||
|
||||
<para>As mentioned previously, for a comprehensive list of changes,
|
||||
consult the <filename>'changelog.txt'</filename> file that is located
|
||||
in the top level directory of the Spring Framework distribution.</para>
|
||||
|
||||
<para>The following classes/interfaces have been removed as of Spring
|
||||
2.0:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><interfacename>ResultReader</interfacename> : Use the
|
||||
<interfacename>RowMapper</interfacename> interface instead.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><classname>BeanFactoryBootstrap</classname> : Consider using
|
||||
a <interfacename>BeanFactoryLocator</interfacename> or a custom
|
||||
bootstrap class instead.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-migrating-ojb">
|
||||
<title>Apache OJB</title>
|
||||
|
||||
<para>As of Spring 2.0, support for Apache OJB was <emphasis>totally
|
||||
removed</emphasis> from the main Spring source tree. The Apache OJB
|
||||
integration library is still available, but can be found in its new
|
||||
home in the <ulink url="https://springmodules.dev.java.net/">Spring
|
||||
Modules project</ulink>.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-migrating-ibatis">
|
||||
<title>iBATIS</title>
|
||||
|
||||
<para>Please note that support for iBATIS SQL Maps 1.3 has been removed.
|
||||
If you haven't done so already, upgrade to iBATIS SQL Maps 2.3.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-migrating-hibernate">
|
||||
<title>Hibernate</title>
|
||||
|
||||
<para>As of Spring 2.5, support for Hibernate 2.1 and Hibernate 3.0
|
||||
has been removed. If you haven't done so already, upgrade to
|
||||
Hibernate 3.1 or higher.</para>
|
||||
|
||||
<para>If you need to stick with Hibernate 2.1 or 3.0 for the time
|
||||
being, we recommend to keep using the Spring Framework version
|
||||
2.0.7/2.0.8 which still supports those versions of Hibernate.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-migrating-jdo">
|
||||
<title>JDO</title>
|
||||
|
||||
<para>As of Spring 2.5, support for JDO 1.0 has been removed.
|
||||
If you haven't done so already, upgrade to JDO 2.0 or higher.</para>
|
||||
|
||||
<para>If you need to stick with JDO 1.0 for the time being,
|
||||
we recommend to keep using the Spring Framework version
|
||||
2.0.7/2.0.8 which still supports that version of JDO.</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-migrating-UrlFilenameViewController">
|
||||
<title><classname>UrlFilenameViewController</classname></title>
|
||||
|
||||
<para>Since Spring 2.0, the view name that is determined by the
|
||||
<classname>UrlFilenameViewController</classname> now takes into
|
||||
account the nested path of the request. This is a breaking change
|
||||
from the original contract of the
|
||||
<classname>UrlFilenameViewController</classname>, and means that if
|
||||
you are upgrading from Spring 1.x to Spring 2.x and you are using this
|
||||
class you <emphasis>might</emphasis> have to change your Spring Web
|
||||
MVC configuration slightly. Refer to the class level Javadocs of the
|
||||
<classname>UrlFilenameViewController</classname> to see examples of
|
||||
the new contract for view name determination.</para>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-other-applications">
|
||||
<title>Updated sample applications</title>
|
||||
|
||||
<para>A number of the sample applications have also been updated to
|
||||
showcase the new and improved features of Spring 2.0. So do take the time
|
||||
to investigate them. The aforementioned sample applications can be found
|
||||
in the <filename class="directory">'samples'</filename> directory of the
|
||||
full Spring distribution
|
||||
(<filename>'spring-with-dependencies.[zip|tar.gz]'</filename>).</para>
|
||||
|
||||
<para>Spring 2.5 features revised versions of the PetClinic and PetPortal sample
|
||||
applications, reengineered from the ground up for leveraging Spring 2.5's
|
||||
annotation configuration features. It also uses Java 5 autoboxing, generics,
|
||||
varargs and the enhanced for loop. A Java 5 or 6 SDK is now required to build and
|
||||
run the sample. Check out PetClinic and PetPortal to get an impression of what
|
||||
Spring 2.5 has to offer!</para>
|
||||
</section>
|
||||
|
||||
<section id="new-in-2-other-documentation">
|
||||
<title>Improved documentation</title>
|
||||
|
||||
<para>The Spring reference documentation has also substantially been
|
||||
updated to reflect all of the above features new in Spring 2.0 and 2.5.
|
||||
While every effort has been made to ensure that there are no errors in this
|
||||
documentation, some errors may nevertheless have crept in. If you do spot
|
||||
any typos or even more serious errors, and you can spare a few cycles
|
||||
during lunch, please do bring the error to the attention of the Spring
|
||||
team by <ulink
|
||||
url="http://opensource.atlassian.com/projects/spring/">raising an
|
||||
issue</ulink>.</para>
|
||||
|
||||
<para>Special thanks to Arthur Loder for his tireless proofreading of the
|
||||
Spring Framework reference documentation and JavaDocs.</para>
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter id="new-in-2">
|
||||
<title>What's new in Spring 3.0?</title>
|
||||
|
||||
<section id="new-in-3-intro">
|
||||
<title>Introduction</title>
|
||||
|
||||
<para>*** WORK IN PROGRESS ***</para>
|
||||
|
||||
<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.</para>
|
||||
|
||||
<sidebar id="new-in-3-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 dedicated support for Java EE 6.</para>
|
||||
</sidebar>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="new-in-3-other-documentation">
|
||||
<title>Improved documentation</title>
|
||||
|
||||
<para>The Spring reference documentation has also substantially been
|
||||
updated to reflect all of the changes and new features for Spring 3.0.
|
||||
While every effort has been made to ensure that there are no errors in this
|
||||
documentation, some errors may nevertheless have crept in. If you do spot
|
||||
any typos or even more serious errors, and you can spare a few cycles
|
||||
during lunch, please do bring the error to the attention of the Spring
|
||||
team by <ulink
|
||||
url="http://jira.springframework.org/">raising an
|
||||
issue</ulink>.</para>
|
||||
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,251 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter id="introduction">
|
||||
<title>Introduction</title>
|
||||
|
||||
<sidebar id="background-ioc">
|
||||
<title>Background</title>
|
||||
|
||||
<para>In early 2004, Martin Fowler asked the readers of his site: when
|
||||
talking about Inversion of Control: <quote><emphasis>the question is, what
|
||||
aspect of control are [they] inverting?</emphasis></quote>. Fowler then
|
||||
suggested renaming the principle (or at least giving it a more
|
||||
self-explanatory name), and started to use the term <firstterm>Dependency
|
||||
Injection</firstterm>. His article then continued to explain the ideas
|
||||
underpinning the Inversion of Control (<acronym>IoC</acronym>) and
|
||||
Dependency Injection (<acronym>DI</acronym>) principle.</para>
|
||||
|
||||
<para>If you need a decent insight into IoC and DI, please do refer to
|
||||
said article : <ulink
|
||||
url="http://martinfowler.com/articles/injection.html">http://martinfowler.com/articles/injection.html</ulink>.</para>
|
||||
</sidebar>
|
||||
|
||||
<para>Java applications (a loose term which runs the gamut from constrained
|
||||
applets to full-fledged n-tier server-side enterprise applications)
|
||||
typically are composed of a number of objects that collaborate with one
|
||||
another to form the application proper. The objects in an application can
|
||||
thus be said to have <emphasis>dependencies</emphasis> between
|
||||
themselves.</para>
|
||||
|
||||
<para>The Java language and platform provides a wealth of functionality for
|
||||
architecting and building applications, ranging all the way from the very
|
||||
basic building blocks of primitive types and classes (and the means to
|
||||
define new classes), to rich full-featured application servers and web
|
||||
frameworks. One area that is decidedly conspicuous by its absence is any
|
||||
means of taking the basic building blocks and composing them into a coherent
|
||||
whole; this area has typically been left to the purvey of the architects and
|
||||
developers tasked with building an application (or applications). Now to be
|
||||
fair, there are a number of design patterns devoted to the business of
|
||||
composing the various classes and object instances that makeup an
|
||||
all-singing, all-dancing application. Design patterns such as
|
||||
<firstterm>Factory</firstterm>, <firstterm>Abstract Factory</firstterm>,
|
||||
<firstterm>Builder</firstterm>, <firstterm>Decorator</firstterm>, and
|
||||
<firstterm>Service Locator</firstterm> (to name but a few) have widespread
|
||||
recognition and acceptance within the software development industry
|
||||
(presumably that is why these patterns have been formalized as patterns in
|
||||
the first place). This is all very well, but these patterns are just that:
|
||||
best practices given a name, typically together with a description of what
|
||||
the pattern does, where the pattern is typically best applied, the problems
|
||||
that the application of the pattern addresses, and so forth. Notice that the
|
||||
last paragraph used the phrase <quote>... a <emphasis>description</emphasis>
|
||||
of what the pattern does...</quote>; pattern books and wikis are typically
|
||||
listings of such formalized best practice that you can certainly take away,
|
||||
mull over, and then <emphasis>implement yourself</emphasis> in your
|
||||
application.</para>
|
||||
|
||||
<para>The IoC component of the Spring Framework addresses the enterprise
|
||||
concern of taking the classes, objects, and services that are to compose an
|
||||
application, by providing a formalized means of composing these various
|
||||
disparate components into a fully working application ready for use. The
|
||||
Spring Framework takes best practices that have been proven over the years
|
||||
in numerous applications and formalized as design patterns, and actually
|
||||
codifies these patterns as first class objects that you as an architect and
|
||||
developer can take away and integrate into your own application(s). This is
|
||||
a <firstterm>Very Good Thing Indeed</firstterm> as attested to by the
|
||||
numerous organizations and institutions that have used the Spring Framework
|
||||
to engineer robust, <emphasis>maintainable</emphasis> applications.</para>
|
||||
|
||||
<section id="introduction-overview">
|
||||
<title>Overview</title>
|
||||
|
||||
<para>The Spring Framework contains a lot of features, which are
|
||||
well-organized in six modules shown in the diagram below. This chapter
|
||||
discusses each of the modules in turn.</para>
|
||||
|
||||
<para><mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata align="left" fileref="images/spring-overview.png"
|
||||
format="PNG" />
|
||||
</imageobject>
|
||||
|
||||
<imageobject role="html">
|
||||
<imagedata align="center" fileref="images/spring-overview.png"
|
||||
format="PNG" />
|
||||
</imageobject>
|
||||
|
||||
<caption><para>Overview of the Spring Framework</para></caption>
|
||||
</mediaobject></para>
|
||||
|
||||
<para>The <link
|
||||
linkend="beans-introduction"><emphasis>Core</emphasis></link> package is
|
||||
the most fundamental part of the framework and provides the IoC and
|
||||
Dependency Injection features. The basic concept here is the
|
||||
<classname>BeanFactory</classname>, which provides a sophisticated
|
||||
implementation of the factory pattern which 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> package
|
||||
build on the solid base provided by the <link
|
||||
linkend="beans-introduction"><emphasis>Core</emphasis></link> package: it
|
||||
provides a way to access objects in a framework-style manner in a fashion
|
||||
somewhat reminiscent of a JNDI-registry. The context package inherits its
|
||||
features from the beans package and adds support for internationalization
|
||||
(I18N) (using for example resource bundles), event-propagation,
|
||||
resource-loading, and the transparent creation of contexts by, for
|
||||
example, a servlet container.</para>
|
||||
|
||||
<para>The <link linkend="dao-introduction"><emphasis>DAO</emphasis></link>
|
||||
package provides a JDBC-abstraction layer that removes the need to do
|
||||
tedious JDBC coding and parsing of database-vendor specific error codes.
|
||||
Also, the <link linkend="jdbc-introduction">JDBC</link> package provides a
|
||||
way to do programmatic as well as declarative transaction management, not
|
||||
only for classes implementing special interfaces, but for <emphasis>all
|
||||
your POJOs (plain old Java objects)</emphasis>.</para>
|
||||
|
||||
<para>The <link linkend="orm-introduction"><emphasis>ORM</emphasis></link>
|
||||
package 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
|
||||
those O/R-mappers in combination with all the other features Spring
|
||||
offers, such as the simple declarative transaction management feature
|
||||
mentioned previously.</para>
|
||||
|
||||
<para>Spring's <link
|
||||
linkend="aop-introduction"><emphasis>AOP</emphasis></link> package
|
||||
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 implementing
|
||||
functionality that should logically speaking be separated. Using
|
||||
source-level metadata functionality you can also incorporate all kinds of
|
||||
behavioral information into your code, in a manner similar to that of .NET
|
||||
attributes.</para>
|
||||
|
||||
<para>Spring's <emphasis>Web</emphasis> package provides basic
|
||||
web-oriented integration features, such as multipart file-upload
|
||||
functionality, the initialization of the IoC container using servlet
|
||||
listeners and a web-oriented application context. When using Spring
|
||||
together with WebWork or Struts, this is the package to integrate
|
||||
with.</para>
|
||||
|
||||
<para>Spring's <link
|
||||
linkend="mvc-introduction"><emphasis>MVC</emphasis></link> package
|
||||
provides a Model-View-Controller (MVC) implementation for
|
||||
web-applications. Spring's MVC framework is not just any old
|
||||
implementation; it provides a <emphasis>clean</emphasis> separation
|
||||
between domain model code and web forms, and allows you to use all the
|
||||
other features of the Spring Framework.</para>
|
||||
</section>
|
||||
|
||||
<section id="overview-usagescenarios">
|
||||
<title>Usage scenarios</title>
|
||||
|
||||
<para>With the building blocks described above you can use Spring in all
|
||||
sorts of scenarios, from applets up to fully-fledged enterprise
|
||||
applications using Spring's transaction management functionality and web
|
||||
framework integration.</para>
|
||||
|
||||
<para><mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata align="center" fileref="images/full.png" format="PNG" />
|
||||
</imageobject>
|
||||
|
||||
<imageobject role="html">
|
||||
<imagedata align="center" fileref="images/full.gif" format="GIF" />
|
||||
</imageobject>
|
||||
|
||||
<caption><para>Typical full-fledged Spring web
|
||||
application</para></caption>
|
||||
</mediaobject></para>
|
||||
|
||||
<para>By using Spring's <link
|
||||
linkend="transaction-declarative">declarative transaction management
|
||||
features</link> the web application is fully transactional, just as it
|
||||
would be when using container managed transactions as provided by
|
||||
Enterprise JavaBeans. All your custom business logic can be implemented
|
||||
using simple POJOs, managed by Spring's IoC container. Additional services
|
||||
include support for sending email, and validation that is independent of
|
||||
the web layer enabling you to choose where to execute validation rules.
|
||||
Spring's ORM support is integrated with JPA, Hibernate, JDO and iBatis;
|
||||
for example, when using Hibernate, you can continue to use your existing
|
||||
mapping files and standard Hibernate
|
||||
<interfacename>SessionFactory</interfacename> configuration. Form
|
||||
controllers seamlessly integrate the web-layer with the domain model,
|
||||
removing the need for <classname>ActionForms</classname> or other classes
|
||||
that transform HTTP parameters to values for your domain model.</para>
|
||||
|
||||
<para><mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata align="center" fileref="images/thirdparty-web.png"
|
||||
format="PNG" />
|
||||
</imageobject>
|
||||
|
||||
<imageobject role="html">
|
||||
<imagedata align="center" fileref="images/thirdparty-web.gif"
|
||||
format="GIF" />
|
||||
</imageobject>
|
||||
|
||||
<caption><para>Spring middle-tier using a third-party web
|
||||
framework</para></caption>
|
||||
</mediaobject></para>
|
||||
|
||||
<para>Sometimes the current 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
|
||||
using WebWork, Struts, Tapestry, or other UI frameworks can be integrated
|
||||
perfectly well with a Spring-based middle-tier, allowing you to use the
|
||||
transaction features that Spring offers. The only thing you need to do is
|
||||
wire up your business logic using an
|
||||
<classname>ApplicationContext</classname> and integrate your web layer
|
||||
using a <classname>WebApplicationContext</classname>.</para>
|
||||
|
||||
<para><mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata align="center" fileref="images/remoting.png" format="PNG" />
|
||||
</imageobject>
|
||||
|
||||
<imageobject role="html">
|
||||
<imagedata align="center" fileref="images/remoting.gif" format="GIF" />
|
||||
</imageobject>
|
||||
|
||||
<caption><para>Remoting usage scenario</para></caption>
|
||||
</mediaobject></para>
|
||||
|
||||
<para>When you need to access existing code via 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 suddenly is not
|
||||
that hard anymore.</para>
|
||||
|
||||
<para><mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata align="center" fileref="images/ejb.png" format="PNG" />
|
||||
</imageobject>
|
||||
|
||||
<imageobject role="html">
|
||||
<imagedata align="center" fileref="images/ejb.gif" format="GIF" />
|
||||
</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, failsafe web applications that might need declarative
|
||||
security.</para>
|
||||
</section>
|
||||
</chapter>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<preface id="preface">
|
||||
<title>Preface</title>
|
||||
|
||||
<para>Developing software applications is hard enough even with good tools
|
||||
and technologies. Implementing applications using platforms which promise
|
||||
everything but turn out to be heavy-weight, hard to control and not very
|
||||
efficient during the development cycle makes it even harder. Spring provides
|
||||
a light-weight solution for building enterprise-ready applications, while
|
||||
still supporting the possibility of using declarative transaction
|
||||
management, remote access to your logic using RMI or web services, and
|
||||
various options for persisting your data to a database. Spring provides a
|
||||
full-featured <link linkend="mvc-introduction">MVC framework</link>, and
|
||||
transparent ways of integrating <link linkend="aop-introduction">AOP</link>
|
||||
into your software.</para>
|
||||
|
||||
<para>Spring could potentially be a one-stop-shop for all your enterprise
|
||||
applications; however, Spring is modular, allowing you to use just those
|
||||
parts of it that you need, without having to bring in the rest. You can use
|
||||
the IoC container, with Struts on top, but you could also choose to use just
|
||||
the <link linkend="orm-hibernate">Hibernate integration code</link> or the
|
||||
<link linkend="jdbc-introduction">JDBC abstraction layer</link>. Spring has
|
||||
been (and continues to be) designed to be non-intrusive, meaning
|
||||
dependencies on the framework itself are generally none (or absolutely
|
||||
minimal, depending on the area of use).</para>
|
||||
|
||||
<para>This document provides a reference guide to Spring's features. Since
|
||||
this document is still to be considered very much work-in-progress, if you
|
||||
have any requests or comments, please post them on the user mailing list or
|
||||
on the support forums at <ulink
|
||||
url="http://forum.springframework.org/" />.</para>
|
||||
|
||||
<para>Before we go on, a few words of gratitude are due to Christian Bauer
|
||||
(of the <ulink url="http://www.hibernate.org/">Hibernate</ulink> team), who
|
||||
prepared and adapted the DocBook-XSL software in order to be able to create
|
||||
Hibernate's reference guide, thus also allowing us to create this one. Also
|
||||
thanks to Russell Healy for doing an extensive and valuable review of some
|
||||
of the material.</para>
|
||||
</preface>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,739 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter id="resources">
|
||||
<title>Resources</title>
|
||||
|
||||
<section id="resources-introduction">
|
||||
<title>Introduction</title>
|
||||
|
||||
<para>Java's standard <classname>java.net.URL</classname> class and
|
||||
standard handlers for various URL prefixes unfortunately are not quite
|
||||
adequate enough for all access to low-level resources. For example,
|
||||
there is no standardized <classname>URL</classname> implementation
|
||||
that may be used to access a resource that needs to be obtained from
|
||||
the classpath, or relative to a
|
||||
<interfacename>ServletContext</interfacename>. While it is possible
|
||||
to register new handlers for specialized <classname>URL</classname>
|
||||
prefixes (similar to existing handlers for prefixes such as
|
||||
<literal>http:</literal>), this is generally quite complicated, and the
|
||||
<classname>URL</classname> interface still lacks some desirable
|
||||
functionality, such as a method to check for the existence of the
|
||||
resource being pointed to.</para>
|
||||
</section>
|
||||
|
||||
<section id="resources-resource">
|
||||
<title>The <interfacename>Resource</interfacename> interface</title>
|
||||
|
||||
<para>Spring's <interfacename>Resource</interfacename> interface is meant
|
||||
to be a more capable interface for abstracting access to low-level
|
||||
resources.</para>
|
||||
|
||||
<programlisting><![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><![CDATA[public interface InputStreamSource {
|
||||
|
||||
InputStream getInputStream() throws IOException;
|
||||
}]]></programlisting>
|
||||
|
||||
<para>Some of the most important methods from the
|
||||
<interfacename>Resource</interfacename> interface are:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><methodname>getInputStream()</methodname>: locates and opens the
|
||||
resource, returning an <classname>InputStream</classname> for reading
|
||||
from the resource. It is expected that each invocation returns a
|
||||
fresh <classname>InputStream</classname>. It is the responsibility of
|
||||
the caller to close the stream.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><methodname>exists()</methodname>: returns a
|
||||
<literal>boolean</literal> indicating whether this resource actually
|
||||
exists in physical form.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><methodname>isOpen()</methodname>: returns a
|
||||
<literal>boolean</literal> indicating whether this resource represents
|
||||
a handle with an open stream. If <literal>true</literal>, the
|
||||
<classname>InputStream</classname> cannot be read multiple times, and
|
||||
must be read once only and then closed to avoid resource leaks. Will
|
||||
be <literal>false</literal> for all usual resource implementations,
|
||||
with the exception of
|
||||
<classname>InputStreamResource</classname>.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><methodname>getDescription()</methodname>: returns a description
|
||||
for this resource, to be used for error output when working with the
|
||||
resource. This is often the fully qualified file name or the actual
|
||||
URL of the resource.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>Other methods allow you to obtain an actual
|
||||
<classname>URL</classname> or <classname>File</classname> object
|
||||
representing the resource (if the underlying implementation is compatible,
|
||||
and supports that functionality).</para>
|
||||
|
||||
<para>The <interfacename>Resource</interfacename> abstraction is used
|
||||
extensively in Spring itself, as an argument type in many method
|
||||
signatures when a resource is needed. Other methods in some Spring APIs
|
||||
(such as the constructors to various
|
||||
<interfacename>ApplicationContext</interfacename> implementations), take a
|
||||
<classname>String</classname> which in unadorned or simple form is used to
|
||||
create a <interfacename>Resource</interfacename> appropriate to that
|
||||
context implementation, or via special prefixes on the
|
||||
<classname>String</classname> path, allow the caller to specify that a
|
||||
specific <interfacename>Resource</interfacename> implementation must be
|
||||
created and used.</para>
|
||||
|
||||
<para>While the <interfacename>Resource</interfacename> interface is used
|
||||
a lot with Spring and by Spring, it's actually very useful to use as a
|
||||
general utility class by itself in your own code, for access to resources,
|
||||
even when your code doesn't know or care about any other parts of Spring.
|
||||
While this couples your code to Spring, it really only couples it to this
|
||||
small set of utility classes, which are serving as a more capable
|
||||
replacement for <classname>URL</classname>, and can be considered
|
||||
equivalent to any other library you would use for this purpose.</para>
|
||||
|
||||
<para>It is important to note that the
|
||||
<interfacename>Resource</interfacename> abstraction does not replace
|
||||
functionality: it wraps it where possible. For example, a
|
||||
<classname>UrlResource</classname> wraps a URL, and uses the wrapped
|
||||
<classname>URL</classname> to do its work.</para>
|
||||
</section>
|
||||
|
||||
<section id="resources-implementations">
|
||||
<title>Built-in <interfacename>Resource</interfacename> implementations</title>
|
||||
|
||||
<para>There are a number of <interfacename>Resource</interfacename>
|
||||
implementations that come supplied straight out of the box in
|
||||
Spring:</para>
|
||||
|
||||
<section id="resources-implementations-urlresource">
|
||||
<title><classname>UrlResource</classname></title>
|
||||
|
||||
<para>The <classname>UrlResource</classname> wraps a
|
||||
<classname>java.net.URL</classname>, and may be used to access any
|
||||
object that is normally accessible via a URL, such as files, an HTTP
|
||||
target, an FTP target, etc. All URLs have a standardized
|
||||
<classname>String</classname> representation, such that appropriate
|
||||
standardized prefixes are used to indicate one URL type from another.
|
||||
This includes <literal>file:</literal> for accessing filesystem paths,
|
||||
<literal>http:</literal> for accessing resources via the HTTP protocol,
|
||||
<literal>ftp:</literal> for accessing resources via FTP, etc.</para>
|
||||
|
||||
<para>A <classname>UrlResource</classname> is created by Java code
|
||||
explicitly using the <classname>UrlResource</classname> constructor, but
|
||||
will often be created implicitly when you call an API method which takes
|
||||
a <classname>String</classname> argument which is meant to represent a
|
||||
path. For the latter case, a JavaBeans
|
||||
<interfacename>PropertyEditor</interfacename> will ultimately decide
|
||||
which type of <interfacename>Resource</interfacename> to create. If the
|
||||
path string contains a few well-known (to it, that is) prefixes such as
|
||||
<literal>classpath:</literal>, it will create an appropriate specialized
|
||||
<interfacename>Resource</interfacename> for that prefix. However, if it
|
||||
doesn't recognize the prefix, it will assume the this is just a standard
|
||||
URL string, and will create a <classname>UrlResource</classname>.</para>
|
||||
</section>
|
||||
|
||||
<section id="resources-implementations-classpathresource">
|
||||
<title><classname>ClassPathResource</classname></title>
|
||||
|
||||
<para>This class represents a resource which should be obtained from the
|
||||
classpath. This uses either the thread context class loader, a given
|
||||
class loader, or a given class for loading resources.</para>
|
||||
|
||||
<para>This <interfacename>Resource</interfacename> implementation
|
||||
supports resolution as <classname>java.io.File</classname> if the class
|
||||
path resource resides in the file system, but not for classpath
|
||||
resources which reside in a jar and have not been expanded (by the
|
||||
servlet engine, or whatever the environment is) to the filesystem. To
|
||||
address this the various <interfacename>Resource</interfacename>
|
||||
implementations always support resolution as a
|
||||
<classname>java.net.URL</classname>.</para>
|
||||
|
||||
<para>A <classname>ClassPathResource</classname> is created by Java code
|
||||
explicitly using the <classname>ClassPathResource</classname>
|
||||
constructor, but will often be created implicitly when you call an API
|
||||
method which takes a <classname>String</classname> argument which is
|
||||
meant to represent a path. For the latter case, a JavaBeans
|
||||
<interfacename>PropertyEditor</interfacename> will recognize the special
|
||||
prefix <literal>classpath:</literal>on the string path, and create a
|
||||
<classname>ClassPathResource</classname> in that case.</para>
|
||||
</section>
|
||||
|
||||
<section id="resources-implementations-filesystemresource">
|
||||
<title><classname>FileSystemResource</classname></title>
|
||||
|
||||
<para>This is a <interfacename>Resource</interfacename> implementation
|
||||
for <classname>java.io.File</classname> handles. It obviously supports
|
||||
resolution as a <classname>File</classname>, and as a
|
||||
<classname>URL</classname>.</para>
|
||||
</section>
|
||||
|
||||
<section id="resources-implementations-servletcontextresource">
|
||||
<title><classname>ServletContextResource</classname></title>
|
||||
|
||||
<para>This is a <interfacename>Resource</interfacename> implementation
|
||||
for <interfacename>ServletContext</interfacename> resources,
|
||||
interpreting relative paths within the relevant web application's root
|
||||
directory.</para>
|
||||
|
||||
<para>This always supports stream access and URL access, but only allows
|
||||
<classname>java.io.File</classname> access when the web application
|
||||
archive is expanded and the resource is physically on the filesystem.
|
||||
Whether or not it's expanded and on the filesystem like this, or
|
||||
accessed directly from the JAR or somewhere else like a DB (it's
|
||||
conceivable) is actually dependent on the Servlet container.</para>
|
||||
</section>
|
||||
|
||||
<section id="resources-implementations-inputstreamresource">
|
||||
<title><classname>InputStreamResource</classname></title>
|
||||
|
||||
<para>A <interfacename>Resource</interfacename> implementation for a
|
||||
given <interfacename>InputStream</interfacename>. This should only be
|
||||
used if no specific <interfacename>Resource</interfacename>
|
||||
implementation is applicable. In particular, prefer
|
||||
<classname>ByteArrayResource</classname> or any of the file-based
|
||||
<interfacename>Resource</interfacename> implementations where
|
||||
possible.</para>
|
||||
|
||||
<para>In contrast to other <interfacename>Resource</interfacename>
|
||||
implementations, this is a descriptor for an
|
||||
<emphasis>already</emphasis> opened resource - therefore returning
|
||||
<literal>true</literal> from <methodname>isOpen()</methodname>. Do not
|
||||
use it if you need to keep the resource descriptor somewhere, or if you
|
||||
need to read a stream multiple times.</para>
|
||||
</section>
|
||||
|
||||
<section id="resources-implementations-bytearrayresource">
|
||||
<title><classname>ByteArrayResource</classname></title>
|
||||
|
||||
<para>This is a <interfacename>Resource</interfacename> implementation
|
||||
for a given byte array. It creates a
|
||||
<classname>ByteArrayInputStream</classname> for the given byte
|
||||
array.</para>
|
||||
|
||||
<para>It's useful for loading content from any given byte array, without
|
||||
having to resort to a single-use
|
||||
<classname>InputStreamResource</classname>.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="resources-resourceloader">
|
||||
<title>The <interfacename>ResourceLoader</interfacename></title>
|
||||
|
||||
<para>The <interfacename>ResourceLoader</interfacename> interface is meant
|
||||
to be implemented by objects that can return (i.e. load)
|
||||
<interfacename>Resource</interfacename> instances.</para>
|
||||
|
||||
<programlisting>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>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>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>Resource template = ctx.getResource("file:/some/resource/path/myTemplate.txt);</programlisting>
|
||||
|
||||
<programlisting>Resource template = ctx.getResource("http://myhost.com/resource/path/myTemplate.txt);</programlisting>
|
||||
|
||||
<para>The following table summarizes the strategy for converting
|
||||
<classname>String</classname>s to
|
||||
<interfacename>Resource</interfacename>s:</para>
|
||||
|
||||
<table pgwide="1" id="resources-resource-strings">
|
||||
<title>Resource strings</title>
|
||||
|
||||
<tgroup cols="3">
|
||||
<colspec align="left" />
|
||||
|
||||
<thead>
|
||||
<row>
|
||||
<entry align="center">Prefix</entry>
|
||||
|
||||
<entry align="center">Example</entry>
|
||||
|
||||
<entry align="center">Explanation</entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><para>classpath:</para></entry>
|
||||
|
||||
<entry><para> <literal>classpath:com/myapp/config.xml</literal>
|
||||
</para></entry>
|
||||
|
||||
<entry><para>Loaded from the classpath.</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para>file:</para></entry>
|
||||
|
||||
<entry><para> <literal>file:/data/config.xml</literal>
|
||||
</para></entry>
|
||||
|
||||
<entry><para> Loaded as a <classname>URL</classname>, from the
|
||||
filesystem. <footnote>
|
||||
<para>But see also the section entitled <xref
|
||||
linkend="resources-filesystemresource-caveats" />.</para>
|
||||
</footnote> </para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para>http:</para></entry>
|
||||
|
||||
<entry><para> <literal>http://myserver/logo.png</literal>
|
||||
</para></entry>
|
||||
|
||||
<entry><para>Loaded as a
|
||||
<classname>URL</classname>.</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para>(none)</para></entry>
|
||||
|
||||
<entry><para> <literal>/data/config.xml</literal> </para></entry>
|
||||
|
||||
<entry><para> Depends on the underlying
|
||||
<interfacename>ApplicationContext</interfacename>. </para></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<section id="resources-resourceloaderaware">
|
||||
<title>The <interfacename>ResourceLoaderAware</interfacename> interface</title>
|
||||
|
||||
<para>The <interfacename>ResourceLoaderAware</interfacename> interface is
|
||||
a special marker interface, identifying objects that expect to be provided
|
||||
with a <interfacename>ResourceLoader</interfacename> reference.</para>
|
||||
|
||||
<programlisting><![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 the section entitled
|
||||
<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 the section entitled <xref linkend="beans-autowired-annotation"/>.</para>
|
||||
</section>
|
||||
|
||||
<section id="resources-as-dependencies">
|
||||
<title><literal>Resources</literal> as dependencies</title>
|
||||
|
||||
<para>If the bean itself is going to determine and supply the resource
|
||||
path through some sort of dynamic process, it probably makes sense for the
|
||||
bean to use the <interfacename>ResourceLoader</interfacename> interface to
|
||||
load resources. Consider as an example the loading of a template of some
|
||||
sort, where the specific resource that is needed depends on the role of
|
||||
the user. If the resources are static, it makes sense to eliminate the use
|
||||
of the <interfacename>ResourceLoader</interfacename> interface completely,
|
||||
and just have the bean expose the <interfacename>Resource</interfacename>
|
||||
properties it needs, and expect that they will be injected into it.</para>
|
||||
|
||||
<para>What makes it trivial to then inject these properties, is that all
|
||||
application contexts register and use a special JavaBeans
|
||||
<interfacename>PropertyEditor</interfacename> which can convert
|
||||
<classname>String</classname> paths to
|
||||
<interfacename>Resource</interfacename> objects. So if
|
||||
<literal>myBean</literal> has a template property of type
|
||||
<interfacename>Resource</interfacename>, it can be configured with a
|
||||
simple string for that resource, as follows:</para>
|
||||
|
||||
<programlisting><![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><![CDATA[<property name="template" value="classpath:some/resource/path/myTemplate.txt">]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[<property name="template" value="file:/some/resource/path/myTemplate.txt"/>]]></programlisting>
|
||||
</section>
|
||||
|
||||
<section id="resources-app-ctx">
|
||||
<title>Application contexts and <interfacename>Resource</interfacename> paths</title>
|
||||
|
||||
<section id="resources-app-ctx-construction">
|
||||
<title>Constructing application contexts</title>
|
||||
|
||||
<para>An application context constructor (for a specific application
|
||||
context type) generally takes a string or array of strings as the
|
||||
location path(s) of the resource(s) such as XML files that make up the
|
||||
definition of the context.</para>
|
||||
|
||||
<para>When such a location path doesn't have a prefix, the specific
|
||||
<interfacename>Resource</interfacename> type built from that path and
|
||||
used to load the bean definitions, depends on and is appropriate to the
|
||||
specific application context. For example, if you create a
|
||||
<classname>ClassPathXmlApplicationContext</classname> as follows:</para>
|
||||
|
||||
<programlisting><![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><![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><![CDATA[ApplicationContext ctx =
|
||||
new FileSystemXmlApplicationContext("classpath:conf/appContext.xml");]]></programlisting>
|
||||
|
||||
<para>... will actually load its bean definitions from the classpath.
|
||||
However, it is still a <classname>FileSystemXmlApplicationContext</classname>. If it is
|
||||
subsequently used as a <interfacename>ResourceLoader</interfacename>,
|
||||
any unprefixed paths will still be treated as filesystem paths.</para>
|
||||
|
||||
<section id="resources-app-ctx-classpathxml">
|
||||
<title>Constructing <classname>ClassPathXmlApplicationContext</classname> instances - shortcuts</title>
|
||||
|
||||
<para>The <classname>ClassPathXmlApplicationContext</classname>
|
||||
exposes a number of constructors to enable convenient instantiation.
|
||||
The basic idea is that one supplies merely a string array containing
|
||||
just the filenames of the XML files themselves (without the leading
|
||||
path information), and one <emphasis>also</emphasis> supplies a
|
||||
<classname>Class</classname>; the
|
||||
<classname>ClassPathXmlApplicationContext</classname> will derive the
|
||||
path information from the supplied class.</para>
|
||||
|
||||
<para>An example will hopefully make this clear. Consider a directory
|
||||
layout that looks like this:</para>
|
||||
|
||||
<programlisting><![CDATA[com/
|
||||
foo/
|
||||
services.xml
|
||||
daos.xml
|
||||
MessengerService.class]]></programlisting>
|
||||
|
||||
<para>A <classname>ClassPathXmlApplicationContext</classname> instance
|
||||
composed of the beans defined in the <literal>'services.xml'</literal>
|
||||
and <literal>'daos.xml'</literal> could be instantiated like
|
||||
so...</para>
|
||||
|
||||
<programlisting><![CDATA[ApplicationContext ctx = new ClassPathXmlApplicationContext(
|
||||
new String[] {"services.xml", "daos.xml"}, MessengerService.class);]]></programlisting>
|
||||
|
||||
<para>Please do consult the Javadocs for the
|
||||
<classname>ClassPathXmlApplicationContext</classname> class for
|
||||
details of the various constructors.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="resources-app-ctx-wildcards-in-resource-paths">
|
||||
<title>Wildcards in application context constructor resource paths</title>
|
||||
|
||||
<para>The resource paths in application context constructor values may
|
||||
be a simple path (as shown above) which has a one-to-one mapping to a
|
||||
target Resource, or alternately may contain the special "classpath*:"
|
||||
prefix and/or internal Ant-style regular expressions (matched using
|
||||
Spring's <classname>PathMatcher</classname> utility). Both of the latter
|
||||
are effectively wildcards</para>
|
||||
|
||||
<para>One use for this mechanism is when doing component-style
|
||||
application assembly. All components can 'publish' context definition
|
||||
fragments to a well-known location path, and when the final application
|
||||
context is created using the same path prefixed via
|
||||
<literal>classpath*:</literal>, all component fragments will be picked
|
||||
up automatically.</para>
|
||||
|
||||
<para>Note that this wildcarding is specific to use of resource paths in
|
||||
application context constructors (or when using the
|
||||
<classname>PathMatcher</classname> utility class hierarchy directly),
|
||||
and is resolved at construction time. It has nothing to do with the
|
||||
<interfacename>Resource</interfacename> type itself. It's not possible
|
||||
to use the <literal>classpath*:</literal> prefix to construct an actual
|
||||
<interfacename>Resource</interfacename>, as a resource points to just
|
||||
one resource at a time.</para>
|
||||
|
||||
<section id="resources-app-ctx-ant-patterns-in-paths">
|
||||
<title>Ant-style Patterns</title>
|
||||
|
||||
<para>When the path location contains an Ant-style pattern, for example:</para>
|
||||
|
||||
<programlisting><![CDATA[ /WEB-INF/*-context.xml
|
||||
com/mycompany/**/applicationContext.xml
|
||||
file:C:/some/path/*-context.xml
|
||||
classpath:com/mycompany/**/applicationContext.xml]]></programlisting>
|
||||
|
||||
<para>... the resolver follows a more complex but defined procedure to
|
||||
try to resolve the wildcard. It produces a Resource for the path up to
|
||||
the last non-wildcard segment and obtains a URL from it. If this URL
|
||||
is not a "jar:" URL or container-specific variant (e.g.
|
||||
"<literal>zip:</literal>" in WebLogic, "<literal>wsjar</literal>" in
|
||||
WebSphere, etc.), then a <classname>java.io.File</classname> is
|
||||
obtained from it and used to resolve the wildcard by traversing the
|
||||
filesystem. In the case of a jar URL, the resolver either gets a
|
||||
<classname>java.net.JarURLConnection</classname> from it or manually
|
||||
parses the jar URL and then traverses the contents of the jar file
|
||||
to resolve the wildcards.</para>
|
||||
|
||||
<section id="resources-app-ctx-portability">
|
||||
<title>Implications on portability</title>
|
||||
|
||||
<para>If the specified path is already a file URL (either
|
||||
explicitly, or implicitly because the base
|
||||
<interfacename>ResourceLoader</interfacename> is a
|
||||
filesystem one, then wildcarding is guaranteed to work in a
|
||||
completely portable fashion.</para>
|
||||
|
||||
<para>If the specified path is a classpath location, then the
|
||||
resolver must obtain the last non-wildcard path segment URL via a
|
||||
<methodname>Classloader.getResource()</methodname> call. Since this
|
||||
is just a node of the path (not the file at the end) it is actually
|
||||
undefined (in the <classname>ClassLoader</classname> Javadocs)
|
||||
exactly what sort of a URL is returned in this case. In practice, it
|
||||
is always a <classname>java.io.File</classname> representing the
|
||||
directory, where the classpath resource resolves to a filesystem
|
||||
location, or a jar URL of some sort, where the classpath resource
|
||||
resolves to a jar location. Still, there is a portability concern on
|
||||
this operation.</para>
|
||||
|
||||
<para>If a jar URL is obtained for the last non-wildcard segment,
|
||||
the resolver must be able to get a
|
||||
<classname>java.net.JarURLConnection</classname> from it, or
|
||||
manually parse the jar URL, to be able to walk the contents of the
|
||||
jar, and resolve the wildcard. This will work in most environments,
|
||||
but will fail in others, and it is strongly recommended that the
|
||||
wildcard resolution of resources coming from jars be thoroughly
|
||||
tested in your specific environment before you rely on it.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="resources-classpath-wildcards">
|
||||
<title>The <literal>classpath*:</literal> prefix</title>
|
||||
|
||||
<para>When constructing an XML-based application context, a location
|
||||
string may use the special <literal>classpath*:</literal>
|
||||
prefix:</para>
|
||||
|
||||
<programlisting><![CDATA[ApplicationContext ctx =
|
||||
new ClassPathXmlApplicationContext("classpath*:conf/appContext.xml");]]></programlisting>
|
||||
|
||||
<para>This special prefix specifies that all classpath resources that
|
||||
match the given name must be obtained (internally, this essentially
|
||||
happens via a <methodname>ClassLoader.getResources(...)</methodname>
|
||||
call), and then merged to form the final application context
|
||||
definition.</para>
|
||||
|
||||
<note>
|
||||
<title>Classpath*: portability</title>
|
||||
|
||||
<para>The wildcard classpath relies on the <literal>getResources()</literal> method of the
|
||||
underlying classloader. As most application servers nowadays supply
|
||||
their own classloader implementation, the behavior might differ
|
||||
especially when dealing with jar files. A simple test to check if
|
||||
<literal>classpath*</literal> works is to use the classloader to load a file from
|
||||
within a jar on the classpath:
|
||||
<literal>getClass().getClassLoader().getResources("<someFileInsideTheJar>")</literal>.
|
||||
Try this test with files that have the same name but are placed
|
||||
inside two different locations. In case an inappropriate result is
|
||||
returned, check the application server documentation for settings
|
||||
that might affect the classloader behavior.</para>
|
||||
</note>
|
||||
|
||||
<para>The "<literal>classpath*:</literal>" prefix can also be combined
|
||||
with a <literal>PathMatcher</literal> pattern in the rest of the location path, for
|
||||
example "<literal>classpath*:META-INF/*-beans.xml</literal>". In this
|
||||
case, the resolution strategy is fairly simple: a
|
||||
ClassLoader.getResources() call is used on the last non-wildcard path
|
||||
segment to get all the matching resources in the class loader
|
||||
hierarchy, and then off each resource the same PathMatcher resoltion
|
||||
strategy described above is used for the wildcard subpath.</para>
|
||||
</section>
|
||||
|
||||
<section id="resources-wildcards-in-path-other-stuff">
|
||||
<title>Other notes relating to wildcards</title>
|
||||
|
||||
<para>Please note that "<literal>classpath*:</literal>" when
|
||||
combined with Ant-style patterns will only work reliably with at least
|
||||
one root directory before the pattern starts, unless the actual target
|
||||
files reside in the file system. This means that a pattern like
|
||||
"<literal>classpath*:*.xml</literal>" will not retrieve files from the
|
||||
root of jar files but rather only from the root of expanded
|
||||
directories. This originates from a limitation in the JDK's
|
||||
<methodname>ClassLoader.getResources()</methodname> method which only
|
||||
returns file system locations for a passed-in empty string (indicating
|
||||
potential roots to search).</para>
|
||||
|
||||
<para>Ant-style patterns with "<literal>classpath:</literal>"
|
||||
resources are not guaranteed to find matching resources if the root
|
||||
package to search is available in multiple class path locations. This
|
||||
is because a resource such as</para>
|
||||
|
||||
<programlisting><![CDATA[ com/mycompany/package1/service-context.xml]]></programlisting>
|
||||
|
||||
<para>may be in only one location, but when a path such as</para>
|
||||
|
||||
<programlisting><![CDATA[ classpath:com/mycompany/**/service-context.xml]]></programlisting>
|
||||
|
||||
<para>is used to try to resolve it, the resolver will work off the (first) URL
|
||||
returned by <methodname>getResource("com/mycompany")</methodname>;. If
|
||||
this base package node exists in multiple classloader locations, the
|
||||
actual end resource may not be underneath. Therefore, preferably, use
|
||||
"<literal>classpath*:</literal>" with the same Ant-style pattern in
|
||||
such a case, which will search all class path locations that contain
|
||||
the root package.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="resources-filesystemresource-caveats">
|
||||
<title><classname>FileSystemResource</classname> caveats</title>
|
||||
|
||||
<para>A <classname>FileSystemResource</classname> that is not attached
|
||||
to a <classname>FileSystemApplicationContext</classname> (that is, a
|
||||
<classname>FileSystemApplicationContext</classname> is not the actual
|
||||
<interfacename>ResourceLoader</interfacename>) will treat absolute vs.
|
||||
relative paths as you would expect. Relative paths are relative to the
|
||||
current working directory, while absolute paths are relative to the root
|
||||
of the filesystem.</para>
|
||||
|
||||
<para>For backwards compatibility (historical) reasons however, this
|
||||
changes when the <classname>FileSystemApplicationContext</classname> is
|
||||
the <literal>ResourceLoader</literal>. The
|
||||
<classname>FileSystemApplicationContext</classname> simply forces all
|
||||
attached <classname>FileSystemResource</classname> instances to treat
|
||||
all location paths as relative, whether they start with a leading slash
|
||||
or not. In practice, this means the following are equivalent:</para>
|
||||
|
||||
<programlisting><![CDATA[ApplicationContext ctx =
|
||||
new FileSystemXmlApplicationContext("conf/context.xml");]]></programlisting>
|
||||
|
||||
<programlisting><![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><![CDATA[FileSystemXmlApplicationContext ctx = ...;
|
||||
ctx.getResource("some/resource/path/myTemplate.txt");]]></programlisting>
|
||||
|
||||
<programlisting><![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><lineannotation>// actual context type doesn't matter, the <interfacename>Resource</interfacename> will always be <classname>UrlResource</classname></lineannotation><![CDATA[
|
||||
ctx.getResource("file:/some/resource/path/myTemplate.txt");]]></programlisting>
|
||||
|
||||
<programlisting><lineannotation>// force this FileSystemXmlApplicationContext to load its definition via a <classname>UrlResource</classname></lineannotation><![CDATA[
|
||||
ApplicationContext ctx =
|
||||
new FileSystemXmlApplicationContext("file:/conf/context.xml");]]></programlisting>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
||||
@@ -0,0 +1,499 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<chapter id="scheduling">
|
||||
<title>Scheduling and Thread Pooling</title>
|
||||
<section id="scheduling-introduction">
|
||||
<title>Introduction</title>
|
||||
<para>
|
||||
The Spring Framework features integration classes for scheduling support. Currently, Spring
|
||||
supports the <classname>Timer</classname>, part of the JDK since 1.3, and the
|
||||
Quartz Scheduler (<ulink url="http://www.opensymphony.com/quartz/"/>). Both 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).
|
||||
Spring also features classes for thread pooling that abstract
|
||||
away differences between Java SE 1.4, Java SE 5 and Java EE environments.
|
||||
</para>
|
||||
</section>
|
||||
<section id="scheduling-quartz">
|
||||
<title>Using the OpenSymphony 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
|
||||
<ulink url="http://www.opensymphony.com/quartz" />. For convenience purposes,
|
||||
Spring offers a couple of classes that simplify the usage of Quartz within
|
||||
Spring-based applications.
|
||||
</para>
|
||||
<section 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><![CDATA[
|
||||
<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><![CDATA[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><![CDATA[
|
||||
}
|
||||
}]]></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 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><![CDATA[<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><![CDATA[public class ExampleBusinessObject {
|
||||
|
||||
]]><lineannotation>// properties and collaborators</lineannotation><![CDATA[
|
||||
|
||||
public void doIt() {
|
||||
]]><lineannotation>// do the actual work</lineannotation><![CDATA[
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
<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><![CDATA[
|
||||
<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 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 to you 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. Spring offers two subclassed triggers with convenient defaults:
|
||||
<classname>CronTriggerBean</classname> and <classname>SimpleTriggerBean</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><![CDATA[<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
|
||||
<!-- 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.CronTriggerBean">
|
||||
<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><![CDATA[<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
|
||||
<ulink url="http://static.springframework.org/spring/docs/2.5.x/api/org/springframework/scheduling/quartz/SchedulerFactoryBean.html">SchedulerFactoryBean Javadoc</ulink>
|
||||
for more information.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
<section id="scheduling-jdk-timer">
|
||||
<title>Using JDK Timer support</title>
|
||||
<para>
|
||||
The other way to schedule jobs in Spring is to use JDK
|
||||
<classname>Timer</classname> objects. You can create custom timers or
|
||||
use the timer that invokes methods. Wiring timers is done using the
|
||||
<classname>TimerFactoryBean</classname>.
|
||||
</para>
|
||||
<section id="scheduling-jdk-timer-creating">
|
||||
<title>Creating custom timers</title>
|
||||
<para>
|
||||
Using the <classname>TimerTask</classname> you can create customer
|
||||
timer tasks, similar to Quartz jobs:
|
||||
</para>
|
||||
<programlisting><![CDATA[public class CheckEmailAddresses extends TimerTask {
|
||||
|
||||
private List emailAddresses;
|
||||
|
||||
public void setEmailAddresses(List emailAddresses) {
|
||||
this.emailAddresses = emailAddresses;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
]]><lineannotation>// iterate over all email addresses and archive them</lineannotation><![CDATA[
|
||||
}
|
||||
}]]></programlisting>
|
||||
<para>
|
||||
Wiring it up is simple:
|
||||
</para>
|
||||
<programlisting><![CDATA[<bean id="checkEmail" class="examples.CheckEmailAddress">
|
||||
<property name="emailAddresses">
|
||||
<list>
|
||||
<value>test@springframework.org</value>
|
||||
<value>foo@bar.com</value>
|
||||
<value>john@doe.net</value>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="scheduledTask" class="org.springframework.scheduling.timer.ScheduledTimerTask">
|
||||
]]><lineannotation><!-- wait 10 seconds before starting repeated execution --></lineannotation><![CDATA[
|
||||
<property name="delay" value="10000" />
|
||||
]]><lineannotation><!-- run every 50 seconds --></lineannotation><![CDATA[
|
||||
<property name="period" value="50000" />
|
||||
<property name="timerTask" ref="checkEmail" />
|
||||
</bean>]]></programlisting>
|
||||
<para>
|
||||
<emphasis>
|
||||
Note that letting the task only run once can be done by changing the
|
||||
<literal>period</literal> property to 0 (or a negative value).
|
||||
</emphasis>
|
||||
</para>
|
||||
</section>
|
||||
<section id="scheduling-jdk-timer-method-invoking-task">
|
||||
<title>Using the <classname>MethodInvokingTimerTaskFactoryBean</classname></title>
|
||||
<para>
|
||||
Similar to the Quartz support, the <classname>Timer</classname> support also features
|
||||
a component that allows you to periodically invoke a method:
|
||||
</para>
|
||||
<programlisting><![CDATA[<bean id="doIt" class="org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean">
|
||||
<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> (see below):
|
||||
</para>
|
||||
<programlisting><![CDATA[public class BusinessObject {
|
||||
|
||||
]]><lineannotation>// properties and collaborators</lineannotation><![CDATA[
|
||||
|
||||
public void doIt() {
|
||||
]]><lineannotation>// do the actual work</lineannotation><![CDATA[
|
||||
}
|
||||
}]]></programlisting>
|
||||
<para>Changing the <literal>timerTask</literal> reference of the
|
||||
<classname>ScheduledTimerTask</classname> example to the bean <literal>doIt</literal>
|
||||
will result in the <literal>doIt</literal> method being executed on a fixed schedule.</para>
|
||||
</section>
|
||||
<section id="scheduling-jdk-timer-factory-bean">
|
||||
<title>Wrapping up: setting up the tasks using the <classname>TimerFactoryBean</classname></title>
|
||||
<para>The <classname>TimerFactoryBean</classname> is similar to the Quartz
|
||||
<classname>SchedulerFactoryBean</classname> in that it serves the same
|
||||
purpose: setting up the actual scheduling. The <classname>TimerFactoryBean</classname>
|
||||
sets up an actual <classname>Timer</classname> and schedules the tasks it has
|
||||
references to. You can specify whether or not daemon threads should be used.</para>
|
||||
<programlisting><![CDATA[<bean id="timerFactory" class="org.springframework.scheduling.timer.TimerFactoryBean">
|
||||
<property name="scheduledTimerTasks">
|
||||
<list>
|
||||
]]><lineannotation><!-- see the example above --></lineannotation><![CDATA[
|
||||
<ref bean="scheduledTask" />
|
||||
</list>
|
||||
</property>
|
||||
</bean>]]></programlisting>
|
||||
</section>
|
||||
</section>
|
||||
<section 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>
|
||||
<title>The <interfacename>TaskExecutor</interfacename> interface</title>
|
||||
<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 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 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
|
||||
mutlithreading isn't necessary such as simple
|
||||
test cases.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem 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 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
|
||||
threadpool that may need to be shared by both
|
||||
Quartz and non-Quartz components.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem 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 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><![CDATA[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><![CDATA[<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>
|
||||
</chapter>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,346 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
|
||||
<!ENTITY preface SYSTEM "preface.xml">
|
||||
<!ENTITY overview SYSTEM "overview.xml">
|
||||
<!ENTITY whats-new-in-3 SYSTEM "new-in-3.xml">
|
||||
<!ENTITY beans SYSTEM "beans.xml">
|
||||
<!ENTITY resources SYSTEM "resources.xml">
|
||||
<!ENTITY validation SYSTEM "validation.xml">
|
||||
<!ENTITY aop SYSTEM "aop.xml">
|
||||
<!ENTITY aop-api SYSTEM "aop-api.xml">
|
||||
<!ENTITY transaction SYSTEM "transaction.xml">
|
||||
<!ENTITY metadata SYSTEM "metadata.xml">
|
||||
<!ENTITY dao SYSTEM "dao.xml">
|
||||
<!ENTITY jdbc SYSTEM "jdbc.xml">
|
||||
<!ENTITY orm SYSTEM "orm.xml">
|
||||
<!ENTITY mvc SYSTEM "mvc.xml">
|
||||
<!ENTITY view SYSTEM "view.xml">
|
||||
<!ENTITY web-integration SYSTEM "web-integration.xml">
|
||||
<!ENTITY portlet SYSTEM "portlet.xml">
|
||||
<!ENTITY remoting SYSTEM "remoting.xml">
|
||||
<!ENTITY ejb SYSTEM "ejb.xml">
|
||||
<!ENTITY jms SYSTEM "jms.xml">
|
||||
<!ENTITY jmx SYSTEM "jmx.xml">
|
||||
<!ENTITY cci SYSTEM "cci.xml">
|
||||
<!ENTITY mail SYSTEM "mail.xml">
|
||||
<!ENTITY scheduling SYSTEM "scheduling.xml">
|
||||
<!ENTITY testing SYSTEM "testing.xml">
|
||||
<!ENTITY dynamic-languages SYSTEM "dynamic-languages.xml">
|
||||
<!ENTITY xsd-configuration SYSTEM "xsd-configuration.xml">
|
||||
<!ENTITY xml-custom SYSTEM "xml-custom.xml">
|
||||
<!ENTITY dtd SYSTEM "dtd.xml">
|
||||
<!ENTITY spring-tld SYSTEM "spring.tld.xml">
|
||||
<!ENTITY spring-form-tld SYSTEM "spring-form.tld.xml">
|
||||
<!ENTITY swf-sidebar SYSTEM "swf-sidebar.xml">
|
||||
]>
|
||||
<book>
|
||||
<bookinfo>
|
||||
<title>Reference Documentation</title>
|
||||
<subtitle>(Work in progress)</subtitle>
|
||||
<productname>Spring Framework</productname>
|
||||
<releaseinfo>3.0.M3</releaseinfo>
|
||||
<mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata align="center" fileref="images/logo-pdf.png"
|
||||
format="PNG" width="240"/>
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
<authorgroup>
|
||||
<author>
|
||||
<firstname>Rod</firstname>
|
||||
<surname>Johnson</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Juergen</firstname>
|
||||
<surname>Hoeller</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Alef</firstname>
|
||||
<surname>Arendsen</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Colin</firstname>
|
||||
<surname>Sampaleanu</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Rob</firstname>
|
||||
<surname>Harrop</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Thomas</firstname>
|
||||
<surname>Risberg</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Darren</firstname>
|
||||
<surname>Davison</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Dmitriy</firstname>
|
||||
<surname>Kopylenko</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Mark</firstname>
|
||||
<surname>Pollack</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Thierry</firstname>
|
||||
<surname>Templier</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Erwin</firstname>
|
||||
<surname>Vervaet</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Portia</firstname>
|
||||
<surname>Tung</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Ben</firstname>
|
||||
<surname>Hale</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Adrian</firstname>
|
||||
<surname>Colyer</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>John</firstname>
|
||||
<surname>Lewis</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Costin</firstname>
|
||||
<surname>Leau</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Mark</firstname>
|
||||
<surname>Fisher</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Sam</firstname>
|
||||
<surname>Brannen</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Ramnivas</firstname>
|
||||
<surname>Laddad</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Arjen</firstname>
|
||||
<surname>Poutsma</surname>
|
||||
</author>
|
||||
</authorgroup>
|
||||
<copyright>
|
||||
<year>2004-2009</year>
|
||||
<holder>Rod Johnson, Juergen Hoeller, Alef Arendsen, Colin Sampaleanu, Rob Harrop, Thomas Risberg, Darren Davison,
|
||||
Dmitriy Kopylenko, Mark Pollack, Thierry Templier, Erwin Vervaet, Portia Tung, Ben Hale, Adrian Colyer, John Lewis, Costin Leau,
|
||||
Mark Fisher, Sam Brannen, Ramnivas Laddad, Arjen Poutsma
|
||||
</holder>
|
||||
</copyright>
|
||||
<legalnotice>
|
||||
<para>Copies of this document may be made for your own use and for
|
||||
distribution to others, provided that you do not charge any
|
||||
fee for such copies and further provided that each copy
|
||||
contains this Copyright Notice, whether distributed in print
|
||||
or electronically.</para>
|
||||
</legalnotice>
|
||||
</bookinfo>
|
||||
<!-- front matter -->
|
||||
<toc/>
|
||||
&preface;
|
||||
&overview;
|
||||
&whats-new-in-3;
|
||||
<part id="spring-core">
|
||||
<title>Core Technologies</title>
|
||||
<partintro id="spring-core-intro">
|
||||
<para>
|
||||
This initial 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 have 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 on 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="aop"/></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><xref linkend="aop-api"/></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><xref linkend="testing"/></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</partintro>
|
||||
&beans;
|
||||
&resources;
|
||||
&validation;
|
||||
&aop;
|
||||
&aop-api;
|
||||
&testing;
|
||||
</part>
|
||||
<part id="spring-middle-tier">
|
||||
<title>Middle Tier Data Access</title>
|
||||
<partintro id="spring-middle-tier-intro">
|
||||
<para>
|
||||
This part of the reference documentation is concerned
|
||||
with the middle tier, and specifically the data access
|
||||
responsibilities of said tier.
|
||||
</para>
|
||||
<para>
|
||||
Spring's comprehensive transaction management support is
|
||||
covered in some detail, followed by thorough coverage of
|
||||
the various middle tier 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>
|
||||
</itemizedlist>
|
||||
</partintro>
|
||||
&transaction;
|
||||
&dao;
|
||||
&jdbc;
|
||||
&orm;
|
||||
</part>
|
||||
<part id="spring-web">
|
||||
<title>The Web</title>
|
||||
<partintro id="spring-web-intro">
|
||||
<para>
|
||||
This part of the reference documentation covers the
|
||||
Spring Framework's support for the presentation tier
|
||||
(and specifically web-based presentation tiers).
|
||||
</para>
|
||||
<para>
|
||||
The Spring Framework's own web framework,
|
||||
<link linkend="mvc">Spring Web MVC</link>, is covered in
|
||||
the first couple of chapters. A number of the remaining
|
||||
chapters in this part of the reference documentation are
|
||||
concerned with the Spring Framework's integration with
|
||||
other web technologies, such as <link linkend="struts">Struts</link>
|
||||
and <link linkend="jsf">JSF</link> (to name but two).
|
||||
</para>
|
||||
<para>
|
||||
This section concludes with coverage of Spring's MVC
|
||||
<link linkend="portlet">portlet framework</link>.
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><xref linkend="mvc"/></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><xref linkend="view"/></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><xref linkend="web-integration"/></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><xref linkend="portlet"/></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</partintro>
|
||||
&mvc;
|
||||
&view;
|
||||
&web-integration;
|
||||
&portlet;
|
||||
</part>
|
||||
<part id="spring-integration">
|
||||
<title>Integration</title>
|
||||
<partintro id="spring-integration-intro">
|
||||
<para>
|
||||
This part of the reference documentation covers
|
||||
the Spring Framework's integration with a number of J2EE
|
||||
(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="metadata"/></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</partintro>
|
||||
&remoting;
|
||||
&ejb;
|
||||
&jms;
|
||||
&jmx;
|
||||
&cci;
|
||||
&mail;
|
||||
&scheduling;
|
||||
&dynamic-languages;
|
||||
&metadata;
|
||||
</part>
|
||||
<!-- back matter -->
|
||||
&xsd-configuration;
|
||||
&xml-custom;
|
||||
&dtd;
|
||||
&spring-tld;
|
||||
&spring-form-tld;
|
||||
</book>
|
||||
@@ -0,0 +1,737 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<appendix id="spring.tld">
|
||||
<title>spring.tld</title>
|
||||
<section id="spring.tld-intro">
|
||||
<title>Introduction</title>
|
||||
</section>
|
||||
<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 <ulink url="http://www.w3.org/TR/xhtml1/">XHTML-1.0-Strict specification</ulink> and attendant <ulink url="http://www.w3.org/TR/xhtml1/dtds.html#a_dtd_XHTML-1.0-Strict">DTD</ulink>.</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>
|
||||
</itemizedlist>
|
||||
<section 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 id="spring.tld.bind.table">
|
||||
<title>Attributes</title>
|
||||
<tgroup cols="3">
|
||||
<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 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 id="spring.tld.escapeBody.table">
|
||||
<title>Attributes</title>
|
||||
<tgroup cols="3">
|
||||
<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 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 id="spring.tld.hasBindErrors.table">
|
||||
<title>Attributes</title>
|
||||
<tgroup cols="3">
|
||||
<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 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 id="spring.tld.htmlEscape.table">
|
||||
<title>Attributes</title>
|
||||
<tgroup cols="3">
|
||||
<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 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 id="spring.tld.message.table">
|
||||
<title>Attributes</title>
|
||||
<tgroup cols="3">
|
||||
<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 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 id="spring.tld.nestedPath.table">
|
||||
<title>Attributes</title>
|
||||
<tgroup cols="3">
|
||||
<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 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 id="spring.tld.theme.table">
|
||||
<title>Attributes</title>
|
||||
<tgroup cols="3">
|
||||
<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 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 id="spring.tld.transform.table">
|
||||
<title>Attributes</title>
|
||||
<tgroup cols="3">
|
||||
<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>
|
||||
</appendix>
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<sidebar>
|
||||
<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
|
||||
<ulink url="http://www.springframework.org/webflow">Spring Web Flow website</ulink>.
|
||||
</para>
|
||||
</sidebar>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,749 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter id="validation">
|
||||
<title>Validation, Data-binding, the <interfacename>BeanWrapper</interfacename>, and <literal>PropertyEditors</literal></title>
|
||||
|
||||
<section id="validation-introduction">
|
||||
<title>Introduction</title>
|
||||
|
||||
<para>There are pros and cons for considering validation as business logic,
|
||||
and Spring offers a design for validation (and data binding) that
|
||||
does not exclude either one of them. Specifically validation should not be
|
||||
tied to the web tier, should be easy to localize and it should be
|
||||
possible to plug in any validator available. Considering the above, Spring
|
||||
has come up with a <interfacename>Validator</interfacename> interface that
|
||||
is both basic and eminently usable in every layer of an application.</para>
|
||||
|
||||
<para>Data binding is useful for allowing user input to be dynamically
|
||||
bound to the domain model of an application (or whatever objects you use
|
||||
to process user input). Spring provides the so-called
|
||||
<interfacename>DataBinder</interfacename> to do exactly that. The
|
||||
<interfacename>Validator</interfacename> and the
|
||||
<interfacename>DataBinder</interfacename> make up the <literal>validation</literal> package,
|
||||
which is primarily used in but not limited to the MVC framework.</para>
|
||||
|
||||
<para>The <interfacename>BeanWrapper</interfacename> is a fundamental concept in the
|
||||
Spring Framework and is used in a lot of places. However, you probably
|
||||
will not ever have the need to use the <interfacename>BeanWrapper</interfacename> directly. Because this
|
||||
is reference documentation however, we felt that some explanation might be
|
||||
in order. We're explaining the <interfacename>BeanWrapper</interfacename> in this chapter since if you were
|
||||
going to use it at all, you would probably do so when trying to bind
|
||||
data to objects, which is strongly related to the <interfacename>BeanWrapper</interfacename>.</para>
|
||||
|
||||
<para>Spring uses PropertyEditors all over the place. The concept of a
|
||||
<interfacename>PropertyEditor</interfacename> is part of the JavaBeans specification. Just as the
|
||||
<interfacename>BeanWrapper</interfacename>, it's best to explain the use of PropertyEditors in this
|
||||
chapter as well, since it's closely related to the <interfacename>BeanWrapper</interfacename> and the
|
||||
<interfacename>DataBinder</interfacename>.</para>
|
||||
</section>
|
||||
|
||||
<section id="validator">
|
||||
<title>Validation using Spring's <interfacename>Validator</interfacename> interface</title>
|
||||
<para>Spring's features a <interfacename>Validator</interfacename> interface that you can
|
||||
use to validate objects. The <interfacename>Validator</interfacename> interface works using
|
||||
an <interfacename>Errors</interfacename> object so that while validating, validators can report
|
||||
validation failures to the <interfacename>Errors</interfacename> object.</para>
|
||||
<para>Let's consider a small data object:</para>
|
||||
<programlisting><![CDATA[
|
||||
public class Person {
|
||||
|
||||
private String name;
|
||||
private int age;
|
||||
|
||||
]]><lineannotation>// the usual getters and setters...</lineannotation><![CDATA[
|
||||
}]]></programlisting>
|
||||
<para>We're going to provide validation behavior for the <classname>Person</classname>
|
||||
class by implementing the following two methods of the
|
||||
<interfacename>org.springframework.validation.Validator</interfacename> interface:
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para><methodname>supports(Class)</methodname> - Can this
|
||||
<interfacename>Validator</interfacename> validate instances of the supplied
|
||||
<classname>Class</classname>?</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><methodname>validate(Object, org.springframework.validation.Errors)</methodname> -
|
||||
validates the given object and in case of validation errors, registers
|
||||
those with the given <interfacename>Errors</interfacename> object</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<para>
|
||||
Implementing a <interfacename>Validator</interfacename> is fairly straightforward,
|
||||
especially when you know of the <classname>ValidationUtils</classname> helper class
|
||||
that the Spring Framework also provides.</para>
|
||||
<programlisting><![CDATA[public class PersonValidator implements Validator {
|
||||
|
||||
]]><lineannotation>/**
|
||||
* This <interfacename>Validator</interfacename> validates <emphasis role="bold">just</emphasis> <classname>Person</classname> instances
|
||||
*/</lineannotation><![CDATA[
|
||||
public boolean supports(Class clazz) {
|
||||
return Person.class.equals(clazz);
|
||||
}
|
||||
|
||||
public void validate(Object obj, Errors e) {
|
||||
ValidationUtils.rejectIfEmpty(e, "name", "name.empty");
|
||||
Person p = (Person) obj;
|
||||
if (p.getAge() < 0) {
|
||||
e.rejectValue("age", "negativevalue");
|
||||
} else if (p.getAge() > 110) {
|
||||
e.rejectValue("age", "too.darn.old");
|
||||
}
|
||||
}
|
||||
}]]></programlisting>
|
||||
<para>As you can see, the <literal>static</literal> <methodname>rejectIfEmpty(..)</methodname>
|
||||
method on the <classname>ValidationUtils</classname> class is used to reject the
|
||||
<literal>'name'</literal> property if it is <literal>null</literal> or the empty string.
|
||||
Have a look at the Javadoc for the <classname>ValidationUtils</classname> class to see
|
||||
what functionality it provides besides the example shown previously.</para>
|
||||
<para>While it is certainly possible to implement a single
|
||||
<interfacename>Validator</interfacename> class to validate each of the nested objects
|
||||
in a rich object, it may be better to encapsulate the validation logic for each nested
|
||||
class of object in its own <interfacename>Validator</interfacename> implementation. A
|
||||
simple example of a <emphasis>'rich'</emphasis> object would be a
|
||||
<classname>Customer</classname> that is composed of two <classname>String</classname>
|
||||
properties (a first and second name) and a complex <classname>Address</classname> object.
|
||||
<classname>Address</classname> objects may be used independently of
|
||||
<classname>Customer</classname> objects, and so a distinct
|
||||
<classname>AddressValidator</classname> has been implemented. If you want your
|
||||
<classname>CustomerValidator</classname> to reuse the logic contained within the
|
||||
<classname>AddressValidator</classname> class without recourse to copy-n-paste you can
|
||||
dependency-inject or instantiate an <classname>AddressValidator</classname> within your
|
||||
<classname>CustomerValidator</classname>, and use it like so:</para>
|
||||
<programlisting><![CDATA[public class CustomerValidator implements Validator {
|
||||
|
||||
private final Validator addressValidator;
|
||||
|
||||
public CustomerValidator(Validator addressValidator) {
|
||||
if (addressValidator == null) {
|
||||
throw new IllegalArgumentException("The supplied [Validator] is required and must not be null.");
|
||||
}
|
||||
if (!addressValidator.supports(Address.class)) {
|
||||
throw new IllegalArgumentException(
|
||||
"The supplied [Validator] must support the validation of [Address] instances.");
|
||||
}
|
||||
this.addressValidator = addressValidator;
|
||||
}
|
||||
|
||||
]]><lineannotation>/**
|
||||
* This <interfacename>Validator</interfacename> validates <classname>Customer</classname> instances, and any subclasses of <classname>Customer</classname> too
|
||||
*/</lineannotation><![CDATA[
|
||||
public boolean supports(Class clazz) {
|
||||
return Customer.class.isAssignableFrom(clazz);
|
||||
}
|
||||
|
||||
public void validate(Object target, Errors errors) {
|
||||
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "firstName", "field.required");
|
||||
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "surname", "field.required");
|
||||
Customer customer = (Customer) target;
|
||||
try {
|
||||
errors.pushNestedPath("address");
|
||||
ValidationUtils.invokeValidator(this.addressValidator, customer.getAddress(), errors);
|
||||
} finally {
|
||||
errors.popNestedPath();
|
||||
}
|
||||
}
|
||||
}]]></programlisting>
|
||||
<para>Validation errors are reported to the <interfacename>Errors</interfacename>
|
||||
object passed to the validator. In case of Spring Web MVC you can use
|
||||
<literal><spring:bind/></literal> tag to inspect the error messages, but
|
||||
of course you can also inspect the errors object yourself. More information about
|
||||
the methods it offers can be found from the Javadoc.</para>
|
||||
</section>
|
||||
<section id="validation-conversion">
|
||||
<title>Resolving codes to error messages</title>
|
||||
<para>We've talked about databinding and validation. Outputting messages corresponding to
|
||||
validation errors is the last thing we need to discuss. In the example we've shown
|
||||
above, we rejected the <literal>name</literal> and the <literal>age</literal> field.
|
||||
If we're going to output the error messages by using a <interfacename>MessageSource</interfacename>,
|
||||
we will do so using the error code we've given when rejecting the field ('name' and 'age'
|
||||
in this case). When you call (either directly, or indirectly, using for example the
|
||||
<classname>ValidationUtils</classname> class) <literal>rejectValue</literal> or one of
|
||||
the other <literal>reject</literal> methods from the <interfacename>Errors</interfacename>
|
||||
interface, the underlying implementation will not only register the code you've
|
||||
passed in, but also a number of additional error codes. What error codes it registers
|
||||
is determined by the <interfacename>MessageCodesResolver</interfacename> that is used.
|
||||
By default, the <classname>DefaultMessageCodesResolver</classname> is used, which for example
|
||||
not only registers a message with the code you gave, but also messages that include the
|
||||
field name you passed to the reject method. So in case you reject a field using
|
||||
<literal>rejectValue("age", "too.darn.old")</literal>, apart from the
|
||||
<literal>too.darn.old</literal> code, Spring will also register
|
||||
<literal>too.darn.old.age</literal> and <literal>too.darn.old.age.int</literal>
|
||||
(so the first will include the field name and the second will include the type of the
|
||||
field); this is done as a convenience to aid developers in targeting error
|
||||
messages and suchlike.</para>
|
||||
<para>More information on the <interfacename>MessageCodesResolver</interfacename> and the default
|
||||
strategy can be found online with the Javadocs for
|
||||
<ulink url="http://static.springframework.org/spring/docs/2.5.x/api/org/springframework/validation/MessageCodesResolver.html">MessageCodesResolver</ulink>
|
||||
and
|
||||
<ulink url="http://static.springframework.org/spring/docs/2.5.x/api/org/springframework/validation/DefaultMessageCodesResolver.html">DefaultMessageCodesResolver</ulink>
|
||||
respectively.</para>
|
||||
</section>
|
||||
|
||||
<section id="beans-beans">
|
||||
<title>Bean manipulation and the <interfacename>BeanWrapper</interfacename></title>
|
||||
|
||||
<para>The <literal>org.springframework.beans</literal> package adheres to
|
||||
the JavaBeans standard provided by Sun. A JavaBean is simply a class with
|
||||
a default no-argument constructor, which follows a naming convention
|
||||
where (by way of an example) a property named <literal>bingoMadness</literal> would have a setter
|
||||
method <methodname>setBingoMadness(..)</methodname> and a getter method <methodname>getBingoMadness()</methodname>.
|
||||
For more information about JavaBeans and the specification, please refer
|
||||
to Sun's website ( <ulink url="http://java.sun.com/products/javabeans/">java.sun.com/products/javabeans</ulink>).</para>
|
||||
|
||||
<para>One quite important class in the beans package is the
|
||||
<interfacename>BeanWrapper</interfacename> interface and its corresponding
|
||||
implementation (<classname>BeanWrapperImpl</classname>). As quoted from the
|
||||
Javadoc, the <interfacename>BeanWrapper</interfacename> offers functionality to set and get property
|
||||
values (individually or in bulk), get property descriptors, and to query
|
||||
properties to determine if they are readable or writable. Also, the
|
||||
<interfacename>BeanWrapper</interfacename> offers support for nested properties, enabling the setting of
|
||||
properties on sub-properties to an unlimited depth. Then, the <interfacename>BeanWrapper</interfacename>
|
||||
supports the ability to add standard JavaBeans
|
||||
<interfacename>PropertyChangeListeners</interfacename> and
|
||||
<interfacename>VetoableChangeListeners</interfacename>, without the need for
|
||||
supporting code in the target class. Last but not least, the <interfacename>BeanWrapper</interfacename>
|
||||
provides support for the setting of indexed properties. The <interfacename>BeanWrapper</interfacename>
|
||||
usually isn't used by application code directly, but by the
|
||||
<interfacename>DataBinder</interfacename> and the
|
||||
<interfacename>BeanFactory</interfacename>.</para>
|
||||
|
||||
<para>The way the <interfacename>BeanWrapper</interfacename> works is partly indicated by its name:
|
||||
<emphasis>it wraps a bean</emphasis> to perform actions on that bean, like
|
||||
setting and retrieving properties.</para>
|
||||
|
||||
<section id="beans-beans-conventions">
|
||||
<title>Setting and getting basic and nested properties</title>
|
||||
|
||||
<para>Setting and getting properties is done using the
|
||||
<literal>setPropertyValue(s)</literal> and
|
||||
<literal>getPropertyValue(s)</literal> methods that both come with a
|
||||
couple of overloaded variants. They're all described in more detail in
|
||||
the Javadoc Spring comes with. What's important to know is that there
|
||||
are a couple of conventions for indicating properties of an object. A
|
||||
couple of examples:</para>
|
||||
<table id="beans-beans-conventions-properties-tbl">
|
||||
<title>Examples of properties</title>
|
||||
|
||||
<tgroup cols="2">
|
||||
<colspec colname="c1" colwidth="1*" />
|
||||
<colspec colname="c2" colwidth="3*" />
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Expression</entry>
|
||||
<entry>Explanation</entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><literal>name</literal></entry>
|
||||
|
||||
<entry>Indicates the property <literal>name</literal>
|
||||
corresponding to the methods <methodname>getName()</methodname> or
|
||||
<methodname>isName()</methodname> and
|
||||
<methodname>setName(..)</methodname></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><literal>account.name</literal></entry>
|
||||
|
||||
<entry>Indicates the nested property <literal>name</literal>
|
||||
of the property <literal>account</literal> corresponding e.g.
|
||||
to the methods <literal>getAccount().setName()</literal> or
|
||||
<literal>getAccount().getName()</literal></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><literal>account[2]</literal></entry>
|
||||
|
||||
<entry>Indicates the <emphasis>third</emphasis> element of the
|
||||
indexed property <literal>account</literal>. Indexed
|
||||
properties can be of type <literal>array</literal>,
|
||||
<literal>list</literal> or other <emphasis>naturally
|
||||
ordered</emphasis> collection</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><literal>account[COMPANYNAME]</literal></entry>
|
||||
|
||||
<entry>Indicates the value of the map entry indexed by the key
|
||||
<emphasis>COMPANYNAME</emphasis> of the Map property
|
||||
<literal>account</literal></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<para>Below you'll find some examples of working with the <interfacename>BeanWrapper</interfacename> to
|
||||
get and set properties.</para>
|
||||
|
||||
<para><emphasis>(This next section is not vitally important to you if you're not
|
||||
planning to work with the <interfacename>BeanWrapper</interfacename> directly. If you're
|
||||
just using the <interfacename>DataBinder</interfacename> and the
|
||||
<interfacename>BeanFactory</interfacename> and their out-of-the-box implementation, you
|
||||
should skip ahead to the section about
|
||||
<interfacename>PropertyEditors</interfacename>.)</emphasis></para>
|
||||
|
||||
<para>Consider the following two classes:</para>
|
||||
<programlisting><![CDATA[public class Company {
|
||||
private String name;
|
||||
private Employee managingDirector;
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
public Employee getManagingDirector() {
|
||||
return this.managingDirector;
|
||||
}
|
||||
public void setManagingDirector(Employee managingDirector) {
|
||||
this.managingDirector = managingDirector;
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[public class Employee {
|
||||
private String name;
|
||||
private float salary;
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
public float getSalary() {
|
||||
return salary;
|
||||
}
|
||||
public void setSalary(float salary) {
|
||||
this.salary = salary;
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
<para>The following code snippets show some examples of how to retrieve
|
||||
and manipulate some of the properties of instantiated
|
||||
<literal>Companies</literal> and <literal>Employees</literal>:</para>
|
||||
<programlisting><![CDATA[BeanWrapper company = BeanWrapperImpl(new Company());
|
||||
]]><lineannotation>// setting the company name..</lineannotation><![CDATA[
|
||||
company.setPropertyValue("name", "Some Company Inc.");
|
||||
]]><lineannotation>// ... can also be done like this:</lineannotation><![CDATA[
|
||||
PropertyValue value = new PropertyValue("name", "Some Company Inc.");
|
||||
company.setPropertyValue(value);
|
||||
|
||||
]]><lineannotation>// ok, let's create the director and tie it to the company:</lineannotation><![CDATA[
|
||||
BeanWrapper jim = BeanWrapperImpl(new Employee());
|
||||
jim.setPropertyValue("name", "Jim Stravinsky");
|
||||
company.setPropertyValue("managingDirector", jim.getWrappedInstance());
|
||||
|
||||
]]><lineannotation>// retrieving the salary of the managingDirector through the company</lineannotation><![CDATA[
|
||||
Float salary = (Float) company.getPropertyValue("managingDirector.salary");]]></programlisting>
|
||||
</section>
|
||||
|
||||
<section id="beans-beans-conversion">
|
||||
<title>Built-in <interface>PropertyEditor</interface> implementations</title>
|
||||
|
||||
<para>Spring heavily uses the concept of <literal>PropertyEditors</literal> to effect the conversion
|
||||
between an <classname>Object</classname> and a <classname>String</classname>. If you think about it,
|
||||
it sometimes might be handy to be able to represent properties in a different way than the object itself.
|
||||
For example, a <classname>Date</classname> can be represented in a human readable way (as the
|
||||
<classname>String</classname> '<literal>2007-14-09</literal>'), while we're still able to convert the
|
||||
human readable form back to the original date (or even better: convert any date entered in a human readable
|
||||
form, back to <classname>Date</classname> objects). This behavior can be achieved by
|
||||
<emphasis>registering custom editors</emphasis>, of type <interfacename>java.beans.PropertyEditor</interfacename>.
|
||||
Registering custom editors on a <interfacename>BeanWrapper</interfacename> or alternately in a specific IoC
|
||||
container as mentioned in the previous chapter, gives it the knowledge of how to convert properties to the
|
||||
desired type. Read more about <interfacename>PropertyEditors</interfacename> in the Javadoc of the
|
||||
<literal>java.beans</literal> package provided by Sun.</para>
|
||||
|
||||
<para>A couple of examples where property editing is used in Spring:
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para><emphasis>setting properties on beans</emphasis> is done
|
||||
using <literal>PropertyEditors</literal>. When mentioning
|
||||
<literal>java.lang.String</literal> as the value of a property of
|
||||
some bean you're declaring in XML file, Spring will (if the setter
|
||||
of the corresponding property has a <classname>Class</classname>-parameter) use the
|
||||
<classname>ClassEditor</classname> to try to resolve the parameter to
|
||||
a <classname>Class</classname> object.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><emphasis>parsing HTTP request parameters</emphasis> in
|
||||
Spring's MVC framework is done using all kinds of <literal>PropertyEditors</literal>
|
||||
that you can manually bind in all subclasses of the
|
||||
<classname>CommandController</classname>.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>Spring has a number of built-in <literal>PropertyEditors</literal> to make life easy.
|
||||
Each of those is listed below and they are all located in the
|
||||
<literal>org.springframework.beans.propertyeditors</literal> package. Most, but not all (as indicated below),
|
||||
are registered by default by <classname>BeanWrapperImpl</classname>. Where the property editor is configurable
|
||||
in some fashion, you can of course still register your own variant to override the default one:</para>
|
||||
|
||||
<table id="beans-beans-property-editors-tbl">
|
||||
<title>Built-in <literal>PropertyEditors</literal></title>
|
||||
|
||||
<tgroup cols="2">
|
||||
<colspec colname="c1" colwidth="3*" />
|
||||
<colspec colname="c2" colwidth="5*" />
|
||||
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Class</entry>
|
||||
<entry>Explanation</entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><classname>ByteArrayPropertyEditor</classname></entry>
|
||||
|
||||
<entry>Editor for byte arrays. Strings will simply be
|
||||
converted to their corresponding byte representations.
|
||||
Registered by default by <classname>BeanWrapperImpl</classname>.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><classname>ClassEditor</classname></entry>
|
||||
|
||||
<entry>Parses Strings representing classes to actual classes
|
||||
and the other way around. When a class is not found, an
|
||||
<classname>IllegalArgumentException</classname> is thrown. Registered by default by
|
||||
<classname>BeanWrapperImpl</classname>.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><classname>CustomBooleanEditor</classname></entry>
|
||||
|
||||
<entry>Customizable property editor for <classname>Boolean</classname> properties.
|
||||
Registered by default by <classname>BeanWrapperImpl</classname>, but, can be
|
||||
overridden by registering custom instance of it as custom
|
||||
editor.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><classname>CustomCollectionEditor</classname></entry>
|
||||
<entry>Property editor for Collections, converting any source
|
||||
<interfacename>Collection</interfacename> to a given target <interfacename>Collection</interfacename> type.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><classname>CustomDateEditor</classname></entry>
|
||||
|
||||
<entry>Customizable property editor for java.util.Date,
|
||||
supporting a custom DateFormat. NOT registered by default. Must
|
||||
be user registered as needed with appropriate format.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><classname>CustomNumberEditor</classname></entry>
|
||||
|
||||
<entry>Customizable property editor for any Number subclass
|
||||
like <classname>Integer</classname>, <classname>Long</classname>,
|
||||
<classname>Float</classname>, <classname>Double</classname>. Registered
|
||||
by default by <classname>BeanWrapperImpl</classname>, but can be
|
||||
overridden by registering custom instance of it as a custom editor.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><classname>FileEditor</classname></entry>
|
||||
|
||||
<entry>Capable of resolving Strings to
|
||||
<classname>java.io.File</classname> objects. Registered by default by
|
||||
<classname>BeanWrapperImpl</classname>. </entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><classname>InputStreamEditor</classname></entry>
|
||||
|
||||
<entry>One-way property editor, capable of taking a text
|
||||
string and producing (via an intermediate <classname>ResourceEditor</classname> and
|
||||
<interfacename>Resource</interfacename>) an
|
||||
<interfacename>InputStream</interfacename>, so <interfacename>InputStream</interfacename>
|
||||
properties may be directly set as Strings. Note that the default usage
|
||||
will not close the <interfacename>InputStream</interfacename> for
|
||||
you! Registered by default by <classname>BeanWrapperImpl</classname>.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><classname>LocaleEditor</classname></entry>
|
||||
|
||||
<entry>Capable of resolving Strings to
|
||||
<classname>Locale</classname> objects and vice versa (the String
|
||||
format is [language]_[country]_[variant], which is the same
|
||||
thing the toString() method of Locale provides). Registered by
|
||||
default by <classname>BeanWrapperImpl</classname>.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><classname>PatternEditor</classname></entry>
|
||||
|
||||
<entry>Capable of resolving Strings to JDK 1.5
|
||||
<classname>Pattern</classname> objects and vice versa.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><classname>PropertiesEditor</classname></entry>
|
||||
|
||||
<entry>Capable of converting Strings (formatted using the
|
||||
format as defined in the Javadoc for the java.lang.Properties
|
||||
class) to <classname>Properties</classname> objects. Registered by
|
||||
default by <classname>BeanWrapperImpl</classname>.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><classname>StringTrimmerEditor</classname></entry>
|
||||
|
||||
<entry>Property editor that trims Strings. Optionally allows
|
||||
transforming an empty string into a <literal>null</literal> value. NOT
|
||||
registered by default; must be user registered as needed.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><classname>URLEditor</classname></entry>
|
||||
|
||||
<entry>Capable of resolving a String representation of a URL
|
||||
to an actual <classname>URL</classname> object. Registered by
|
||||
default by <classname>BeanWrapperImpl</classname>.</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<para>
|
||||
Spring uses the <interfacename>java.beans.PropertyEditorManager</interfacename> to set
|
||||
the search path for property editors that might be needed. The search path also includes
|
||||
<literal>sun.bean.editors</literal>, which includes
|
||||
<interfacename>PropertyEditor</interfacename> implementations for types such as
|
||||
<classname>Font</classname>, <classname>Color</classname>, and most of the primitive types.
|
||||
Note also that the standard JavaBeans infrastructure will automatically discover
|
||||
<interfacename>PropertyEditor</interfacename> classes (without you having to register them
|
||||
explicitly) if they are in the same package as the class they handle, and have the same name
|
||||
as that class, with <literal>'Editor'</literal> appended; for example, one could have the
|
||||
following class and package structure, which would be sufficient for the
|
||||
<classname>FooEditor</classname> class to be recognized and used as the
|
||||
<interfacename>PropertyEditor</interfacename> for <classname>Foo</classname>-typed
|
||||
properties.
|
||||
</para>
|
||||
<programlisting><![CDATA[com
|
||||
chank
|
||||
pop
|
||||
Foo
|
||||
FooEditor ]]><lineannotation>// the <interfacename>PropertyEditor</interfacename> for the <classname>Foo</classname> class</lineannotation></programlisting>
|
||||
<para>Note that you can also use the standard <interfacename>BeanInfo</interfacename> JavaBeans
|
||||
mechanism here as well (described
|
||||
<ulink url="http://java.sun.com/docs/books/tutorial/javabeans/customization/index.html">in not-amazing-detail here</ulink>).
|
||||
Find below an example of using the <interfacename>BeanInfo</interfacename> mechanism for
|
||||
explicitly registering one or more <interfacename>PropertyEditor</interfacename> instances
|
||||
with the properties of an associated class.</para>
|
||||
<programlisting><![CDATA[com
|
||||
chank
|
||||
pop
|
||||
Foo
|
||||
FooBeanInfo ]]><lineannotation>// the <interfacename>BeanInfo</interfacename> for the <classname>Foo</classname> class</lineannotation></programlisting>
|
||||
<para>
|
||||
Here is the Java source code for the referenced <classname>FooBeanInfo</classname> class. This
|
||||
would associate a <classname>CustomNumberEditor</classname> with the <literal>age</literal>
|
||||
property of the <classname>Foo</classname> class.
|
||||
</para>
|
||||
<programlisting><![CDATA[public class FooBeanInfo extends SimpleBeanInfo {
|
||||
|
||||
public PropertyDescriptor[] getPropertyDescriptors() {
|
||||
try {
|
||||
final PropertyEditor numberPE = new CustomNumberEditor(Integer.class, true);
|
||||
PropertyDescriptor ageDescriptor = new PropertyDescriptor("age", Foo.class) {
|
||||
public PropertyEditor createPropertyEditor(Object bean) {
|
||||
return numberPE;
|
||||
};
|
||||
};
|
||||
return new PropertyDescriptor[] { ageDescriptor };
|
||||
}
|
||||
catch (IntrospectionException ex) {
|
||||
throw new Error(ex.toString());
|
||||
}
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
|
||||
<section id="beans-beans-conversion-customeditor-registration">
|
||||
<title>Registering additional custom <interfacename>PropertyEditors</interfacename></title>
|
||||
|
||||
<para>When setting bean properties as a string value, a Spring IoC container
|
||||
ultimately uses standard JavaBeans <literal>PropertyEditors</literal> to convert these
|
||||
Strings to the complex type of the property. Spring pre-registers a number
|
||||
of custom <literal>PropertyEditors</literal> (for example, to convert a classname expressed
|
||||
as a string into a real <classname>Class</classname> object). Additionally, Java's standard
|
||||
JavaBeans <interfacename>PropertyEditor</interfacename> lookup mechanism allows a
|
||||
<classname>PropertyEditor</classname> for a class simply to be named appropriately and
|
||||
placed in the same package as the class it provides support for, to be found automatically.</para>
|
||||
<para>If there is a need to register other custom <literal>PropertyEditors</literal>, there
|
||||
are several mechanisms available. The most manual approach, which is not normally convenient or
|
||||
recommended, is to simply use the <methodname>registerCustomEditor()</methodname> method of the
|
||||
<interfacename>ConfigurableBeanFactory</interfacename> interface, assuming you have a
|
||||
<interfacename>BeanFactory</interfacename> reference. Another, slightly more convenient, mechanism is to use
|
||||
a special bean factory post-processor called <classname>CustomEditorConfigurer</classname>.
|
||||
Although bean factory post-processors can be used with <interfacename>BeanFactory</interfacename>
|
||||
implementations, the <classname>CustomEditorConfigurer</classname> has a nested property setup, so it is
|
||||
strongly recommended that it is used with the <interfacename>ApplicationContext</interfacename>, where
|
||||
it may be deployed in similar fashion to any other bean, and automatically detected and applied.</para>
|
||||
<para>Note that all bean factories and application contexts automatically use a number of built-in property
|
||||
editors, through their use of something called a <interfacename>BeanWrapper</interfacename> to handle
|
||||
property conversions. The standard property editors that the <interfacename>BeanWrapper</interfacename>
|
||||
registers are listed in <link linkend="beans-beans-conversion">the previous section</link>. Additionally,
|
||||
<literal>ApplicationContexts</literal> also override or add an additional number of editors
|
||||
to handle resource lookups in a manner appropriate to the specific application context type.</para>
|
||||
|
||||
<para>Standard JavaBeans <interfacename>PropertyEditor</interfacename> instances are used to convert
|
||||
property values expressed as strings to the actual complex type of the property.
|
||||
<classname>CustomEditorConfigurer</classname>, a bean factory post-processor, may be used to conveniently
|
||||
add support for additional <interfacename>PropertyEditor</interfacename> instances to an
|
||||
<interfacename>ApplicationContext</interfacename>.</para>
|
||||
<para>Consider a user class <classname>ExoticType</classname>, and another class
|
||||
<classname>DependsOnExoticType</classname> which needs <classname>ExoticType</classname> set as a property:</para>
|
||||
|
||||
<programlisting><![CDATA[package example;
|
||||
|
||||
public class ExoticType {
|
||||
|
||||
private String name;
|
||||
|
||||
public ExoticType(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
public class DependsOnExoticType {
|
||||
|
||||
private ExoticType type;
|
||||
|
||||
public void setType(ExoticType type) {
|
||||
this.type = type;
|
||||
}
|
||||
}]]></programlisting>
|
||||
<para>When things are properly set up, we want to be able to assign the type property as a string, which a
|
||||
<interfacename>PropertyEditor</interfacename> will behind the scenes convert into an actual
|
||||
<classname>ExoticType</classname> instance:</para>
|
||||
<programlisting><![CDATA[<bean id="sample" class="example.DependsOnExoticType">
|
||||
<property name="type" value="aNameForExoticType"/>
|
||||
</bean>]]></programlisting>
|
||||
<para>The <interfacename>PropertyEditor</interfacename> implementation could look similar to this:</para>
|
||||
<programlisting><lineannotation>// converts string representation to <classname>ExoticType</classname> object</lineannotation><![CDATA[
|
||||
package example;
|
||||
|
||||
public class ExoticTypeEditor extends PropertyEditorSupport {
|
||||
|
||||
private String format;
|
||||
|
||||
public void setFormat(String format) {
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
public void setAsText(String text) {
|
||||
if (format != null && format.equals("upperCase")) {
|
||||
text = text.toUpperCase();
|
||||
}
|
||||
ExoticType type = new ExoticType(text);
|
||||
setValue(type);
|
||||
}
|
||||
}]]></programlisting>
|
||||
<para>Finally, we use <classname>CustomEditorConfigurer</classname> to register the new
|
||||
<interfacename>PropertyEditor</interfacename> with the <interfacename>ApplicationContext</interfacename>,
|
||||
which will then be able to use it as needed:</para>
|
||||
<programlisting><![CDATA[<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
|
||||
<property name="customEditors">
|
||||
<map>
|
||||
<entry key="example.ExoticType">
|
||||
<bean class="example.ExoticTypeEditor">
|
||||
<property name="format" value="upperCase"/>
|
||||
</bean>
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
</bean>]]></programlisting>
|
||||
|
||||
<section id="beans-beans-conversion-customeditor-registration-per">
|
||||
<title>Using <interfacename>PropertyEditorRegistrars</interfacename></title>
|
||||
|
||||
<para>Another mechanism for registering property editors with the Spring container is to create and use
|
||||
a <interfacename>PropertyEditorRegistrar</interfacename>. This interface is particularly useful when you
|
||||
need to use the same set of property editors in several different situations: write a corresponding
|
||||
registrar and reuse that in each case. <literal>PropertyEditorRegistrars</literal> work in conjunction
|
||||
with an interface called <interfacename>PropertyEditorRegistry</interfacename>, an interface
|
||||
that is implemented by the Spring <interfacename>BeanWrapper</interfacename> (and
|
||||
<interfacename>DataBinder</interfacename>). <literal>PropertyEditorRegistrars</literal> are particularly
|
||||
convenient when used in conjunction with the <classname>CustomEditorConfigurer</classname>
|
||||
(introduced <link linkend="beans-beans-conversion-customeditor-registration">here</link>), which exposes a
|
||||
property called <methodname>setPropertyEditorRegistrars(..)</methodname>:
|
||||
<literal>PropertyEditorRegistrars</literal> added to a <classname>CustomEditorConfigurer</classname> in this
|
||||
fashion can easily be shared with <interfacename>DataBinder</interfacename> and Spring MVC
|
||||
<interfacename>Controllers</interfacename>. Furthermore, it avoids the need for synchronization on custom
|
||||
editors: a <interfacename>PropertyEditorRegistrar</interfacename> is expected to create fresh
|
||||
<interfacename>PropertyEditor</interfacename> instances for each bean creation attempt.</para>
|
||||
<para>Using a <interfacename>PropertyEditorRegistrar</interfacename> is perhaps best illustrated with an
|
||||
example. First off, you need to create your own <interfacename>PropertyEditorRegistrar</interfacename>
|
||||
implementation:</para>
|
||||
|
||||
<programlisting><![CDATA[package com.foo.editors.spring;
|
||||
|
||||
public final class CustomPropertyEditorRegistrar implements PropertyEditorRegistrar {
|
||||
|
||||
public void registerCustomEditors(PropertyEditorRegistry registry) {
|
||||
|
||||
]]><lineannotation>// it is expected that new <interfacename>PropertyEditor</interfacename> instances are created</lineannotation><![CDATA[
|
||||
registry.registerCustomEditor(ExoticType.class, new ExoticTypeEditor());
|
||||
|
||||
]]><lineannotation>// you could register as many custom property editors as are required here...</lineannotation><![CDATA[
|
||||
}
|
||||
}]]></programlisting>
|
||||
<para>See also the <classname>org.springframework.beans.support.ResourceEditorRegistrar</classname> for an
|
||||
example <interfacename>PropertyEditorRegistrar</interfacename> implementation. Notice how in its
|
||||
implementation of the <methodname>registerCustomEditors(..)</methodname> method it creates new instances
|
||||
of each property editor.</para>
|
||||
<para>Next we configure a <classname>CustomEditorConfigurer</classname> and inject an
|
||||
instance of our <classname>CustomPropertyEditorRegistrar</classname> into it:</para>
|
||||
<programlisting><![CDATA[<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
|
||||
<property name="propertyEditorRegistrars">
|
||||
<list>
|
||||
<ref bean="customPropertyEditorRegistrar"/>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="customPropertyEditorRegistrar" class="com.foo.editors.spring.CustomPropertyEditorRegistrar"/>]]></programlisting>
|
||||
|
||||
<para>Finally, and in a bit of a departure from the focus of this chapter, for those of you using
|
||||
<link linkend="mvc">Spring's MVC web framework</link>, using <interfacename>PropertyEditorRegistrars</interfacename>
|
||||
in conjunction with data-binding <interfacename>Controllers</interfacename> (such as
|
||||
<classname>SimpleFormController</classname>) can be very convenient. Find below an example of using a
|
||||
<interfacename>PropertyEditorRegistrar</interfacename> in the implementation of an <methodname>initBinder(..)</methodname>
|
||||
method:</para>
|
||||
|
||||
<programlisting><![CDATA[public final class RegisterUserController extends SimpleFormController {
|
||||
|
||||
private final PropertyEditorRegistrar customPropertyEditorRegistrar;
|
||||
|
||||
public RegisterUserController(PropertyEditorRegistrar propertyEditorRegistrar) {
|
||||
this.customPropertyEditorRegistrar = propertyEditorRegistrar;
|
||||
}
|
||||
|
||||
protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
|
||||
]]><emphasis role="bold">this.customPropertyEditorRegistrar.registerCustomEditors(binder);</emphasis><![CDATA[
|
||||
}
|
||||
|
||||
]]><lineannotation>// other methods to do with registering a <classname>User</classname></lineannotation><![CDATA[
|
||||
}]]></programlisting>
|
||||
|
||||
<para>This style of <interfacename>PropertyEditor</interfacename> registration can lead to concise code (the
|
||||
implementation of <methodname>initBinder(..)</methodname> is just one line long!), and allows common
|
||||
<interfacename>PropertyEditor</interfacename> registration code to be encapsulated in a class and then
|
||||
shared amongst as many <interfacename>Controllers</interfacename> as needed.</para>
|
||||
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
</section>
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,597 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<appendix id="extensible-xml">
|
||||
<title>Extensible XML authoring</title>
|
||||
<section 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><![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 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><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><![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><![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 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><![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 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><![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 id="extensible-xml-parser-simpledateformat-co-1"/><![CDATA[
|
||||
|
||||
protected Class getBeanClass(Element element) {
|
||||
return SimpleDateFormat.class; ]]><co 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 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
|
||||
infrastructurewill automatically pick up your new extension by consuming these special
|
||||
properties files, the formats of which are detailed below.</para>
|
||||
<section 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 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 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><![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-2.5.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 id="extensible-xml-meat">
|
||||
<title>Meatier examples</title>
|
||||
<para>Find below some much meatier examples of custom XML extensions.</para>
|
||||
<section 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><![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-2.5.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="Sport-1"/>
|
||||
<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><![CDATA[package com.foo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Component {
|
||||
|
||||
private String name;
|
||||
private List components = new ArrayList();
|
||||
|
||||
]]><lineannotation>// mmm, there is no setter method for the <literal>'components'</literal></lineannotation><![CDATA[
|
||||
public void addComponent(Component component) {
|
||||
this.components.add(component);
|
||||
}
|
||||
|
||||
public List 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><![CDATA[package com.foo;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public class ComponentFactoryBean implements FactoryBean {
|
||||
|
||||
private Component parent;
|
||||
private List children;
|
||||
|
||||
public void setParent(Component parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public void setChildren(List children) {
|
||||
this.children = children;
|
||||
}
|
||||
|
||||
public Object getObject() throws Exception {
|
||||
if (this.children != null && this.children.size() > 0) {
|
||||
for (Iterator it = children.iterator(); it.hasNext();) {
|
||||
Component childComponent = (Component) it.next();
|
||||
this.parent.addComponent(childComponent);
|
||||
}
|
||||
}
|
||||
return this.parent;
|
||||
}
|
||||
|
||||
public Class 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><![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><![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><![CDATA[package com.foo;
|
||||
|
||||
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) {
|
||||
BeanDefinitionBuilder factory = BeanDefinitionBuilder.rootBeanDefinition(ComponentFactoryBean.class);
|
||||
BeanDefinitionBuilder parent = parseComponent(element);
|
||||
factory.addPropertyValue("parent", parent.getBeanDefinition());
|
||||
|
||||
List childElements = DomUtils.getChildElementsByTagName(element, "component");
|
||||
if (childElements != null && childElements.size() > 0) {
|
||||
parseChildComponents(childElements, factory);
|
||||
}
|
||||
return factory.getBeanDefinition();
|
||||
}
|
||||
|
||||
private static BeanDefinitionBuilder parseComponent(Element element) {
|
||||
BeanDefinitionBuilder component = BeanDefinitionBuilder.rootBeanDefinition(Component.class);
|
||||
component.addPropertyValue("name", element.getAttribute("name"));
|
||||
return component;
|
||||
}
|
||||
|
||||
private static void parseChildComponents(List childElements, BeanDefinitionBuilder factory) {
|
||||
ManagedList children = new ManagedList(childElements.size());
|
||||
for (int i = 0; i < childElements.size(); ++i) {
|
||||
Element childElement = (Element) childElements.get(i);
|
||||
BeanDefinitionBuilder child = parseComponent(childElement);
|
||||
children.add(child.getBeanDefinition());
|
||||
}
|
||||
factory.addPropertyValue("children", children);
|
||||
}
|
||||
}]]></programlisting>
|
||||
<para>Lastly, the various artifacts need to be registered with the Spring XML infrastructure.</para>
|
||||
<programlisting><lineannotation># in <filename>'META-INF/spring.handlers'</filename></lineannotation><![CDATA[
|
||||
http\://www.foo.com/schema/component=com.foo.ComponentNamespaceHandler]]></programlisting>
|
||||
<programlisting><lineannotation># in <filename>'META-INF/spring.schemas'</filename></lineannotation><![CDATA[
|
||||
http\://www.foo.com/schema/component/component.xsd=com/foo/component.xsd]]></programlisting>
|
||||
</section>
|
||||
<section 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
|
||||
<ulink url="http://jcp.org/en/jsr/detail?id=107">JCache</ulink>, and you want to ensure that
|
||||
the named JCache instance is eagerly started within the surrounding cluster:</para>
|
||||
<programlisting><![CDATA[<bean id="checkingAccountService" class="com.foo.DefaultCheckingAccountService"
|
||||
]]><lineannotation><emphasis role="bold">jcache:cache-name="checking.account"></emphasis></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><![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><![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><![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><![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 <filename>'META-INF/spring.handlers'</filename></lineannotation><![CDATA[
|
||||
http\://www.foo.com/schema/jcache=com.foo.JCacheNamespaceHandler]]></programlisting>
|
||||
<programlisting><lineannotation># in <filename>'META-INF/spring.schemas'</filename></lineannotation><![CDATA[
|
||||
http\://www.foo.com/schema/jcache/jcache.xsd=com/foo/jcache.xsd]]></programlisting>
|
||||
</section>
|
||||
</section>
|
||||
<section 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 <ulink url="http://www.w3.org/TR/2004/REC-xmlschema-1-20041028/">XML Schema Part 1: Structures Second Edition</ulink></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>The <ulink url="http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/">XML Schema Part 2: Datatypes Second Edition</ulink></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
</appendix>
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user