Spring Framework Guide
Spring Framework Guide
Table of Contents
Preface
1. Introduction
1.1. Overview
1.2. Usage scenarios
2. Background information
11.1. Introduction
11.2. Hibernate
11.2.1. Resource Management
11.2.2. Resource Definitions in an Application Context
11.2.3. Inversion of Control: Template and Callback
11.2.4. Applying an AOP Interceptor Instead of a Template
11.2.5. Programmatic Transaction Demarcation
11.2.6. Declarative Transaction Demarcation
11.2.7. Transaction Management Strategies
11.2.8. Container Resources versus Local Resources
11.2.9. Samples
11.3. JDO
11.4. iBATIS
11.4.1. Overview and differences between 1.3.x and 2.0
11.4.2. Setting up the SqlMap
11.4.3. Using SqlMapDaoSupport
11.4.4. Transaction management
12. Web framework
12.1. Introduction to the web framework
12.1.1. Pluggability of MVC implementation
12.1.2. Features of Spring MVC
12.2. The DispatcherServlet
12.3. Controllers
12.3.1. AbstractController and WebContentGenerator
12.3.2. Other simple controllers
12.3.3. The MultiActionController
12.3.4. CommandControllers
12.4. Handler mappings
12.4.1. BeanNameUrlHandlerMapping
12.4.2. SimpleUrlHandlerMapping
12.4.3. Adding HandlerInterceptors
12.5. Views and resolving them
12.5.1. ViewResolvers
Next
Preface
Preface
Prev Next
Preface
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 webservices, mailing
facilities and various options in persisting your data to a database. Spring provides an MVC framework,
transparent ways of integrating AOP into your software and a well-structured exception hierarchy
including automatic mapping from proprietary exception hierarchies.
Spring could potentially be a one-stop-shop for all your enterprise applications, however, Spring is
modular, allowing you to use parts of it, without having to bring in the rest. You can use the bean
container, with Struts on top, but you could also choose to just use the Hibernate integration or the JDBC
abstraction layer. Spring is non-intrusive, meaning dependencies on the framework are generally none or
absolutely minimal, depending on the area of use..
This document provides a reference guide to Spring's features. Since this document is still a
work-in-progress, if you have any requests or comments, please post them on the user mailing list or on
the forum at the SourceForge project page: http://www.sf.net/projects/springframework
Before we go on, a few words of gratitude: Chris Bauer (of the Hibernate team) prepared and adapted the
DocBook-XSL software in order to be able to create Hibernate's reference guide, also allowing us to
create this one.
Prev Up Next
Spring - Java/J2EE Application Chapter 1. Introduction
Home
Framework
Chapter 1. Introduction
Prev Next
Chapter 1. Introduction
1.1. Overview
Spring contains a lot of functionality and features, which are well-organized in seven modules shown in the diagram below. This section
discusses each the of modules in turn.
Prev Up Next
Preface Home Chapter 2. Background information
Prev Up Next
Chapter 1. Introduction Chapter 3. Beans, BeanFactory and the
Home
ApplicationContext
<beans>
...
</beans>
id and name Section 3.2.4, The bean identifiers (id and name)
singleton or prototype Section 3.2.5, To singleton or not to singleton
constructor arguments Section 3.3.1, Setting bean properties and collaborators
bean properties Section 3.3.1, Setting bean properties and collaborators
autowiring mode Section 3.3.5, Autowiring collaborators
dependency checking mode Section 3.3.6, Checking for dependencies
initialization method Section 3.4.1, Lifecycle interfaces
destruction method Section 3.4.1, Lifecycle interfaces
When creating a bean using the constructor approach, all normal classes are usable by Spring and compatible with Spring. That
is, the class being created does not need to implement any specific interfaces or be coded in a specific fashion. Just specifying
the bean class should be enough. However, depending on what type of IoC you are going to use for that specific bean, you may
need a default (empty) constructor.
Additionally, the BeanFactory isn't limited to just managing true JavaBeans, it is also able to manage virtually any class you
want it to manage. Most people using Spring prefer to have actual JavaBeans (having just a default (no-argument) constructor
and appropriate setters and getters modelled after the properties) in the BeanFactory, but it it's also possible to have more exotic
non-bean-style classes in your BeanFactory. If, for example, you need to use a legacy connection pool that absolutely does not
adhere to the JavaBean specification, no worries, Spring can manage it as well.
Using the XmlBeanFactory you can specify your bean class as follows:
<bean id="exampleBean"
class="examples.ExampleBean"/>
<bean name="anotherExample"
class="examples.ExampleBeanTwo"/>
The mechanism for supplying (optional) arguments to the constructor, or setting properties of the object instance after it has
been constructed, will be described shortly.
When defining a bean which is to be created using a static factory method, along with the class attribute which specifies the
class containing the static factory method, another attribute named factory-method is needed to specify the name of the
factory method itself. Spring expects to be able to call this method (with an optional list of arguments as described later) and get
back a live object, which from that point on is treated as if it had been created normally via a constructor. One use for such a
bean definition is to call static factories in legacy code.
Following is an example of a bean definition which specifies that the bean is to be created by calling a factory-method. Note that
the definition does not specify the type (class) of the returned object, only the class containing the factory method. In this
Quite similar to using a static factory method to create a bean, is the the use of an instance (non-static) factory method, where a
factory method of an existing bean from the factory is called to create the new bean.
To use this mechanism, the class attribute must be left empty, and the factory-bean attribute must specify the name of a
bean in the current or an ancestor bean factory which contains the factory method. The factory method itself should still be set
via the factory-method attribute.
Following is an example:
<!-- The factory bean, which contains a method called
createInstance -->
<bean id="myFactoryBean"
class="...">
...
</bean>
<!-- The bean to be created via the factory bean -->
<bean id="exampleBean"
factory-bean="myFactoryBean"
factory-method="createInstance"/>
Although the mechanisms for setting bean properties are still to be discussed, one implication of this approach is that the factory
bean itself can be managed and configured via Dependency Injection, by the container.
non-singleton (prototype), each request for a bean will result in a newly created bean and this might not be what you actually
want. So only change the mode to prototype when absolutely necessary.
In the example below, two beans are declared of which one is defined as a singleton, and the other one is a non-singleton
(prototype). exampleBean is created each and every time a client asks the BeanFactory for this bean, while
yetAnotherExample is only created once; a reference to the exact same instance is returned on each request for this bean.
<bean id="exampleBean"
class="examples.ExampleBean" singleton="false"/>
<bean name="yetAnotherExample"
class="examples.ExampleBeanTwo" singleton="true"/>
Note: when deploying a bean in the prototype mode, the lifecycle of the bean changes slightly. By definition, Spring can not
manage the complete lifecycle of a non-singleton/prototype bean, since after it is created, it is given to the client and the
container does not keep track of it at all any longer. You can think of Spring's role when talking about a non-singleton/prototype
bean as a replacement for the 'new' operator. Any lifecycle aspects past that point have to be handled by the client. The lifecycle
of a bean in the BeanFactory is further described in Section 3.4.1, Lifecycle interfaces .
1. The BeanFactory is created and initialized with a configuration which describes all the beans. Most Spring users use a
BeanFactory or ApplicationContext variant which supports XML format configuration files.
2. Each bean has dependencies expressed in the form of properties, constructor arguments, or arguments to the static-factory
method when that is used instead of a normal constructor. These dependencies will be provided to the bean, when the
bean is actually created.
3. Each property or constructor-arg is either an actual definition of the value to set, or a reference to another bean in the
BeanFactory. In the case of the ApplicationContext, the reference can be to a bean in a parent ApplicationContext.
4. Each property or constructor argument which is a value must be able to be converted from whatever format it was
specified in, to the actual type of that property or constructor argument. By default Spring can convert a value supplied in
string format to all built-in types, such as int, long, String, boolean, etc. Additionally, when talking about the
XML based BeanFactory variants (including the ApplicationContext variants), these have built-in support for defining
Lists, Maps, Sets, and Properties collection types. Additionally, Spring uses JavaBeans PropertyEditor definitions to
be able to convert string values to other, arbitrary types. (You can provide the BeanFactory with your own
PropertyEditor definitions to be able to convert your own custom types; more information about PropertyEditors
and how to manually add custom ones, can be found in Section 3.9, Registering additional custom PropertyEditors ).
When a bean property is a Java Class type, Spring allows you to specify the value for that property as a string value which
is the name of the class, and the ClassEditor PropertyEditor, which is built-in, will take care of converting that class
name to an actual Class instance.
5. It is important to realize that Spring validates the configuration of each bean in the BeanFactory when the BeanFactory is
created, including the validation that properties which are bean references are actually referring to valid beans (i.e. the
beans being referred to are also defined in the BeanFactory, or in the case of ApplicationContext, a parent context).
However, the bean properties themselves are not set until the bean is actually created. For beans which are singleton and
set to be pre-instantiated (such as singleton beans in an ApplicationContext), creation happens at the time that the
BeanFactory is created, but otherwise this is only when the bean is requested. When a bean actually has to be created, this
will potentially cause a graph of other beans to be created, as its dependencies and its dependencies' dependencies (and so
on) are created and assigned.
6. You can generally trust Spring to do the right thing. It will pick up configuraton issues, including references to
non-existent beans and circular dependencies, at BeanFactory load-time. It will actually set properties and resolve
dependencies (i.e. create those dependencies if needed) as late as possible, which is when the bean is actually created.
This does mean that a BeanFactory which has loaded correctly, can later generate an exception when you request a bean,
if there is a problem creating that bean or one of its dependencies. This could happen if the bean throws an exception as a
result of a missing or invalid property, for example. This potentially delayed visibility of some configuration issues is why
ApplicationContext by default pre-instantiates singleton beans. At the cost of some upfront time and memory to create
these beans before they are actually needed, you find out about configuration issues when the ApplicationContext is
created, not later. If you wish, you can still override this default behavior and set any of these singleton beans to lazy-load
(not be preinstantiated).
Some examples:
First, an example of using the BeanFactory for setter-based dependency injection. Below is a small part of an
XmlBeanFactory config file specifying some bean definitions. Following is the code for the actual main bean itself, showing
the appropriate setters declared.
<bean id="exampleBean" class="examples.ExampleBean">
<property name="beanOne"><ref bean="anotherExampleBean"/></property>
<property name="beanTwo"><ref bean="yetAnotherBean"/></property>
<property name="integerProperty"><value>1</value></property>
</bean>
...
// a private constructor
private ExampleBean(...) {
...
}
</bean>
</beans>
Note that the value of a Map entry, or a set value, can also again be any of the elements:
(bean | ref | idref | list | set | map | props | value | null)
A bean element inside the property element is used to define a bean value inline, instead of referring to a bean defined
elsewhere in the BeanFactory. The inline bean definition does not need to have any id defined.
<bean id="outer" class="...">
<!-- Instead of using a reference to target, just use an inner bean -->
<property name="target">
<bean class="com.mycompany.PersonImpl">
<property name="name"><value>Tony</value></property>
<property name="age"><value>51</value></property>
</bean>
</property>
</bean>
An idref element is simply a shorthand and error-proof way to set a property to the String id or name of another bean in the
container.
<bean id="theTargetBean" class="...">
</bean>
<bean id="theClientBean" class="...">
<property name="targetName">
<idref bean="theTargetBean"/>
</property>
</bean>
This is exactly equivalent at runtime to the following fragment:
<bean id="theTargetBean" class="...">
</bean>
<bean id="theClientBean" class="...">
<property name="targetName">
<value>theTargetBean</value>
</property>
</bean>
The main reason the first form is preferrable to the second is that using the idref tag will allow Spring to validate at
deployment time that the other bean actually exists. In the second variation, the class who's targetName property is forced to do
its own validation, and that will only happen when that class is actually instantiated by Spring, possibly long after the container
is actually deployed.
Additionally, if the bean being referred to is in the same actual XML file, and the bean name is the bean id, the local attribute
may be used, which will allow the XML parser itself to validate the bean name even earlier, at XML document parse time.
<property name="targetName">
<idref local="theTargetBean"/>
</property>
The ref element is the final element allowed inside a property definition element. It is used to set the value of the specified
property to be a reference to another bean managed by the container, a collaborator, so to speak. As mentioned in a previous
section, the referred-to bean is considered to be a dependency of the bean who's property is being set, and will be initialized on
demand as needed (if it is a singleton bean it may have already been initialized by the container) before the property is set. All
references are ultimately just a reference to another object, but there are 3 variations on how the id/name of the other object may
be specified, which determines how scoping and validation is handled.
Specifying the target bean by using the bean attribute of the ref tag is the most general form, and will allow creating a
reference to any bean in the same BeanFactory/ApplicationContext (whether or not in the same XML file), or parent
BeanFactory/ApplicationContext. The value of the bean attribute may be the same as either the id attribute of the target bean,
or one of the values in the name attribute of the target bean.
<ref bean="someBean"/>
Specifying the target bean by using the local attribute leverages the ability of the XML parser to validate XML id references
within the same file. The value of the local attribute must be the same as the id attribute of the target bean. The XML parser
will issue an error if no matching element is found in the same file. As such, using the local variant is the best choice (in order to
know about errors are early as possible) if the target bean is in the same XML file.
<ref local="someBean"/>
Specifying the target bean by using the parent attribute allows a reference to be created to a bean which is in a parent
BeanFactory (or ApplicationContext) of the current BeanFactory (or ApplicationContext). The value of the parent attribute
may be ther same as either the id attribute of the target bean, or one of the values in the name attribute of the target bean, and
the target bean must be in a parent BeanFactory or ApplicationContext to the current one. The main use of this bean reference
variant is when there is a need to wrap an existing bean in a parent context with some sort of proxy (which may have the same
name as the parent), and needs the original object so it may wrap it.
<ref parent="someBean"/>
Lookup method injection refers to the ability of the container to override abstract or concrete methods on managed beans in the
container, to return the result of looking up another named bean in the container. The lookup will typically be of a non-singleton
bean as per the scenario described above (although it can also be a singleton). Spring implements this by performing bytecode
modification on the client class, using the CGLIB library.
In the client class containing the method to be injected, the method definition must be an abstract (or concrete) definition in this
form:
protected abstract SingleShotHelper createSingleShotHelper();
If the method is not abstract, Spring will simply override the existing implementation. In the XmlBeanFactory case, you instruct
Spring to inject/override this method to return a particular bean from the container, by using the lookup-method element
inside the bean definition. For example:
<!-- a stateful bean deployed as a protype (non-singleton) -->
<bean id="singleShotHelper class="..." singleton="false">
</bean>
The bean identified as myBean will call its own method createSingleShotHelper whenever it needs a new instance of
the singleShotHelper bean. It is important to note that the person deploying the beans must be careful to deploy
singleShotHelper as a non-singleton (if that is actually what is needed). If it is deployed as a singleton (either explicitly, or
relying on the default true setting for this flag), the same instance of singleShotHelper will be returned each time!
Note that lookup method injection can be combined with Constructor Injection (supplying optional constructor arguments to the
bean being constructed), and also with Setter Injection (settings properties on the bean being constructed).
A less commonly useful form of method injection than Lookup Method Injection is the ability to replace arbitrary methods in a
managed bean with another method implementation. Users may safely skip the rest of this section (which describes this
somewhat advanced feature), until this functionality is actually needed.
In an XmlBeanFactory, the replaced-method element may be used to replace an existing method implementation with
another, for a deployed bean. Consider the following class, with a method computeValue, which we want to override:
...
public class MyValueCalculator {
public String computeValue(String input) {
... some real code
}
Since the number of arguments is often enough to distinguish between each possible choice, this shortcut can save a lot of
typing, by just using the shortest string which will match an argument.
Note that explicit dependencies, i.e. property and constructor-arg elements, always override autowiring. Autowire
behaviour can be combined with dependency checking, which will be performed after all autowiring has been completed.
Note: as has already been mentioned, for larger applications, it is discouraged to use autowiring because it removes the
transparency and the structure from your collaborating classes.
unecessarily couples the code to Spring). A bean definition provides support for a generic initialization method to be specified.
In the case of the XmlBeanFactory, this is done via the init-method attribute. For example, the following definition:
<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
container does not keep track of it at all any longer. You can think of Spring's role when talking about a non-singleton/prototype
bean as a replacement for the 'new' operator. Any lifecycle aspects past that point have to be handled by the client. The lifecycle
of a bean in the BeanFactory is further described in Section 3.4.1, Lifecycle interfaces .
3.4.2.2. BeanNameAware
3.4.3. FactoryBean
The org.springframework.beans.factory.FactoryBean interface is to be implemented by objects that are
themselves factories. The BeanFactory interface provides three method:
● Object getObject(): has to return an instance of the object this factory creates. The instance can possibly be shared
(depending on whether this factory returns singletons or prototypes).
● boolean isSingleton(): has to return true if this FactoryBean returns singletons, false otherwise
● Class getObjectType(): has to return either the object type returned by the getObject() method or null if
the type isn't known in advance
When working with a BeanFactory programmatically, child bean definitions are represented by the ChildBeanDefinition
class. Most users will never work with them on this level, instead configuring bean definitions declaratively in something like
the XmlBeanFactory. In an XmlBeanFactory bean definition, a child bean definition is indicated simply by using the parent
attribute, specifying the parent bean as the value of this attribute.
<bean id="inheritedTestBean" abstract="true"
class="org.springframework.beans.TestBean">
<property name="name"><value>parent</value></property>
<property name="age"><value>1</value></property>
</bean>
<bean id="inheritsWithDifferentClass"
class="org.springframework.beans.DerivedTestBean"
parent="inheritedTestBean" init-method="initialize">
<property name="name"><value>override</value></property>
<!-- age should inherit value of 1 from parent -->
</bean>
A child bean definition will use the bean class from the parent definition if none is specified, but can also override it. In the
latter case, the child bean class must be compatible with the parent, i.e. it must accept the parent's property values.
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 and/or static 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, singleton,
lazy init.
Note that in the example above, we have explicitly marked the parent bean definition as abstract by using the abstract attribute.
In the case that the parent definition does not specify a class:
<bean id="inheritedTestBeanWithoutClass">
<property name="name"><value>parent</value></property>
<property name="age"><value>1</value></property>
</bean>
...
Since this manual registration step is not convenient, and ApplictionContexts are functionally supersets of BeanFactories, it is
generally recommended that ApplicationContext variants are used when bean post-processors are needed.
jdbc.url=jdbc:hsqldb:hsql://production:9002
jdbc.username=sa
jdbc.password=root
To use this with a BeanFactory, the bean factory post-processor is manually executed on it:
XmlBeanFactory factory = new XmlBeanFactory(new FileSystemResource("beans.xml"));
PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer();
cfg.setLocation(new FileSystemResource("jdbc.properties"));
cfg.postProcessBeanFactory(factory);
Note that ApplicationContexts are able to automatically recognize and apply beans deployed in them which implement
BeanFactoryPostProcessor. This means that as described here, applying PropertyPlaceholderConfiguer is much more convenient
when using an ApplicationContext. For this reason, it is recommended that users wishing to use this or other bean factory
postprocessors use an ApplicationContext instead of a BeanFactory.
The PropertyPlaceHolderConfigurer doesn't only look for properties in the Properties file you specify, but also
checks against the Java System properties if it cannot find a property you are trying to use. This behavior can be customized by
setting the systemPropertiesMode property of the configurer. It has three values, one to tell the configurer to always
override, one to let it never override and one to let it override only if the property cannot be found in the properties file
specified. Please consult the JavaDoc for the PropertiesPlaceHolderConfigurer for more information.
is strongly recommended that, as described here, it is used with the ApplicationContext, where it may be deployed in similar
fashion to any other bean, and automatically detected and applied.
messages, an empty StaticMessageSource will be instantiated in order to be able to accept calls to the methods defined
above.
Spring currently provides two MessageSource implementations. These are the ResourceBundleMessageSource and
the StaticMessageSource. Both implement NestingMessageSource in order to do nested messaging. The
StaticMessageSource is hardly ever used but provides programmatic ways to add messages to the source. The
ResourceBundleMessageSource is more interesting and is the one we will provides an example for:
<beans>
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>format</value>
<value>exceptions</value>
<value>windows</value>
</list>
</property>
</bean>
</beans>
This assumes you have three resource bundles defined on your classpath called format, exceptions and windows. Using
the JDK standard way of resolving messages through ResourceBundles, any request to resolve a message will be handled.
TODO: SHOW AN EXAMPLE
Implementing custom events can be done as well. Simply call the publishEvent() method on the ApplicationContext,
specifying a parameter which is an instance of your custom event class implementing ApplicationEvent. Let's look at an
example. First, the ApplicationContext:
<bean id="emailer" class="example.EmailBean">
<property name="blackList">
<list>
<value>[email protected]</value>
<value>[email protected]</value>
<value>[email protected]</value>
</list>
</property>
</bean>
A couple of Resource implementations are provided by Spring. They all need a String representing the actual location of the
resource. Based upon that String, Spring will automatically choose the right Resource implementation for you. When asking an
ApplicationContext for a resource first of all Spring will inspect the resource location you're specifying and look for any
prefixes. Depending on the implenentation of the ApplicationContext more or less Resource implementations are available.
Resources can best be configured by using the ResourceEditor and for example the XmlBeanFactory.
class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="example.ExoticType">
<bean class="example.ExoticTypeEditor">
<property name="format">
<value>upperCase</value>
</property>
</bean>
</entry>
</map>
</property>
</bean>
of the method to call on that target object. Arguments for the method invocation may be specified by setting the args property.
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
-->
The listener inspects the contextConfigLocation parameter. If it doesn't exist, it'll use
/WEB-INF/applicationContext.xml as a default. When it does exist, it'll separate the String using predefined
delimiters (comma, semi-colon and space) and use the values as locations where application contexts will be searched for. The
ContextLoaderServlet can - as said - be used instead of the ContextLoaderListener. The servlet will use the
contextConfigLocation parameter just as the listener does.
usage or initialization times (when using beans in the BeanFactory such as a Hibernate SessionFactory) for each bean to use its
own, non-singleton BeanFactory.
As another example, in a complex J2EE apps with multiple layers (i.e. various JAR files, EJBs, and WAR files packaged as an
EAR), with each layer having its own ApplicationContext definition (effectively forming a hierarchy), the preferred approach
when there is only one web-app (WAR) in the top hierarchy is to simply create one composite ApplicationContext from the
multiple XML definition files from each layer. All the ApplicationContext variants may be constructed from multiple definition
files in this fashion. However, if there are multiple sibling web-apps at the top of the hierarchy, it is problematic to create an
ApplicationContext for each web-app which consists of mostly identical bean definitions from lower layers, as there may be
issues due to increased memory usage, issues with creating mutliple copies of beans which take a long time to initialize (i.e. a
Hibernate SessionFactory), and possible issues due to side-effects. As an alternative, classes such as
ContextSingletonBeanFactoryLocator or SingletonBeanFactoryLocator may be used to demand load
multiple hierarchical (i.e. one is a parent of another) BeanFactories or ApplicationContexts in an effectively singleton fashion,
which may then be used as the parents of the web-app ApplicationContexts. The result is that bean definitions for lower layers
are loaded only as needed, and loaded only once.
Prev Up Next
Chapter 2. Background information Home
Chapter 4. PropertyEditors, data
binding, validation and the BeanWrapper
One quite important concept of the beans package is the BeanWrapper interface and its corresponding
implementation (BeanWrapperImpl). As quoted from the JavaDoc, the BeanWrapper offers
functionnality to set and get property values (individually or in bulk), get property descriptors and query the
readability and writability of properties. Also, the BeanWrapper offers support for nested properties,
enabling the setting of properties on subproperties to an unlimited depth. Then, the BeanWrapper support the
ability to add standard JavaBeans PropertyChangeListeners and VetoableChangeListeners,
without the need for supporting code in the target class. Last but not least, the BeanWrapper provides support
for the setting of indexed properties. The BeanWrapper usually isn't used by application code directly, but by
the DataBinder and the BeanFactory.
The way the BeanWrapper works is partly indicated by its name: it wraps a bean to perform actions on that
bean, like setting and retrieving properties.
Below you'll find some examples of working with the BeanWrapper to get and set properties.
Note: this part is not important to you if you're not planning to work with the BeanWrapper directly. If
you're just using the DataBinder and the BeanFactory and their out-of-the-box implementation, you
should skip ahead to the section about PropertyEditors.
Consider the following two classes:
public class Company {
private String name;
private Employee managingDirector;
Spring uses the java.beans.PropertyEditorManager to set the search-path for property editors
that might be needed. The search-path also includes sun.bean.editors, which includes PropertyEditors
for Font, Color and all the primitive types.
Prev Up Next
Chapter 3. Beans, BeanFactory and the Home
Chapter 5. Spring AOP: Aspect
ApplicationContext Oriented Programming with Spring
● Weaving: Assembling aspects to create an advised object. This can be done at compile time (using the AspectJ compiler, for
example), or at runtime. Spring, like other pure Java AOP frameworks, performs weaving at runtime.
Different advice types include:
● Around advice: Advice that surrounds a joinpoint such as a method invocation. This is the most powerful kind of advice.
Around advices will perform custom behaviour before and after the method invocation. They are responsible for choosing
whether to proceed to the joinpoint or to shortcut executing by returning their own return value or throwing an exception.
● Before advice: Advice that executes before a joinpoint, but which does not have the ability to prevent execution flow
proceeding to the joinpoint (unless it throws an exception).
● Throws advice: Advice to be executed if a method throws an exception. Spring provides strongly typed throws advice, so
you can write code that catches the exception (and subclasses) you're interested in, without needing to cast from Throwable
or Exception.
● After returning advice: Advice to be executed after a joinpoint completes normally: for example, if a method returns without
throwing an exception.
Around advice is the most general kind of advice. Most interception-based AOP frameworks, such as Nanning Aspects, provide
only around advice.
As Spring, like AspectJ, provides a full range of advice types, we recommend that you use the least powerful advice type that can
implement the required behaviour. For example, if you need only to update a cache with the return value of a method, you are
better off implementing an after returning advice than an around advice, although an around advice can accomplish the same thing.
Using the most specific advice type provides a simpler programming model with less potential for errors. For example, you don't
need to invoke the proceed() method on the MethodInvocation used for around advice, and hence can't fail to invoke it.
The pointcut concept is the key to AOP, distinguishing AOP from older technologies offering interception. Pointcuts enable advice
to be targeted independently of the OO hierarchy. For example, an around advice providing declarative transaction management
can be applied to a set of methods spanning multiple objects. Thus pointcuts provide the structural element of AOP.
5.2.1. Concepts
Spring's pointcut model enables pointcut reuse independent of advice types. It's possible to target different advice using the same
pointcut.
The org.springframework.aop.Pointcut interface is the central interface, used to target advices to particular classes
and methods. The complete interface is shown below:
public interface Pointcut {
ClassFilter getClassFilter();
MethodMatcher getMethodMatcher();
}
Splitting the Pointcut interface into two parts allows reuse of class and method matching parts, and fine-grained composition
operations (such as performing a "union" with another method matcher).
The ClassFilter interface is used to restrict the pointcut to a given set of target classes. If the matches() method always
returns true, all target classes will be matched:
public interface ClassFilter {
boolean isRuntime();
Static pointcuts are based on method and target class, and cannot take into account the method's arguments. Static pointcuts are
sufficient--and best--for most usages. It's possible for Spring to evaluate a static pointcut only once, when a method is first invoked:
after that, there is no need to evaluate the pointcut again with each method invocation.
Let's consider some static pointcut implementations included with Spring.
One obvious way to specific static pointcuts is regular expressions. Several AOP frameworks besides Spring make this possible.
org.springframework.aop.support.RegexpMethodPointcut is a generic regular expression pointcut, using Perl 5
regular expression syntax.
Using this class, you can provide a list of pattern Strings. If any of these is a match, the pointcut will evaluate to true. (So the result
is effectively the union of these pointcuts.)
The usage is shown below:
<bean id="settersAndAbsquatulatePointcut"
class="org.springframework.aop.support.RegexpMethodPointcut">
<property name="patterns">
<list>
<value>.*get.*</value>
<value>.*absquatulate</value>
</list>
</property>
</bean>
An important type of static pointcut is a metadata-driven pointcut. This uses the values of metadata attributes: typically,
source-level metadata.
Dynamic pointcuts are costlier to evaluate than static pointcuts. They take into account method arguments, as well as static
information. This means that they must be evaluated with every method invocation; the result cannot be cached, as arguments will
vary.
The main example is the control flow pointcut.
Spring control flow pointcuts are conceptually similar to AspectJ cflow pointcuts, although less powerful. (There is currently no
way to specify that a pointcut executes below another pointcut.) A control flow pointcut matches the current call stack. For
example, it might fire if the joinpoint was invoked by a method in the com.mycompany.web package, or by the SomeCaller
class. Control flow pointcuts are specified using the org.springframework.aop.support.ControlFlowPointcut
class.
[Note] Note
Control flow pointcuts are significantly more expensive to evaluate at runtime than even other dynamic pointcuts. In Java
1.4, the cost is about 5 times that of other dynamic pointcuts; in Java 1.3 more than 10.
A simpler advice type is a before advice. This does not need a MethodInvocation object, since it will only be called before
entering the method.
The main advantage of a before advice is that there is no need to invoke the proceed() method, and therefore no possibility of
inadvertently failing to proceed down the interceptor chain.
The MethodBeforeAdvice interface is shown below. (Spring's API design would allow for field before advice, although the
usual objects apply to field interception and it's unlikely that Spring will ever implement it).
public interface MethodBeforeAdvice extends BeforeAdvice {
Throws advice is invoked after the return of the joinpoint if the joinpoint threw an exception. Spring offers typed throws advice.
Note that this means that the org.springframework.aop.ThrowsAdvice interface does not contain any methods: it is a
tag interface identifying that the given object implements one or more typed throws advice methods. These should be of form
afterThrowing([Method], [args], [target], subclassOfThrowable)
Only the last argument is required. Thus there from one to four arguments, depending on whether the advice method is interested in
the method and arguments. The following are examples of throws advices.
This advice will be invoked if a RemoteException is thrown (including subclasses):
public class RemoteThrowsAdvice implements ThrowsAdvice {
The following advice is invoked if a ServletException is thrown. Unlike the above advice, it declares 4 arguments, so that it has
access to the invoked method, method arguments and target object:
public static class ServletThrowsAdviceWithArguments implements ThrowsAdvice {
An after returning advice in Spring must implement the org.springframework.aop.AfterReturningAdvice interface, shown below:
public interface AfterReturningAdvice extends Advice {
ClassFilter getClassFilter();
IntroductionInterceptor getIntroductionInterceptor();
Class[] getInterfaces();
}
There is no MethodMatcher, and hence no Pointcut, associated with introduction advice. Only class filtering is logical.
The getInterfaces() method returns the interfaces introduced by this advisor.
Let's look at a simple example from the Spring test suite. Let's suppose we want to introduce the following interface to one or more
objects:
public interface Lockable {
void lock();
void unlock();
boolean locked();
}
This illustrates a mixin. We want to be able to cast advised objects to Lockable, whatever their type, and call lock and unlock
methods. If we call the lock() method, we want all setter methods to throw a LockedException. Thus we can add an aspect that
provides the ability to make objects immutable, without them having any knowledge of it: a good example of AOP.
Firstly, we'll need an IntroductionInterceptor that does the heavy lifting. In this case, we extend the
org.springframework.aop.support.DelegatingIntroductionInterceptor convenience class. We could
implement IntroductionInterceptor directly, but using DelegatingIntroductionInterceptor is best for most cases.
The DelegatingIntroductionInterceptor is designed to delegate an introduction to an actual implementation of the
introduced interface(s), concealing the use of interception to do so. The delegate can be set to any object using a constructor
argument; the default delegate (when the no-arg constructor is used) is this. Thus in the example below, the delegate is the
LockMixin subclass of DelegatingIntroductionInterceptor. Given a delegate (by default itself) a
DelegatingIntroductionInterceptor instance looks for all interfaces implemented by the delegate (other than
IntroductionInterceptor), and will support introductions against any of them. It's possible for subclasses such as LockMixin to
call the suppressInterflace(Class intf) method to suppress interfaces that should not be exposed. However, no
matter how many interfaces an IntroductionInterceptor is prepared to support, the IntroductionAdvisor used will
control which interfaces are actually exposed. An introduced interface will conceal any implementation of the same interface by the
target.
Thus LockMixin subclasses DelegatingIntroductionInterceptor and implements Lockable itself. The superclass
automatically picks up that Lockable can be supported for introduction, so we don't need to specify that. We could introduce any
number of interfaces in this way.
Note the use of the locked instance variable. This effectively adds additional state to that held in the target object.
public class LockMixin extends DelegatingIntroductionInterceptor
}
Often it isn't necessary to override the invoke() method: the DelegatingIntroductionInterceptor
implementation--which calls the delegate method if the method is introduced, otherwise proceeds towards the joinpoint--is usually
sufficient. In the present case, we need to add a check: no setter method can be invoked if in locked mode.
The introduction advisor required is simple. All it needs to do is hold a distinct LockMixin instance, and specify the introduced
interfaces--in this case, just Lockable. A more complex example might take a reference to the introduction interceptor (which
would be defined as a prototype): in this case, there's no configuration relevant for a LockMixin, so we simply create it using
new.
public class LockMixinAdvisor extends DefaultIntroductionAdvisor {
public LockMixinAdvisor() {
super(new LockMixin(), Lockable.class);
}
}
We can apply this advisor very simply: it requires no configuration. (However, it is necessary: It's impossible to use an
IntroductionInterceptor without an IntroductionAdvisor.) As usual with introductions, the advisor must be per-instance,
as it is stateful. We need a different instance of LockMixinAdvisor, and hence LockMixin, for each advised object. The
advisor comprises part of the advised object's state.
We can apply this advisor programmatically, using the Advised.addAdvisor() method, or (the recommended way) in XML
configuration, like any other advisor. All proxy creation choices discussed below, including "auto proxy creators," correctly handle
introductions and stateful mixins.
5.5.1. Basics
The ProxyFactoryBean, like other Spring FactoryBean implementations, introduces a level of indirection. If you define a
ProxyFactoryBean with name foo, what objects referencing foo see is not the ProxyFactoryBean instance itself, but an
object created by the ProxyFactoryBean's implementation of the getObject() method. This method will create an AOP
proxy wrapping a target object.
One of the most important benefits of using a ProxyFactoryBean or other IoC-aware class to create AOP proxies, is that it
means that advices and pointcuts can also be managed by IoC. This is a powerful feature, enabling certain approaches that are hard
to achieve with other AOP frameworks. For example, an advice may itself reference application objects (besides the target, which
should be available in any AOP framework), benefiting from all the pluggability provided by Dependency Injection.
<bean id="debugInterceptor"
class="org.springframework.aop.interceptor.DebugInterceptor">
</bean>
<bean id="person"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"><value>com.mycompany.Person</value></property>
<bean id="debugInterceptor"
class="org.springframework.aop.interceptor.DebugInterceptor">
</bean>
<bean id="person"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"><value>com.mycompany.Person</value></property>
<property name="interceptorNames">
<list>
<value>myAdvisor</value>
<value>debugInterceptor</value>
</list>
</property>
</bean>
This has the advantage that there's only one object of type Person: useful if we want to prevent users of the application context
obtaining a reference to the un-advised object, or need to avoid any ambiguity with Spring IoC autowiring. There's also arguably an
advantage in that the ProxyFactoryBean definition is self-contained. However, there are times when being able to obtain the
un-advised target from the factory might actually be an advantage: for example, in certain test scenarios.
5.6.1. TransactionProxyFactoryBean
The jPetStore sample application shipped with Spring shows the use of the TransactionProxyFactoryBean.
The TransactionProxyFactoryBean is a subclass of ProxyConfig, so basic configuration is shared with
ProxyFactoryBean. (See list of ProxyConfig properties above.)
The following example from the jPetStore illustrates how this works. As with a ProxyFactoryBean, there is a target bean
definition. Dependencies should be expressed on the proxied factory bean definition ("petStore" here), rather than the target POJO
("petStoreTarget").
The TransactionProxyFactoryBean requires a target, and information about "transaction attributes," specifying which
methods should be transactional and the required propagation and other settings:
<bean id="petStoreTarget"
class="org.springframework.samples.jpetstore.domain.logic.PetStoreImpl">
<property name="accountDao"><ref bean="accountDao"/></property>
<!-- Other dependencies omitted -->
</bean>
<bean id="petStore"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager"><ref bean="transactionManager"/></property>
<property name="target"><ref local="petStoreTarget"/></property>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
As with the ProxyFactoryBean, we might choose to use an inner bean to set the value of target property, instead of a
reference to a top-level target bean.
The TransactionProxyFactoryBean automatically creates a transaction advisor, including a pointcut based on the
transaction attributes, so only transactional methods are advised.
The TransactionProxyFactoryBean allows the specification of "pre" and "post" advice, using the preInterceptors and
postInterceptors properties. These take Object arrays of interceptors, other advice or Advisors to place in the interception chain
before or after the transaction interceptor. These can be populated using a <list> element in XML bean definitions, as follows:
<property name="preInterceptors">
<list>
<ref local="authorizationInterceptor"/>
<ref local="notificationBeforeAdvice"/>
</list>
</property>
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager"><ref
local="transactionManager"/></ref></property>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
This will never be instantiated itself, so may actually be incomplete. Then each proxy which needs to be created is just a child bean
definition, which to wraps the target of the proxy as an inner bean definition, since the target will never be used on its own
anyways.
<bean id="myService" parent="txProxyTemplate">
<property name="target">
<bean class="org.springframework.samples.MyServiceImpl">
</bean>
</property>
boolean isFrozen();
The getAdvisors() method will return an Advisor for every advisor, interceptor or other advice type that has been added to the
factory. If you added an Advisor, the returned advisor at this index will be the object that you added. If you added an interceptor or
other advice type, Spring will have wrapped this in an advisor with a pointcut that always returns true. Thus if you added a
MethodInterceptor, the advisor returned for this index will be an DefaultPointcutAdvisor returning your
MethodInterceptor and a pointcut that matches all classes and methods.
The addAdvisor() methods can be used to add any Advisor. Usually the advisor holding pointcut and advice will be the generic
DefaultPointcutAdvisor, which can be used with any advice or pointcut (but not for introduction).
By default, it's possible to add or remove advisors or interceptors even once a proxy has been created. The only restriction is that
it's impossible to add or remove an introduction advisor, as existing proxies from the factory will not show the interface change.
(You can obtain a new proxy from the factory to avoid this problem.)
A simple example of casting an AOP proxy to the Advised interface and examining and manipulating its advice:
Advised advised = (Advised) myObject;
Advisor[] advisors = advised.getAdvisors();
int oldAdvisorCount = advisors.length;
System.out.println(oldAdvisorCount + " advisors");
5.10.1.1. BeanNameAutoProxyCreator
The BeanNameAutoProxyCreator automatically creates AOP proxies for beans with names matching literal values or wildcards.
<bean id="jdkBeanNameProxyCreator"
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames"><value>jdk*,onlyJdk</value></property>
<property name="interceptorNames">
<list>
<value>myInterceptor</value>
</list>
</property>
</bean>
As with ProxyFactoryBean, there is an interceptorNames property rather than a list of interceptor, to allow correct behaviour
for prototype advisors. Named "interceptors" can be advisors or any advice type.
As with auto proxying in general, the main point of using BeanNameAutoProxyCreator is to apply the same configuration
consistently to multiple objects, and with minimal volume of configuration. It is a popular choice for applying declarative
transactions to multiple objects.
Bean definitions whose names match, such as "jdkMyBean" and "onlyJdk" in the above example, are plain old bean definitions
with the target class. An AOP proxy will be created automatically by the BeanNameAutoProxyCreator. The same advice will
be applied to all matching beans. Note that if advisors are used (rather than the interceptor in the above example), the pointcuts may
apply differently to different beans.
5.10.1.2. DefaultAdvisorAutoProxyCreator
A more general and extremely powerful auto proxy creator is DefaultAdvisorAutoProxyCreator. This will automagically
apply eligible advisors in the current context, without the need to include specific bean names in the autoproxy advisor's bean
definition. It offers the same merit of consistent configuration and avoidance of duplication as BeanNameAutoProxyCreator.
Using this mechanism involves:
● Specifying a DefaultAdvisorAutoProxyCreator bean definition
● Specifying any number of Advisors in the same or related contexts. Note that these must be Advisors, not just interceptors or
other advices. This is necessary because there must be a pointcut to evaluate, to check the eligibility of each advice to
candidate bean definitions.
The DefaultAdvisorAutoProxyCreator will automatically evaluate the pointcut contained in each advisor, to see what (if
class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
</bean>
<bean id="txAdvisor"
autowire="constructor"
class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">
<property name="order"><value>1</value></property>
</bean>
<bean id="customAdvisor"
class="com.mycompany.MyAdvisor">
</bean>
<bean id="businessObject1"
class="com.mycompany.BusinessObject1">
<!-- Properties omitted -->
</bean>
<bean id="businessObject2"
class="com.mycompany.BusinessObject2">
</bean>
The DefaultAdvisorAutoProxyCreator is very useful if you want to apply the same advice consistently to many business
objects. Once the infrastructure definitions are in place, you can simply add new business objects without including specific proxy
configuration. You can also drop in additional aspects very easily--for example, tracing or performance monitoring aspects--with
minimal change to configuration.
The DefaultAdvisorAutoProxyCreator offers support for filtering (using a naming convention so that only certain advisors are
evaluated, allowing use of multiple, differently configured, AdvisorAutoProxyCreators in the same factory) and ordering. Advisors
can implement the org.springframework.core.Ordered interface to ensure correct ordering if this is an issue. The
TransactionAttributeSourceAdvisor used in the above example has a configurable order value; default is unordered.
5.10.1.3. AbstractAdvisorAutoProxyCreator
This is the superclass of DefaultAdvisorAutoProxyCreator. You can create your own autoproxy creators by subclassing this class,
in the unlikely event that advisor definitions offer insufficient customization to the behaviour of the framework
DefaultAdvisorAutoProxyCreator.
This is really a special case of the DefaultAdvisorAutoProxyCreator, but deserves consideration on its own. (The
metadata-aware code is in the pointcuts contained in the advisors, not the AOP framework itself.)
The /attributes directory of the jPetStore sample application shows the use of attribute-driven autoproxying. In this case,
there's no need to use the TransactionProxyFactoryBean. Simply defining transactional attributes on business objects is
sufficient, because of the use of metadata-aware pointcuts. The bean definitions include the following code, in
/WEB-INF/declarativeServices.xml. Note that this is generic, and can be used outside the jPetStore:
<bean id="autoproxy"
class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
</bean>
<bean id="transactionAttributeSource"
class="org.springframework.transaction.interceptor.AttributesTransactionAttributeSource"
autowire="constructor">
</bean>
<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor"
autowire="byType">
</bean>
<bean id="transactionAdvisor"
class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor"
autowire="constructor" >
</bean>
<bean id="attributes"
class="org.springframework.metadata.commons.CommonsAttributes"
/>
The DefaultAdvisorAutoProxyCreator bean definition--called "advisor" in this case, but the name is not significant--will
pick up all eligible pointcuts in the current application context. In this case, the "transactionAdvisor" bean definition, of type
TransactionAttributeSourceAdvisor, will apply to classes or methods carrying a transaction attribute. The
TransactionAttributeSourceAdvisor depends on a TransactionInterceptor, via constructor dependency. The example resolves this
via autowiring. The AttributesTransactionAttributeSource depends on an implementation of the
org.springframework.metadata.Attributes interface. In this fragement, the "attributes" bean satisfies this, using the
Jakarta Commons Attributes API to obtain attribute information. (The application code must have been compiled using the
Commons Attributes compilation task.)
The TransactionInterceptor defined here depends on a PlatformTransactionManager definition, which is not
included in this generic file (although it could be) because it will be specific to the application's transaction requirements (typically
JTA, as in this example, or Hibernate, JDO or JDBC):
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager"/>
If you require only declarative transaction management, using these generic XML definitions will result in Spring automatically
proxying all classes or methods with transaction attributes. You won't need to work directly with AOP, and the programming model
is similar to that of .NET ServicedComponents.
This mechanism is extensible. It's possible to do autoproxying based on custom attributes. You need to:
● Define your custom attribute.
● Specify an Advisor with the necessary advice, including a pointcut that is triggered by the presence of the custom attribute
on a class or method. You may be able to use an existing advice, merely implementing a static pointcut that picks up the
custom attribute.
It's possible for such advisors to be unique to each advised class (for example, mixins): they simply need to be defined as prototype,
rather than singleton, bean definitions. For example, the LockMixin introduction interceptor from the Spring test suite, shown
above. could be used in conjunction with an attribute-driven pointcut to target a mixin, as shown here. We use the generic
DefaultPointcutAdvisor, configured using JavaBean properties:
<bean id="lockMixin"
class="org.springframework.aop.LockMixin"
singleton="false"
/>
<bean id="lockableAdvisor"
class="org.springframework.aop.support.DefaultPointcutAdvisor"
singleton="false"
>
<property name="pointcut">
<ref local="myAttributeAwarePointcut"/>
</property>
<property name="advice">
<ref local="lockMixin"/>
</property>
</bean>
<bean id="swapper"
class="org.springframework.aop.target.HotSwappableTargetSource">
<constructor-arg><ref local="initialTarget"/></constructor-arg>
</bean>
<bean id="swappable"
class="org.springframework.aop.framework.ProxyFactoryBean"
>
<property name="targetSource">
<ref local="swapper"/>
</property>
</bean>
The above swap() call changes the target of the swappable bean. Clients who hold a reference to that bean will be unaware of the
change, but will immediately start hitting the new target.
Although this example doesn't add any advice--and it's not necessary to add advice to use a TargetSource--of course any
TargetSource can be used in conjunction with arbitrary advice.
<bean id="poolTargetSource"
class="org.springframework.aop.target.CommonsPoolTargetSource">
<property name="targetBeanName"><value>businessObjectTarget</value></property>
<property name="maxSize"><value>25</value></property>
</bean>
<bean id="businessObject"
class="org.springframework.aop.framework.ProxyFactoryBean"
>
<property name="targetSource"><ref local="poolTargetSource"/></property>
<property name="interceptorNames"><value>myInterceptor</value></property>
</bean>
Note that the target object--"businessObjectTarget" in the example--must be a prototype. This allows the
PoolingTargetSource implementation to create new instances of the target to grow the pool as necessary. See the Javadoc
for AbstractPoolingTargetSource and the concrete subclass you wish to use for information about it's properties:
maxSize is the most basic, and always guaranteed to be present.
In this case, "myInterceptor" is the name of an interceptor that would need to be defined in the same IoC context. However, it isn't
5.14. Roadmap
Spring AOP, like the rest of Spring, is actively developed. The core API is stable. Like the rest of Spring, the AOP framework is
very modular, enabling extension while preserving the fundamental design. Several improvements are planned in the Spring 1.1
timeframe, which will preserve backward compatibility. These include:
● Performance improvements: The creation of AOP proxies is handled by a factory via a Strategy interface. Thus we can
support additional AopProxy types without impacting user code or the core implementation. Significant performance
optimizations for CGLIB proxying are scheduled for the 1.0.3 release, with further optimizations by Spring 1.1 in cases
where advice will not change at runtime. This should produce a significant reduction in the overhead of the AOP framework.
Note, however, that the overhead of the AOP framework is not an issue in normal usage.
● More expressive pointcuts: Spring presently offers an expressive Pointcut interface, but we can add value through adding
more Pointcut implementations. We are looking at an integration with AspectJ that will allow AspectJ pointcut expressions
to be used in Spring configuration files. And if you wish to contribute a useful Pointcut, please do!
The most significant enhancements are likely to concern integration with AspectJ, which will be done in cooperation with the
AspectJ community. We believe that this will provide significant benefits for both Spring and AspectJ users, in the following areas:
● Allowing AspectJ aspects to be configured using Spring IoC. This has the potential to integrate AspectJ aspects into
applications where appropriate, in the same way as Spring aspects are integrated into application IoC contexts.
● Allowing the use of AspectJ pointcut expressions within Spring configuration to target Spring advice. This has significant
benefits over devising our own pointcut expression language; AspectJ is both well thought out and well documented.
Both these integrations should be available in Spring 1.1.
Prev Up Next
Chapter 4. PropertyEditors, data binding, Chapter 6. AspectJ Integration
Home
validation and the BeanWrapper
6.2.1.1. Example
Consider a security aspect, which depends on a security manager. This aspects applies to all changes in the value of the
balance instance variable in the Account class. (We couldn't do this in the same way using Spring AOP.)
The AspectJ code for the aspect (one of the Spring/AspectJ samples), is shown below. Note that the dependency on the
SecurityManager interface is expressed in a JavaBean property:
public aspect BalanceChangeSecurityAspect {
before() : balanceChanged() {
this.securityManager.checkAuthorizedToModify();
}
}
We configure this aspect in the same way as an ordinary class. Note that the way in which we set the property reference
is identical. Note that we must use the factory-method attribute to specify that we want the aspect "created" using
the aspectOf() static method. In fact, this is locating, rather than, creating, the aspect, but the Spring container
doesn't care:
<bean id="securityAspect"
class="org.springframework.samples.aspectj.bank.BalanceChangeSecurityAspect"
factory-method="aspectOf"
>
<property name="securityManager">
<ref local="securityManager"/>
</property>
</bean>
We don't need to do anything in Spring configuration to target this aspect. It contains the pointcut information in
AspectJ code that controls where it applies. Thus it can apply even to objects not managed by the Spring IoC container.
to be completed
6.2.3. Gotchas
to be completed
- Singleton issue
This feature replaces our previous plan to create a pointcut expression language for Spring.
Prev Up Next
Chapter 5. Spring AOP: Aspect Oriented Home Chapter 7. Transaction management
Programming with Spring
throws TransactionException;
boolean isNewTransaction();
void setRollbackOnly();
boolean isRollbackOnly();
}
However Spring transaction management is used, defining the PlatformTransactionManager implementation is essential. In
good Spring fashion, this important definition is made using Inversion of Control.
PlatformTransactionManager implementations normally require knowledge of the environment in which they work: JDBC, JTA,
Hibernate etc.
The following examples from dataAccessContext-local.xml from Spring's jPetStore sample application show how a local
PlatformTransactionManager implementation can be defined. This will work with JDBC.
We must define a JDBC DataSource, and then use the Spring DataSourceTransactionManager, giving it a reference to the DataSource.
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager"/>
We can use Hibernate local transactions easily, as shown in the following examples from the Spring PetClinic sample application.
In this case, we need to define a Hibernate LocalSessionFactory, which application code will use to obtain Hibernate Sessions.
The DataSource bean definition will be similar to one of the above examples, and is not shown. (If it's a container DataSource it
should be non-transactional as Spring, rather than the container, will manage transactions.)
The "transactionManager" bean in this case is of class HibernateTransactionManager. In the same way as the
DataSourceTransactionManager needs a reference to the DataSource, the HibernateTransactionManager needs a reference to the
session factory.
<bean id="sessionFactory"
class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
<property name="dataSource"><ref local="dataSource"/></property>
<property name="mappingResources">
<value>org/springframework/samples/petclinic/hibernate/petclinic.hbm.xml</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate.HibernateTransactionManager">
<property name="sessionFactory"><ref local="sessionFactory"/></property>
</bean>
With Hibernate and JTA transactions we could simply use the JtaTransactionManager as with JDBC or any other resource strategy.
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager"/>
Note that this is identical to JTA configuration for any resource, as these are global transactions, which can enlist any transactional
resource.
Application classes wishing to use the TransactionTemplate must have access to a PlatformTransactionManager: usually
exposed as a JavaBean property or as a constructor argument.
It's easy to unit test such classes with a mock or stub PlatformTransactionManager. There's no JNDI lookup or static magic
here: it's a simple interface. As usual, you can use Spring to simplify your unit testing.
try {
// execute your business logic here
} catch (MyException ex) {
transactionManager.rollback(status);
throw ex;
}
transactionManager.commit(status);
class="org.springframework.transaction.interceptor.MatchAlwaysTransactionAttributeSource">
<property
name="transactionAttribute"><value>PROPAGATION_REQUIRED</value></property>
</bean>
<bean id="matchAllTxInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager"><ref bean="transactionManager"/></property>
<property name="transactionAttributeSource"><ref
bean="matchAllWithPropReq"/></property>
</bean>
<!-- One BeanNameAutoProxyCreator handles all beans where we want all methods to
use
PROPAGATION_REQUIRED -->
<bean id="autoProxyCreator"
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="interceptorNames">
<list>
<idref local="matchAllTxInterceptor"/>
<idref bean="hibInterceptor"/>
</list>
</property>
<property name="beanNames">
<list>
<idref local="core-services-applicationControllerSevice"/>
<idref local="core-services-deviceService"/>
<idref local="core-services-authenticationService"/>
<idref local="core-services-packagingMessageHandler"/>
<idref local="core-services-sendEmail"/>
<idref local="core-services-userService"/>
</list>
</property>
</bean>
Assuming that we already have a TransactionManager instance in our ApplicationContext, the first thing we need to do is create
a TransactionInterceptor instance to use. The TransactionInterceptor decides which methods to intercept based on
a TransactionAttributeSource implementing object passed to it as a property. In this case, we want to handle the very
simple case of matching all methods. This is not necessarilly the most efficient approach, but it's very quick to set up, because we can
use the special pre-defined MatchAlwaysTransactionAttributeSource, which simply matches all methods. If we wanted
to be more specific, we could use other variants such as MethodMapTransactionAttributeSource,
Prev Up Next
Chapter 6. AspectJ Integration Home
Chapter 8. Source Level Metadata
Support
<attribute-compiler
destdir="${commons.attributes.tempdir}"
>
<fileset dir="${src.dir}" includes="**/*.java"/>
</attribute-compiler>
</target>
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.
Commons Attributes also provides Maven support. Please refer to Commons Attributes documentation for further information.
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.
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, optional, step, Commons Attributes will create
an index of all the attributes defined on your sources, for efficient lookup at runtime. This step looks as follows:
<attribute-indexer jarFile="myCompiledSources.jar">
<classpath refid="master-classpath"/>
</attribute-indexer>
See the /attributes 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.
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. Commons
Attributes is a static API, while Spring provides a metadata interface that you can easily mock.
8.4.1. Fundamentals
This builds on the Spring AOP autoproxy functionality. Configuration might look like this:
<bean id="autoproxy"
class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
<bean id="transactionAttributeSource"
class="org.springframework.transaction.interceptor.AttributesTransactionAttributeSource"
autowire="constructor">
</bean>
<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor"
autowire="byType">
</bean>
<bean id="transactionAdvisor"
class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor"
autowire="constructor" >
</bean>
<bean id="attributes"
class="org.springframework.metadata.commons.CommonsAttributes"
/>
The basic concepts here should be familiar from the discussion of autoproxying in the AOP chapter.
The most important bean definitions are those named autoproxy and transactionAdvisor. Note that the actual bean names are not important;
what matters is their class.
The autoproxy bean definition of class
org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator will automatically advise
("autoproxy") 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 do know about attributes.
Thus we simply need an AOP advisor that will provide declarative transaction management based on attributes.
It's 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.)
Finally, the attributes bean is the Commons Attributes Attributes implementation. Replace with another implementation of
org.springframework.metadata.Attributes to source attributes from a different source.
8.4.3. Pooling
Again, as with .NET, you can enable pooling behaviour via class-level attributes. Spring can apply this behaviour to any POJO. You simply need
to specify a pooling attribute, as follows, in the business object to be pooled:
/**
* @@org.springframework.aop.framework.autoproxy.target.PoolingAttribute (10)
*
* @author Rod Johnson
*/
public class MyClass {
You'll need the usual autoproxy infrastructure configuration. You then need to specify a pooling TargetSourceCreator, as follows.
Because pooling affects the creation of the target, we can't use a regular advice. Note that pooling will apply even if there are no advisors
applicable to the class, if that class has a pooling attribute.
<bean id="poolingTargetSourceCreator"
class="org.springframework.aop.framework.autoproxy.metadata.AttributesPoolingTargetSourceCreator"
autowire="constructor" >
</bean>
The relevant autoproxy bean definition needs to specify a list of "custom target source creators", including the Pooling target source creator. We
could modify the example shown above to include this property as follows:
<bean id="autoproxy"
class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
>
<property name="customTargetSourceCreators">
<list>
<ref local="poolingTargetSourceCreator" />
</list>
</property>
</bean>
As with the use of metadata in Spring in general, this is a one-off cost: once setup is out of the way, it's very easy to use pooling for additional
business objects.
It's arguable that the need for pooling is rare, so there's seldom a need to apply pooling to a large number of business objects. Hence this
feature does not appear to be used often.
Please see the Javadoc for the org.springframework.aop.framework.autoproxy package for more details. It's possible to use a
different pooling implementation than Commons Pool with minimal custom coding.
}
For this automapping to work, we need to add the following to the relevant xxxx-servlet.xml file, specifying the attributes handler
mapping. This special handler mapping can handle any number of controllers with attributes as shown above. The bean id
("commonsAttributesHandlerMapping") is not important. The type is what matters:
<bean id="commonsAttributesHandlerMapping"
class="org.springframework.web.servlet.handler.metadata.CommonsPathMapHandlerMapping"
/>
We do not currently need an Attributes bean definition, as in the above example, because this class works directly with the Commons Attributes
API, not via the Spring metadata abstraction.
We now need no XML configuration for each controller. Controllers are automatically mapped to the specified URL(s). Controllers benefit from
IoC, using Spring's autowiring capability. For example, the dependency expressed in the "cruncher" bean property of the simple controller
shown above is automatically resolved in the current web application context. Both Setter and Constructor Dependency Injection are available,
each with zero configuration.
An example of Constructor Injection, also showing multiple URL paths:
/**
* Normal comments here
* @author Rod Johnson
*
* @@org.springframework.web.servlet.handler.metadata.PathMap("/foo.cgi")
* @@org.springframework.web.servlet.handler.metadata.PathMap("/baz.cgi")
*/
public class FooController extends AbstractController {
}
This approach has the following benefits:
● Significantly reduced volume of configuration. Each time we add a controller we need add no XML configuration. As with
attribute-driven transaction management, once the basic infrastructure is in place, it is very easy to add more application classes.
● We retain much of the power of Spring IoC to configure controllers.
This approach has the following limitations:
● One-off cost in more complex build process. We need an attribute compilation step and an attribute indexing step. However, once in place,
this should not be an issue.
● Currently Commons Attributes only, although support for other attribute providers may be added in future.
● Only "autowiring by type" dependency injection is supported for such controllers. However, this still leaves them far in advance of Struts
Actions (with no IoC support from the framework) and, arguably, WebWork Actions (with only rudimentary IoC support) where IoC is
concerned.
● Reliance on automagical IoC resolution may be confusing.
Because autowiring by type means there must be exactly one dependency of the specified type, we need to be careful if we use AOP. In the
common case using TransactionProxyFactoryBean, for example, we end up with two implementations of a business interface such as Cruncher:
the original POJO definition, and the transactional AOP proxy. This won't work, as the owning application context can't resolve the type
dependency unambiguously. The solution is to use AOP autoproxying, setting up the autoproxy infrastructure so that there is only one
implementation of Cruncher defined, and that implementation is automatically advised. Thus this approach works well with attribute-targeted
declarative services as described above. As the attributes compilation process must be in place to handle the web controller targeting, this is easy
to set up.
Unlike other metadata functionality, there is currently only a Commons Attributes implementation available:
org.springframework.web.servlet.handler.metadata.CommonsPathMapHandlerMapping. This limitation is due to the fact that not only do we
need attribute compilation, we need attribute indexing: the ability to ask the attributes API for all classes with the PathMap attribute. Indexing is
not currently offered on the org.springframework.metadata.Attributes abstraction interface, although it may be in future. (If you
want to add support for another attributes implementation--which must support indexing--you can easily extend the
AbstractPathMapHandlerMapping superclass of CommonsPathMapHandlerMapping, implementing the two protected abstract
methods to use your preferred attributes API.)
Thus we need two additional steps in the build process: attribute compilation and attribute indexing. Use of the attribute indexer task was shown
above. Note that Commons Attributes presently requires a Jar file as input to indexing.
If you begin with a handler metadata mapping approach, it is possible to switch at any point to a classic Spring XML mapping approach. So you
don't close off this option. For this reason, I find that I often start a web application using metadata mapping.
Prev Up Next
Chapter 7. Transaction management Home Chapter 9. DAO support
Prev Up Next
10.2.2. DataSource
In order to work with data from a database, we need to obtain a connection to the database. The way Spring does this is
through a DataSource. A DataSource is part of the JDBC specification and can be seen as a generalized connection
factory. It allows a container or a framework to hide connection pooling and transaction management issues from the
application code. As a developer, you don't need to know any details about how to connect to the database, that is the
responsibility for the administrator that sets up the datasource. You will most likely have to fulfil both roles while you are
developing and testing you code though, but you will not necessarily have to know how the production data source is
configured.
When using Spring's JDBC layer, you can either obtain a data source from JNDI or you can configure your own, using an
implementation that is provided in the Spring distribution. The latter comes in handy for unit testing outside of a web
container. We will use the DriverManagerDataSource implementation for this section but there are several additional
implementations that will be covered later on. The DriverManagerDataSource works the same way that you probably
are used to work when you obtain a JDBC connection. You have to specify the fully qualified class name of the JDBC driver
that you are using so that the DriverManager can load the driver class. Then you have to provide a url that varies between
JDBC drivers. You have to consult the documentation for your driver for the correct value to use here. Finally you must
provide a username and a password that will be used to connect to the database. Here is an example of how to configure a
DriverManagerDataSource:
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName( "org.hsqldb.jdbcDriver");
dataSource.setUrl( "jdbc:hsqldb:hsql://localhost:");
dataSource.setUsername( "sa");
dataSource.setPassword( "");
10.2.3. SQLExceptionTranslator
SQLExceptionTranslator is an interface to be implemented by classes that can translate between SQLExceptions and
our data access strategy-agnostic org.springframework.dao.DataAccessException.
Implementations can be generic (for example, using SQLState codes for JDBC) or proprietary (for example, using Oracle error
codes) for greater precision.
SQLErrorCodeSQLExceptionTranslator is the implementation of SQLExceptionTranslator that is used by default.
This implementation uses specific vendor codes. More precise than SQLState implementation, but vendor specific. The error
code translations are based on codes held in a JavaBean type class named SQLErrorCodes. This class is created and
populated by an SQLErrorCodesFactory which as the name suggests is a factory for creating SQLErrorCodes based
on the contents of a configuration file named "sql-error-codes.xml". This file is populated with vendor codes and based on the
DatabaseProductName taken from the DatabaseMetaData, the codes for the current database are used.
The SQLErrorCodeSQLExceptionTranslator applies the following matching rules:
● Try custom translation implemented by any subclass. Note that this class is concrete and is typically used itself, in which
case this rule doesn't apply.
● Apply error code matching. Error codes are obtained from the SQLErrorCodesFactory by default. This looks up error
codes from the classpath and keys into them from the database name from the database metadata.
● Use the fallback translator. SQLStateSQLExceptionTranslator is the default fallback translator.
SQLErrorCodeSQLExceptionTranslator can be extended the following way:
public class MySQLErrorCodesTransalator extends SQLErrorCodeSQLExceptionTranslator {
protected DataAccessException customTranslate(String task, String sql,
SQLException sqlex) {
if (sqlex.getErrorCode() == -12345)
return new DeadlockLoserDataAccessException(task, sqlex);
return null;
}
}
In this example the specific error code '-12345' is translated and any other errors are simply left to be translated by the default
translator implementation. To use this custom translator, it is necessary to pass it to the JdbcTemplate using the method
setExceptionTranslator and to use this JdbcTemplate for all of the data access processing where this translator is
needed. Here is an example of how this custom translator can be used:
// create a JdbcTemplate and set data source
JdbcTemplate jt = new JdbcTemplate();
jt.setDataSource(dataSource);
// create a custom translator and set the datasource for the default translation
lookup
MySQLErrorCodesTransalator tr = new MySQLErrorCodesTransalator();
tr.setDataSource(dataSource);
jt.setExceptionTranslator(tr);
// use the JdbcTemplate for this SqlUpdate
SqlUpdate su = new SqlUpdate();
su.setJdbcTemplate(jt);
su.setSql("update orders set shipping_charge = shipping_charge * 1.05");
su.compile();
su.update();
The custom translator is passed a data source because we still want the default translation to look up the error codes in
sql-error-codes.xml.
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.JdbcTemplate;
10.3.2. SmartDataSource
Interface to be implemented by classes that can provide a connection to a relational database. Extends the
javax.sql.DataSource interface to allow classes using it to query whether or not the connection should be closed after a
given operation. This can sometimes be useful for efficiency, if we know that we want to reuse a connection.
10.3.3. AbstractDataSource
Abstract base class for Spring's DataSource implementations, taking care of the "uninteresting" glue. This is the class you
would extend if you are writing your own DataSource implementation.
10.3.4. SingleConnectionDataSource
Implementation of SmartDataSource that wraps a single connection which is not closed after use. Obviously, this is not
multi-threading capable.
If client code will call close in the assumption of a pooled connection, like when using persistence tools, set
suppressClose to true. This will return a close-suppressing proxy instead of the physical connection. Be aware that you
will not be able to cast this to a native Oracle Connection or the like anymore.
This is primarily a test class. For example, it enables easy testing of code outside an application server, in conjunction with a
simple JNDI environment. In contrast to DriverManagerDataSource, it reuses the same connection all the time,
avoiding excessive creation of physical connections.
10.3.5. DriverManagerDataSource
Implementation of SmartDataSource that configures a plain old JDBC Driver via bean properties, and returns a new
connection every time.
Useful for test or standalone environments outside of a J2EE container, either as a DataSource bean in a respective
ApplicationContext, or in conjunction with a simple JNDI environment. Pool-assuming Connection.close() calls will
simply close the connection, so any DataSource-aware persistence code should work.
10.3.6. DataSourceTransactionManager
PlatformTransactionManager implementation for single JDBC data sources. Binds a JDBC connection from the specified data
source to the thread, potentially allowing for one thread connection per data source.
Application code is required to retrieve the JDBC connection via DataSourceUtils.getConnection(DataSource)
instead of J2EE's standard DataSource.getConnection. This is recommended anyway, as it throws unchecked
org.springframework.dao exceptions instead of checked SQLException. All framework classes like
JdbcTemplate use this strategy implicitly. If not used with this transaction manager, the lookup strategy behaves exactly
like the common one - it can thus be used in any case.
Supports custom isolation levels, and timeouts that get applied as appropriate JDBC statement query timeouts. To support the
latter, application code must either use JdbcTemplate or call DataSourceUtils.applyTransactionTimeout
method for each created statement.
This implementation can be used instead of JtaTransactionManager in the single resource case, as it does not require
the container to support JTA. Switching between both is just a matter of configuration, if you stick to the required connection
lookup pattern. Note that JTA does not support custom isolation levels!
10.4.1. SqlQuery
Reusable threadsafe object to represent an SQL query. Subclasses must implement the newResultReader() method to provide
an object that can save the results while iterating over the ResultSet. This class is rarely used directly since the
MappingSqlQuery, that extends this class, provides a much more convenient implementation for mapping rows to Java
classes. Other implementations that extend SqlQuery are MappingSqlQueryWithParameters and
UpdatableSqlQuery.
10.4.2. MappingSqlQuery
MappingSqlQuery is a reusable query in which concrete subclasses must implement the abstract mapRow(ResultSet,
int) method to convert each row of the JDBC ResultSet into an object.
Of all the SqlQuery implementations, this is the one used most often and it is also the one that is the easiest to use.
Here is a brief example of a custom query that maps the data from the customer table to a Java object called Customer.
private class CustomerMappingQuery extends MappingSqlQuery {
public CustomerMappingQuery(DataSource ds) {
super(ds, "SELECT id, name FROM customer WHERE id = ?");
super.declareParameter(new SqlParameter("id", Types.INTEGER));
compile();
}
public Object mapRow(ResultSet rs, int rowNumber) throws SQLException {
Customer cust = new Customer();
cust.setId((Integer) rs.getObject("id"));
cust.setName(rs.getString("name"));
return cust;
}
}
We provide a constructor for this customer query that takes the DataSource as the only parameter. In this constructor we
call the constructor on the superclass with the DataSource and the SQL that should be executed to retrieve the rows for this
query. This SQL will be used to create a PreparedStatement so it may contain place holders for any parameters to be
passed in during execution. Each parameter must be declared using the declareParameter method passing in an
SqlParameter. The SqlParameter takes a name and the JDBC type as defined in java.sql.Types. After all
parameters have been defined we call the compile method so the statement can be prepared and later be executed.
Let's take a look at the code where this custom query is instantiated and executed:
public Customer getCustomer(Integer id) {
CustomerMappingQuery custQry = new CustomerMappingQuery(dataSource);
Object[] parms = new Object[1];
parms[0] = id;
List customers = custQry.execute(parms);
if (customers.size() > 0)
return (Customer) customers.get(0);
else
return null;
}
The method in this example retrieves the customer with the id that is passed in as the only parameter. After creating an
instance of the CustomerMappingQuery class we create an array of objects that will contain all parameters that are passed
in. In this case there is only one parameter and it is passed in as an Integer. Now we are ready to execute the query using
this array of parameters and we get a List that contains a Customer object for each row that was returned for our query. In
this case it will only be one entry if there was a match.
10.4.3. SqlUpdate
RdbmsOperation subclass representing a SQL update. Like a query, an update object is reusable. Like all RdbmsOperation
objects, an update can have parameters and is defined in SQL.
This class provides a number of update() methods analogous to the execute() methods of query objects.
This class is concrete. Although it can be subclassed (for example to add a custom update method) it can easily be
parameterized by setting SQL and declaring parameters.
import java.sql.Types;
import javax.sql.DataSource;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.object.SqlUpdate;
/**
* @param id for the Customer to be updated
* @param rating the new value for credit rating
* @return number of rows updated
*/
public int run(int id, int rating) {
Object[] params =
new Object[] {
new Integer(rating),
new Integer(id)};
return update(params);
}
}
10.4.4. StoredProcedure
Superclass for object abstractions of RDBMS stored procedures. This class is abstract and its execute methods are protected,
preventing use other than through a subclass that offers tighter typing.
The inherited sql property is the name of the stored procedure in the RDBMS. Note that JDBC 3.0 introduces named
parameters, although the other features provided by this class are still necessary in JDBC 3.0.
Here is an example of a program that calls a function sysdate() that comes with any Oracle database. To use the stored
procedure functionality you have to create a class that extends StoredProcedure. There are no input parameters, but there
is an output parameter that is declared as a date using the class SqlOutParameter. The execute() method returns a map
with an entry for each declared output parameter using the parameter name as the key.
import java.sql.Types;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.jdbc.core.SqlOutParameter;
import org.springframework.jdbc.datasource.*;
import org.springframework.jdbc.object.StoredProcedure;
void test() {
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("oracle.jdbc.driver.OracleDriver");
ds.setUrl("jdbc:oracle:thin:@localhost:1521:mydb");
ds.setUsername("scott");
ds.setPassword("tiger");
setDataSource(ds);
setFunction(true);
setSql(SQL);
declareParameter(new SqlOutParameter("date", Types.DATE));
compile();
}
10.4.5. SqlFunction
SQL "function" wrapper for a query that returns a single row of results. The default behavior is to return an int, but that can be
overridden by using the methods with an extra return type parameter. This is similar to using the queryForXxx methods of
the JdbcTemplate. The advantage with SqlFunction is that you don't have to create the JdbcTemplate, it is done
behind the scenes.
This class is intended to use to call SQL functions that return a single result using a query like "select user()" or "select sysdate
from dual". It is not intended for calling more complex stored functions or for using a CallableStatement to invoke a
stored procedure or stored function. Use StoredProcedure or SqlCall for this type of processing.
This is a concrete class, which there is normally no need to subclass. Code using this package can create an object of this type,
declaring SQL and parameters, and then invoke the appropriate run method repeatedly to execute the function. Here is an
example of retrieving the count of rows from a table:
public int countRows() {
SqlFunction sf = new SqlFunction(dataSource, "select count(*) from mytable");
sf.compile();
return sf.run();
}
Prev Up Next
Chapter 9. DAO support Chapter 11. Data Access using O/R
Home
Mappers
11.2. Hibernate
11.2.1. Resource Management
Typical business applications are often cluttered with repetitive resource management code. Many projects try to invent their own
solutions for this issue, sometimes sacrificing proper handling of failures for programming convenience. Spring advocates
strikingly simple solutions for proper resource handling: Inversion of control via templating, i.e. infrastructure classes with
callback interfaces, or applying AOP interceptors. The infrastructure cares for proper resource handling, and for appropriate
conversion of specific API exceptions to an unchecked infrastructure exception hierarchy. Spring introduces a DAO exception
hierarchy, applicable to any data access strategy. For direct JDBC, the JdbcTemplate class mentioned in a previous section
cares for connection handling, and for proper conversion of SQLException to the DataAccessException hierarchy,
including translation of database-specific SQL error codes to meaningful exception classes. It supports both JTA and JDBC
transactions, via respective Spring transaction managers. Spring also offers Hibernate and JDO support, consisting of a
HibernateTemplate / JdoTemplate analogous to JdbcTemplate, a HibernateInterceptor /
JdoInterceptor, and a Hibernate / JDO transaction manager. The major goal is to allow for clear application layering, with
any data access and transaction technology, and for loose coupling of application objects. No more business object dependencies
on the data access or transaction strategy, no more hard-coded resource lookups, no more hard-to-replace singletons, no more
custom service registries. One simple and consistent approach to wiring up application objects, keeping them as reusable and free
from container dependencies as possible. All the individual data access features are usable on their own but integrate nicely with
Spring's application context concept, providing XML-based configuration and cross-referencing of plain JavaBean instances that
don't need to be Spring-aware. In a typical Spring app, many important objects are JavaBeans: data access templates, data access
objects (that use the templates), transaction managers, business objects (that use the data access objects and transaction
managers), web view resolvers, web controllers (that use the business objects), etc.
<bean id="mySessionFactory"
class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
<property name="mappingResources">
<list>
<value>product.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop
key="hibernate.dialect">net.sf.hibernate.dialect.MySQLDialect</prop>
...
</beans>
Note that switching from a JNDI-located DataSource to a locally defined one like a Jakarta Commons DBCP
BasicDataSource is just a matter of configuration:
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName">
<value>org.hsqldb.jdbcDriver</value>
</property>
<property name="url">
<value>jdbc:hsqldb:hsql://localhost:9001</value>
</property>
<property name="username">
<value>sa</value>
</property>
<property name="password">
<value></value>
</property>
</bean>
You can also use a JNDI-located SessionFactory, but that's typically not necessary outside an EJB context (see the
"container resources vs local resources" section for a discussion).
...
</beans>
public class ProductDaoImpl implements ProductDao {
...
<bean id="myHibernateInterceptor"
class="org.springframework.orm.hibernate.HibernateInterceptor">
<property name="sessionFactory">
<ref bean="mySessionFactory"/>
</property>
</bean>
<bean id="myProductDao"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>product.ProductDao</value>
</property>
<property name="interceptorNames">
<list>
<value>myHibernateInterceptor</value>
<value>myProductDaoTarget</value>
</list>
</property>
</bean>
...
</beans>
public class ProductDaoImpl extends HibernateDaoSupport implements ProductDao {
...
<bean id="myTransactionManager"
class="org.springframework.orm.hibernate.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="mySessionFactory"/>
</property>
</bean>
</beans>
public class ProductServiceImpl implements ProductService {
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
transactionTemplate.execute(
new TransactionCallbackWithoutResult() {
public void doInTransactionWithoutResult(TransactionStatus status) {
List productsToChange =
productDAO.loadProductsByCategory(category);
...
}
}
);
}
}
...
<bean id="myTransactionManager"
class="org.springframework.orm.hibernate.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="mySessionFactory"/>
</property>
</bean>
<bean id="myTransactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager">
<ref bean="myTransactionManager"/>
</property>
<property name="transactionAttributeSource">
<value>
product.ProductService.increasePrice*=PROPAGATION_REQUIRED
product.ProductService.someOtherBusinessMethod=PROPAGATION_MANDATORY
</value>
</property>
</bean>
<bean id="myProductService"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>product.ProductService</value>
</property>
<property name="interceptorNames">
<list>
<value>myTransactionInterceptor</value>
<value>myProductServiceTarget</value>
</list>
</property>
</bean>
</beans>
public class ProductServiceImpl implements ProductService {
...
}
As with HibernateInterceptor, TransactionInterceptor allows any checked application exception to be thrown
with the callback code, while TransactionTemplate is restricted to unchecked exceptions within the callback.
TransactionTemplate will trigger a rollback in case of an unchecked application exception, or if the transaction has been
marked rollback-only by the application (via TransactionStatus). TransactionInterceptor behaves the same way
by default but allows configurable rollback policies per method. A convenient alternative way of setting up declarative
transactions is TransactionProxyFactoryBean, particularly if there are no other AOP interceptors involved.
TransactionProxyFactoryBean combines the proxy definition itself with transaction configuration for a particular target
bean. This reduces the configuration effort to one target bean plus one proxy bean. Furthermore, you do not need to specify which
interfaces or classes the transactional methods are defined in.
<beans>
...
<bean id="myTransactionManager"
class="org.springframework.orm.hibernate.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="mySessionFactory"/>
</property>
</bean>
<bean id="myProductService"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="myTransactionManager"/>
</property>
<property name="target">
<ref bean="myProductServiceTarget"/>
</property>
<property name="transactionAttributes">
<props>
<prop key="increasePrice*">PROPAGATION_REQUIRED</prop>
<prop key="someOtherBusinessMethod">PROPAGATION_MANDATORY</prop>
</props>
</property>
</bean>
</beans>
<bean id="mySessionFactory1"
class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
<property name="mappingResources">
<list>
<value>product.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop
key="hibernate.dialect">net.sf.hibernate.dialect.MySQLDialect</prop>
</props>
</property>
<property name="dataSource">
<ref bean="myDataSource1"/>
</property>
</bean>
<bean id="mySessionFactory2"
class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
<property name="mappingResources">
<list>
<value>inventory.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<bean id="myTransactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager"/>
<bean id="myProductService"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="myTransactionManager"/>
</property>
<property name="target">
<ref bean="myProductServiceTarget"/>
</property>
<property name="transactionAttributes">
<props>
<prop key="increasePrice*">PROPAGATION_REQUIRED</prop>
<prop key="someOtherBusinessMethod">PROPAGATION_MANDATORY</prop>
</props>
</property>
</bean>
</beans>
Both HibernateTransactionManager and JtaTransactionManager allow for proper JVM-level cache handling
with Hibernate - without container-specific transaction manager lookup or JCA connector (as long as not using EJB to initiate
transactions). Additionally, HibernateTransactionManager can export the JDBC Connection used by Hibernate to plain
JDBC access code. This allows for high level transaction demarcation with mixed Hibernate/JDBC data access completely
without JTA, as long as just accessing one database!
Note, for an alternative approach to using TransactionProxyFactoryBean to declaratively demarcate transactions, please
see Section 7.4.1, BeanNameAutoProxyCreator, another declarative approach .
11.2.9. Samples
The Petclinic sample in the Spring distribution offers alternative DAO implementations and application context configurations for
Hibernate, JDBC, and Apache OJB. Petclinic can therefore serve as working sample app that illustrates the use of Hibernate in a
Spring web app. It also leverages declarative transaction demarcation with different transaction strategies.
11.3. JDO
ToDo
11.4. iBATIS
Through the org.springframework.orm.ibatis package, Spring supports iBATIS SqlMaps 1.3.x and 2.0. The iBATIS
support much resembles Hibernate support in that it supports the same template style programming and just as with Hibernate,
iBatis support works with Spring's exception hierarchy and let's you enjoy the all IoC features Spring has.
<sql-map name="Account">
<result-map name="result" class="examples.Account">
<property name="name" column="NAME" columnIndex="1"/>
<property name="email" column="EMAIL" columnIndex="2"/>
</result-map>
<mapped-statement name="insertAccount">
insert into ACCOUNT (NAME, EMAIL) values (#name#, #email#)
</mapped-statement>
</sql-map>
After having defined the Sql Map, we have to create a configuration file for iBATIS (sqlmap-config.xml):
<sql-map-config>
<sql-map resource="example/Account.xml"/>
</sql-map-config>
iBATIS loads resources from the classpath so be sure to add the Account.xml file to the classpath somewhere.
Using Spring, we can now very easily set up the SqlMap, using the SqlMapFactoryBean:
<!-- for more information about using datasource, have a look at the JDBC chapter -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property
name="driverClassName"><value>${jdbc.driverClassName}</value></property>
<property name="url"><value>${jdbc.url}</value></property>
<property name="username"><value>${jdbc.username}</value></property>
<property name="password"><value>${jdbc.password}</value></property>
</bean>
Prev Up Next
Chapter 10. Data Access using JDBC Home Chapter 12. Web framework
and/or data access tier, even if you just want to use e.g. the transaction abstraction with JDBC or Hibernate.
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>example</servlet-name>
<url-pattern>*.form</url-pattern>
</servlet-mapping>
</web-app>
In the example above, all requests ending with .form will be handled by the DispatcherServlet. Then, the DispatcherServlet
needs to be configured. As illustrated in Section 3.10, Introduction to the ApplicationContext , ApplicationContexts in Spring
can be scoped. In the web framework, each DispatcherServlet has its own WebApplicationContext, which contains the
DispatcherServlet configuration beans. The default BeanFactory used by the DispatcherServlet is the XmlBeanFactory and
the DispatcherServlet will on initialization look for a file named [servlet-name]-servlet.xml in the WEB-INF
directory of your web application. The default values used by the DispatcherServlet can be modified by using the servlet
initialization parameters (see below for more information).
The WebApplicationContext is just an ordinary ApplicationContext that has some extra features necessary for
webapplications. It differs from a normal ApplicationContext in that it is capable of resolving themes (see Section 12.7, Using
themes ), and that is knows to which servlet it is associated (by having a link to the ServletContext). The
WebApplicationContext is bound in the ServletContext, and using RequestContextUtils you can always lookup the
WebApplicationContext in case you need it.
The Spring DispatcherServlet has a couple of special beans it uses, in order to be able to process requests and render the
appropriate views. Those beans are included in the Spring framework and (optionally) have to be configured in the
WebApplicationContext, just as any other bean would have to be configured. Each of those beans, is described in more detail
below. Right now, we'll just mention them, just to let you know they exist and to enable us to go on talking about the
DispatcherServlet. For most of the beans, defaults are provided so you don't have to worry about those.
Table 12.1. Special beans in the WebApplicationContext
Expression Explanation
(Section 12.4, Handler mappings ) a list of pre- and postprocessors and controllers that will be
handler mapping(s)
executed if they match certain criteria (for instance a matching URL specified with the controller)
(Section 12.3, Controllers ) the beans providing the actual functionality (or at least, access to the
controller(s)
functionality) as part of the MVC triad
(Section 12.5, Views and resolving them ) capable of resolving view names and needed by the
view resolver
DispatcherServlet to resolves those views with
(Section 12.6, Using locales ) capable of resolves the locale a client is using, in order to be able to
locale resolver
offer internationalized views
(Section 12.7, Using themes ) capable of resolving themes your webapplication can use e.g. to
theme resolver
offer personalized layouts
(Section 12.8, Spring's multipart (fileupload) support ) offers functionality to process file uploads
multipart resolver
from HTML forms
(Section 12.9, Handling exceptions ) offers functionality to map exceptions to views or implement
handlerexception resolver
other more complex exception handling code
When a DispatcherServlet is setup for use and a request comes in for that specific DispatcherServlet it starts processing it. The
list below describes the complete process a request goes through if a DispatcherServlet is supposed to handle it:
1. The WebApplicationContext is searched for and bound in the request as an attribute in order for controller and other
elements in the chain of process to use it. It is bound by default under the key
DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE
2. The locale resolver is bound to the request to let elements in the chain resolve the locale to use when processing the
request (rendering the view, preparing data, etcetera). If you don't use the resolver, it won't affect anything, so if you
don't need locale resolving, just don't bother
3. The theme resolver is bound to the request to let e.g. views determine which theme to use (if you don't needs themes,
don't bother, the resolver is just bound and does not affect anything if you don't use it)
4. If a multipart resolver is specified, the request is inspected for multiparts and if so, it is wrapped in a
MultipartHttpServletRequest for further processing by other elements in the chain (more information about
multipart handling is provided below)
5. An appropriate handler is searched for. If a handler is found, it execution chain associated to the handler (preprocessors,
postprocessors, controllers) will be executed in order to prepare a model
6. If a model is returned, the view is rendered, using the view resolver that has been configured with the
WebApplicationContext. If no model was returned (which could be the result of a pre- or postprocessor intercepting the
request because of for instance security reasons), no view is rendered as well, since the request could already have been
fulfilled
Exceptions that might be thrown during processing of the request get picked up by any of the handlerexception resolvers that
are declared in the WebApplicationContext. Using those exception resolvers you can define custom behavior in case such
exceptions get thrown.
The Spring DispatcherServlet also has support for returning the last-modification-date, as specified by the Servlet API. The
process of determining the last modification date for a specific request, is simple. The DispatcherServlet will first of all lookup
an appropriate handler mapping and test if the handler that matched implements the interface LastModified and if so, the
value the of long getLastModified(request) is returned to the client.
You can customize Spring's DispatcherServlet by adding context parameters in the web.xml file or servlet init parameters.
The possibilities are listed below.
Table 12.2. DispatcherServlet initialization parameters
Parameter Explanation
Class that implements WebApplicationContext, which will be used to instantiate the
contextClass context used by this servlet. If this parameter isn't specified, the
XmlWebApplicationContext will be used
String which is passed to the context instance (specified by contextClass) to indicate
where context(s) can be found. The String is potentially split up into multiple strings (using a
contextConfigLocation
comma as a delimiter) to support multiple contexts (in case of multiple context locations, of
beans that are defined twice, the latest takes precedence)
the namespace of the WebApplicationContext. Defaults to
namespace
[server-name]-servlet
12.3. Controllers
The notion of controller is part of the MVC design pattern. Controllers define application behavior, or at least provide users
with access to the application behavior. Controllers interpret user input and transform the user input into a sensible model
which will be represented to the user by the view. Spring has implemented the notion of a controller in a very abstract way
enabling a wide variety of different kinds of controllers to be created. Spring contains formcontroller, commandcontroller,
controllers that execute wizard-style logic and more.
Spring's basis for the controller architecture is the org.springframework.mvc.Controller interface, which is listed
below.
public interface Controller {
/**
* Process the request and return a ModelAndView object which the
DispatcherServlet
* will render.
*/
ModelAndView handleRequest(
HttpServletRequest request,
HttpServletResponse response)
throws Exception;
}
As you can see, the Controller interface just states one single method that should be capable of handling a request and return an
appropriate model and view. Those three concepts are the basis for the Spring MVC implemente; ModelAndView and
Controller. While the Controller interface is quite abstract, Spring offers a lot of controllers that already contain a lot of
functionality you might need. The controller interface just define the most commons functionality offered by every controller:
the functionality of handling a request and returning a model and a view.
the last two properties are actually part of the WebContentGenerator which is the superclass of
AbstractController but to keeps things clear...
When using the AbstractController as a baseclass for your controllers (which is not recommended since there are a lot of other
controller that might already do the job for your) you only have to override the
handleRequestInternal(HttpServletRequest, HttpServletResponse)-method and implement your
logic code and return a ModelAndView object there. A short example consisting of a class and a declaration in the
webapplicationcontext.
package samples;
directives telling the client to cache things for 2 minutes before rechecking. This controller furthermore returns an hard-coded
view (hmm, not so nice), named index (see Section 12.5, Views and resolving them for more information about views).
Methods defined for a multi-action controller will need to conform to the following signature:
// actionName can be replaced by any methodname
ModelAndView actionName(HttpServletRequest, HttpServletResponse);
Method overloading is not allowed since it'll confuse the MultiActionController. Furthermore, you can define exception
handlers capable of handling exception that will be thrown form a method you specify. Exception handler methods need to
return a ModelAndView object, just as any other action method and will need to conform to the following signature:
// anyMeaningfulName can be replaced by any methodname
ModelAndView anyMeaningfulName(HttpServletRequest, HttpServletResponse,
ExceptionClass);
The ExceptionClass can be any exception, as long as it's a subclass of java.lang.Exception or
java.lang.RuntimeException.
The MethodNameResolver is supposed to resolve method names based on the request coming in. There are three resolver
to your disposal, but of course you can implement more of them yourself if you want.
● ParameterMethodNameResolver - capable of resolving a request parameter and using that as the method name
(http://www.sf.net/index.view?testParam=testIt will result in a method
testIt(HttpServletRequest, HttpServletResponse) being called). Use the paramName
configuration parameter to tweak the parameter that's inspected)
● InternalPathMethodNameResolver - retrieves the filename from the path and uses that as the method name
A couple of examples. First of all one showing the ParameterMethodNameResolver and the delegate property, which
will accept requests to urls with the parameter method included and set to retrieveIndex:
<bean id="paramResolver" class="org....mvc.multiaction.ParameterMethodNameResolver">
<property name="paramName"><value>method</value></property>
</bean>
## together with
12.3.4. CommandControllers
Spring's CommandControllers are a fundamental part of the Spring MVC package. Command controllers provide a way to
interact with dataobjects and dynamically bind parameters from the HttpServletRequest to the dataobject you're
specifying. This compares to Struts's actionforms, where in Spring, you don't have to implement any interface of superclasses
to do databinding. First, let's examine what command controllers available, just to get clear picture of what you can do with
them:
● AbstractCommandController - a command controller you can use to create your own command controller,
capable of binding request parameters to a data object you're specifying. This class does not offer form functionality, it
does however, offer validation features and lets you specify in the controller itself what to do with the dataobject that has
been filled with the parameters from the request.
● AbstractFormController - an abstract controller offering form submission support. Using this controller you can
model forms and populate them using a dataobject you're retrieving in the controller. After a user has filled the form, the
AbstractFormController binds the fields, validates and hands the object back to you - the controller - to take appropriate
action. Supported features are invalid form submission (resubmission), validation, and the right workflow a form always
has. What views you tie to your AbstractFormController you decide yourself. Use this controller if you need forms, but
don't want to specify what views you're going to show the user in the applicationcontext
● SimpleFormController - an even more concrete FormCotnroller that helps you creating a form with
corresponding data object even more. The SimpleFormController let's you specify a command object, a viewname for
the form, a viewname for page you want to show the user when formsubmission has succeeded, and more
● AbstractWizardFormController - as the class name suggests, this is an abstract class--your WizardController
should extend it. This means you have to implement both the validatePage(), processFinish as well as
processCancel methods.
Probably you also want to write a contractor, which should at the very least call setPages() and
setCommandName(). The former takes as its argument an array of type String. This array is the list of views which
comprise your wizard. The latter takes as its argument a String, which will be used to refer to your Command object
from within your views.
As with any instance of AbstractFormController, you are required to use a Command object - a JavaBean which will be
populated with the data from your forms. You can do this in one of two ways: either call setCommandClass() from
the constructor with the class of your command object, or implement the formBackingObject() method.
AbstractWizardFormController has a number of concrete methods that you may wish to override. Of these, the ones you
are likely to find most useful are: referenceData which you can use to pass model data to your view in the form of
a Map; getTargetPage if your wizard needs to change page order or omit pages dynamically; and
onBindAndValidate if you want to override the built-in binding and validation workflow.
Finally, it is worth pointing out the setAllowDirtyBack and setAllowDirtyForward, which you can call
from getTargetPage to allow users to move backwards and forwards in the wizard even if validation fails for the
current page.
For a full list of methods, see the JavaDoc for AbstractWizardFormController. There is an implemented example of this
wizard in the jPetStore included in the Spring distribution:
org.springframework.samples.jpetstore.web.spring.OrderFormController.java
contain is a list of handler interceptor that should be applied to the request. When a request comes in, the
DispatcherServlet will hand it over to the handler mapping to let it inspect the request and come up with an appropriate
HandlerExecutionChain. When done, the DispatcherServlet will execute the handler and interceptors in the chain (if any).
The concept of configurable handler mappings that can optionally contain interceptors (executed before or after the actual
handler was executed, or both) is extremely powerful. A lot of supporting functionality can be built-in in custom
HandlerMappings. Think of a custom handler mapping that chooses a handler not only based on the URL of the request
coming in, but also on a specific state of the session associated with the request.
Let's examine the handler mappings that Spring provides.
12.4.1. BeanNameUrlHandlerMapping
A very simple, but very powerful handlermapping is the BeanNameUrlHandlerMapping, which maps incoming HTTP
requests to names of beans, defined in the webapplicationcontext. Let's say we want to enable a user to insert an account and
we've already provided an appropriate FormController (see Section 12.3.4, CommandControllers for more information on
Command- and FormControllers) and a JSP view (or Velocity template) that renders the form. When using the
BeanNameUrlHandlerMapping, we could map the HTTP request with URL
http://samples.com/editaccount.form to the appropriate FormController as follows:
<beans>
<bean id="handlerMapping"
class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<bean name="/editaccount.form"
class="org.springframework.web.servlet.mvc.SimpleFormController">
<property name="formView"><value>account</value></property>
<property name="successView"><value>account-created</value></property>
<property name="commandName"><value>Account</value></property>
<property name="commandClass"><value>samples.Account</value></property>
</bean>
<beans>
All incoming requests for the URL /editaccount.form will now be handled by the FormController in the source listing
above. Of course we have to define a servlet-mapping in web.xml as well, to let through all the requests ending with .form.
<web-app>
...
<servlet>
<servlet-name>sample</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
12.4.2. SimpleUrlHandlerMapping
Another - and much more powerful handlermapping - is the SimpleUrlHandlerMapping. This mapping is configurable
in the applicationcontext and has Ant-style pathmatching capabilities (see Section 12.10.1, A little story about the pathmatcher
). A couple of example will probably makes thing clear enough:
<web-app>
...
<servlet>
<servlet-name>sample</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<bean id="someViewController"
class="org.springframework.web.servlet.mvc.UrlFilenameViewController"/>
<bean id="editAccountFormController"
class="org.springframework.web.servlet.mvc.SimpleFormController">
<property name="formView"><value>account</value></property>
<property name="successView"><value>account-created</value></property>
<property name="commandName"><value>Account</value></property>
<property name="commandClass"><value>samples.Account</value></property>
</bean>
<beans>
This handlermapping first of all reroutes all requests in all directories for a file named help.html to the
someViewController, which is a UrlFilenameViewController (more about that can be found in Section 12.3, Controllers
). Also, all requests for a resource beginning with view, ending with .html, in the directory ex, will be rerouted to that
specific controller. Furthermore, two mappings have been defined that will match with the
editAccountFormController.
<bean id="officeHoursInterceptor"
class="samples.TimeBasedAccessInterceptor">
<property name="openingTime"><value>9</value></property>
<property name="closingTime"><value>18</value></property>
</bean>
<beans>
package samples;
HttpServletRequest request,
HttpServletResponse response,
Object handler)
throws Exception {
Calendar cal = Calendar.getInstance();
int hour = cal.get(HOUR_OF_DAY);
if (openingTime <= hour < closingTime) {
return true;
} else {
response.sendRedirect("http://host.com/outsideOfficeHours.html");
return false;
}
}
}
Any request coming in, will be intercepted by the TimeBasedAccessInterceptor, and if the current time is outside
office hours, the user will be redirect to a static html file, saying for instance he can only access the website during office
hours.
As you can see, Spring has an adapter to make it easy for you to extend the HandlerInterceptor.
12.5.1. ViewResolvers
As discussed before, all controllers in the SpringWeb framework, return a ModelAndView instance. Views in Spring are
addressed by a view name and are resolved by a viewresolver. Spring comes with quite a few view resolvers. We'll list most of
them and then provide a couple of examples.
Table 12.5. View resolvers
ViewResolver Description
Abstract view resolver taking care of caching views. Lots of views need
AbstractCachingViewResolver preparation before they can be used, extending from this viewresolver
enables caching of views
Implementation of ViewResolver that accepts a config file written in
XmlViewResolver
XML to the same DTD as Spring's bean factories
Implementation of ViewResolver that uses bean definitions in a
ResourceBundleViewResolver ResourceBundle, specified by the bundle basename. The bundle is
typically defined in a properties file, located in the classpath
Simple implementation of ViewResolver that allows for direct resolution
of symbolic view names to URLs, without an explicit mapping definition.
UrlBasedViewResolver This is appropriate if your symbolic names match the names of your view
resources in a straightforward manner, without the need for arbitrary
mappings
As an example, when using JSP for a view technology you can use the the UrlBasedViewResolver. This view resolver
translates view names to a URL and hands the request over the RequestDispatcher to render the view.
<bean id="viewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="prefix"><value>/WEB-INF/jsp/</value></property>
<property name="suffix"><value>.jsp</value></property>
</bean>
When returning test as a viewname, this view resolver will hand the request over to the RequestDispatcher that'll send the
request to /WEB-INF/jsp/test.jsp.
When mixing different view technologies in a webapplications, you can use the ResourceBundleViewResolver:
<bean id="viewResolver"
class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
<property name="basename"><value>views</value></property>
<property name="defaultParentView"><value>parentView</value></property>
</bean>
The ResourceBundleViewResolver inspects the ResourceBundle identified by the basename and for each view it is supposed
to resolve, it uses the value of the property [viewname].class as the view class and the value of the property
[viewname].url as the view url. As you can see, you can identify a parent view, from which all view in the properties file
sort of extend. This way you can specify a default view class for instance.
A note on caching: subclasses of AbstractCachingViewResolver cache view instances they've resolved. This greatly
improves performance when using certain view technology. It's possible to turn off the cache, by setting the cache property
to false. Furthermore, if you have the requirement to be able to refresh a certain view at runtime (for example when a Velocity
template has been modified), you can use the removeFromCache(String viewName, Locale loc) method.
12.6.1. AcceptHeaderLocaleResolver
This locale resolver inspects the accept-language header in the request that was sent by the browser of the client. Usually
this header field contains the locale of the client's operating system.
12.6.2. CookieLocaleResolver
This locale resolver inspects a Cookie that might exist on the client, to see if there's a locale specified. If so, it uses that specific
locale. Using the properties of this locale resolver, you can specify the name of the cookie, as well as the maximum age.
<bean id="localeResolver">
<property name="cookieName"><value>clientlanguage</value></property>
<!-- in seconds. If set to -1, the cookie is not persisted (deleted when browser
shuts down) -->
<property name="cookieMaxAge"><value>100000</value></property>
</bean>
This is an example of defining a CookieLocaleResolver.
Table 12.6. Special beans in the WebApplicationContext
Property Default Description
cookieName classname + LOCALE The name of the cookie
The maximum time a cookie will stay persistent on the client. If -1 is specified, the
cookieMaxAge Integer.MAX_INT cookie will not be persisted, at least, only until the client shuts down his or her
browser
Using this parameter, you can limit the visibility of the cookie to a certain part of
cookiePath / your site. When cookiePath is specified, the cookie will only be visible to that path,
and the paths below
12.6.3. SessionLocaleResolver
The SessionLocaleResolver allows you to retrieve locales from the session that might be associated to the user's
request.
12.6.4. LocaleChangeInterceptor
You can build in changing of locales using the LocaleChangeInterceptor. This interceptor needs to be added to one of
the handler mappings (see Section 12.4, Handler mappings ) and it will detect a parameter in the request and change the locale
(it calls setLocale() on the LocaleResolver that also exists in the context).
<bean id="localeChangeInterceptor"
class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName"><value>siteLanguage</value></property>
</bean>
<bean id="localeResolver"
class="org.springframework.web.servlet.i18n.CookieLocaleResolver"/>
<bean id="urlMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="interceptors">
<list>
<ref local="localeChangeInterceptor"/>
</list>
</property>
<property name="mappings">
<props>
<prop key="/**/*.view">someController</prop>
</props>
</property>
</bean>
All calls to all *.view resources containing a parameter named siteLanguage will now change the locale. So a call to
http://www.sf.net/home.view?siteLanguage=nl will change the site language to Dutch.
<!-- one of the properties available; the maximum file size in bytes -->
<property name="maxUploadSize">
<value>100000</value>
</property>
</bean>
This is an example using the CosMultipartResolver:
<bean id="multipartResolver"
class="org.springframework.web.multipart.cos.CosMultipartResolver">
<!-- one of the properties available; the maximum file size in bytes -->
<property name="maxUploadSize">
<value>100000</value>
</property>
</bean>
Of course you need to stick the appropriate jars in your classpath for the multipartresolver to work. In the case of the
CommonsMultipartResolver, you need to use commons-fileupload.jar, while in the case of the CosMultipartResolver,
use cos.jar.
Now that you have seen how to set Spring up to handle multipart requests, let's talk about how to actually use it. When the
Spring DispatcherServlet detects a Multipart request, it activates the resolver that has been declared in your context and hands
over the request. What it basically does is wrap the current HttpServletRequest into a
MultipartHttpServletRequest that has support for multiparts. Using the MultipartHttpServletRequest you can get
information about the multiparts contained by this request and actually get the multiparts themselves in your controllers.
...
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>
<bean id="urlMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/upload.form">fileUploadController</prop>
</props>
</property>
</bean>
</beans>
After that, create the controller and the actual bean holding the file property
// snippet from FileUploadController
public class FileUploadController extends SimpleFormController {
// well, let's do nothing with the bean for now and return:
return super.onSubmit(request, response, command, errors);
}
</form>
</body>
</html>
As you can see, we've created a field named after the property of the bean that holds the byte[]. Furthermore we've added the
encoding attribute which is necessary to let the browser know how to encode the multipart fields (dont' forget this!). Right now
everything should work.
Prev Up Next
Chapter 11. Data Access using O/R Chapter 13. Integrating view
Home
Mappers technologies
productList.class=org.springframework.web.servlet.view.JstlView
productList.url=/WEB-INF/jsp/productlist.jsp
As you can see, the ResourceBundleViewResolver needs a properties file defining the view names mapped to 1) a class and 2) a URL. With a
ResourceBundleViewResolver you can mix different types of views using only one resolver.
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property
name="viewClass"><value>org.springframework.web.servlet.view.JstlView</value></property>
<property name="prefix"><value>/WEB-INF/jsp/</value></property>
<property name="suffix"><value>.jsp</value></property>
</bean>
The InternalResourceBundleViewResolver can be configured for using JSPs as described above. As a best practice, we strongly encourage placing
your JSP files in a a directory under the WEB-INF directory, so there can be no direct access by clients.
13.3. Tiles
It is possible to integrate Tiles - just as any other view technology - in webapplications using Spring. The following describes in a broad way how to
do this.
13.3.1. Dependencies
To be able to use Tiles you have to have a couple of additional dependencies included in your project. The following is the list of dependencies you
need.
● struts version 1.1
● commons-beanutils
● commons-digester
● commons-logging
● commons-lang
The dependencies are all available in the Spring distribution.
13.3.2.1. InternalResourceViewResolver
The InternalResourceViewResolver instantiates the given viewClass for each view it has to resolve.
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="requestContextAttribute"><value>requestContext</value></property>
<property name="viewClass">
<value>org.springframework.web.servlet.view.tiles.TilesView</value>
</property>
</bean>
13.3.2.2. ResourceBundleViewResolver
The ResourceBundleViewResolver has to be provided with a property file containing viewnames and viewclasses the resolver can use:
<bean id="viewResolver"
class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
<property name="basename"><value>views</value></property>
vetsView.class=org.springframework.web.servlet.view.tiles.TilesView
vetsView.url=vetsView (<b>again, this is the name of a definition</b>)
findOwnersForm.class=org.springframework.web.servlet.view.JstlView
findOwnersForm.url=/WEB-INF/jsp/findOwners.jsp
...
As you can see, when using the ResourceBundleViewResolver, you can mix view using different view technologies.
13.4.1. Dependencies
Your web application will need to include velocity-1.x.x.jar or freemarker-2.x.jar in order to work with Velocity or FreeMarker
respectively and commons-collections.jar needs also to be available for Velocity. Typically they are included in the WEB-INF/lib folder
where they are guaranteed to be found by a J2EE server and added to the classpath for your application. It is of course assumed that you already have
the spring.jar in your WEB-INF/lib folder too! The latest stable velocity, freemarker and commons collections jars are supplied with the
Spring framework and can be copied from the relevant /lib/ sub-directories. If you make use of Spring's dateToolAttribute or numberToolAttribute
in your Velocity views, you will also need to include the velocity-tools-generic-1.x.jar
<!--
View resolvers can also be configured with ResourceBundles or XML files. If you
need
different view resolving based on Locale, you have to use the resource bundle
resolver.
-->
<bean
id="viewResolver"
class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
<property name="cache"><value>true</value></property>
<property name="prefix"><value></value></property>
<property name="suffix"><value>.vm</value></property>
</bean>
<!-- freemarker config -->
<bean
id="freemarkerConfig"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath"><value>/WEB-INF/freemarker/</value></property>
</bean>
13.4.4.1. velocity.properties
This file is completely optional, but if specified, contains the values that are passed to the Velocity runtime in order to configure velocity itself. Only
required for advanced configurations, if you need this file, specify its location on the VelocityConfigurer bean definition above.
<bean
id="velocityConfig"
class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
<property name="configLocation">
<value>/WEB-INF/velocity.properties</value>
</property>
</bean>
Alternatively, you can specify velocity properties directly in the bean definition for the Velocity config bean by replacing the "configLocation"
property with the following inline properties.
<bean
id="velocityConfig"
class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
<property name="velocityProperties">
<props>
<prop key="resource.loader">file</prop>
<prop key="file.resource.loader.class">
org.apache.velocity.runtime.resource.loader.FileResourceLoader
</prop>
<prop key="file.resource.loader.path">${webapp.root}/WEB-INF/velocity</prop>
<prop key="file.resource.loader.cache">false</prop>
</props>
</property>
</bean>
Refer to the API documentation for Spring configuration of Velocity, or the Velocity documentation for examples and definitions of the
velocity.properties file itself.
13.4.4.2. FreeMarker
FreeMarker 'Settings' and 'SharedVariables' can be passed directly to the FreeMarker Configuration object managed by Spring by setting the
appropriate bean properties on the FreeMarkerConfigurer bean. The freemarkerSettings property requires a
A standard set of macros are maintained within the spring.jar file for both languages, so they are always available to a suitably configured
application. However they can only be used if your view sets the bean property exposeSpringMacroHelpers to true . The same property can
be set on VelocityViewResolver or FreeMarkerViewResolver too if you happen to be using it, in which case all of your views will
inherit the value from it. Note that this property is not required for any aspect of HTML form handling except where you wish to take advantage of
the Spring macros. Below is an example of a view.properties file showing correct configuration of such a view for either language;
personFormV.class=org.springframework.web.servlet.view.velocity.VelocityView
personFormV.url=personForm.vm
personFormV.exposeSpringMacroHelpers=true
personFormF.class=org.springframework.web.servlet.view.freemarker.FreeMarkerView
personFormF.url=personForm.ftl
personFormF.exposeSpringMacroHelpers=true
Some of the macros defined in the Spring libraries are considered internal (private) but no such scoping exists in the macro definitions making all
macros visible to calling code and user templates. The following sections concentrate only on the macros you need to be directly calling from within
your templates. If you wish to view the macro code directly, the files are called spring.vm / spring.ftl and are in the packages
org.springframework.web.servlet.view.velocity or org.springframework.web.servlet.view.freemarker
respectively.
In your html forms (vm / ftl templates) that act as the 'formView' for a Spring form controller, you can use code similar to the following to bind to field
values and display error messages for each input field in similar fashion to the JSP equivalent. Note that the name of the command object is
"command" by default, but can be overridden in your MVC configuration by setting the 'commandName' bean property on your form controller.
Example code is shown below for the personFormV and personFormF views configured earlier;
<!-- velocity macros are automatically available -->
<html>
...
<form action="" method="POST">
Name:
#springBind( "command.name" )
<input type="text"
name="${status.expression}"
value="$!status.value" /><br>
#foreach($error in $status.errorMessages) <b>$error</b> <br> #end
<br>
...
<input type="submit" value="submit"/>
</form>
...
</html>
Additional convenience macros for both languages simplify both binding and form generation (including validation error display). It is never necessary
to use these macros to generate form input fields, and they can be mixed and matched with simple HTML or calls direct to the spring bind macros
highlighted previously.
The following table of available macros show the VTL and FTL definitions and the parameter list that each takes.
Table 13.1. table of macro definitions
macro VTL definition FTL definition
formInput (standard input
<@spring.formInput path,
field for gathering user #springFormInput($path $attributes)
attributes/>
input)
formTextarea (large text
<@spring.formTextarea path,
field for gathering long, #springFormTextarea($path $attributes)
attributes/>
freeform text input)
formSingleSelect (drop
down box of options #springFormSingleSelect( $path $options <@spring.formSingleSelect path,
allowing a single required $attributes) options, attributes/>
value to be selected)
formMultiSelect (a list box
#springFormMultiSelect($path $options <@spring.formMultiSelect path,
of options allowing the user
$attributes) options, attributes/>
to select 0 or more values)
formRadioButtons (a set of
radio buttons allowing a #springFormRadioButtons($path $options <@spring.formRadioButtons path,
single selection to be made $separator $attributes) options separator, attributes/>
from the available choices)
formCheckboxes (a set of
#springFormCheckboxes($path $options <@spring.formCheckboxes path,
checkboxes allowing 0 or
$separator $attributes) options, separator, attributes/>
more values to be selected)
showErrors (simplify
#springShowErrors($separator <@spring.showErrors separator,
display of validation errors
$classOrStyle) classOrStyle/>
for the bound field)
● options: a Map of all the available values that can be selected from in the input field. The keys to the map represent the values that will be
POSTed back from the form and bound to the command object. Map objects stored against the keys are the labels displayed on the form to the
user and may be different from the corresponding values posted back by the form. Usually such a map is supplied as reference data by the
controller. Any Map implementation can be used depending on required behaviour. For strictly sorted maps, a SortedMap such as a TreeMap
with a suitable Comparator may be used and for arbitrary Maps that should return values in insertion order, use a LinkedHashMap or a
LinkedMap from commons-collections.
● separator: where multiple options are available as discreet elements (radio buttons or checkboxes), the sequence of characters used to separate
each one in the list (ie "<br>").
● attributes: an additional string of arbitrary tags or text to be included within the HTML tag itself. This string is echoed literally by the macro. For
example, in a textarea field you may supply attributes as 'rows="5" cols="60"' or you could pass style information such as 'style="border:1px
solid silver"'.
● classOrStyle: for the showErrors macro, the name of the CSS class that the span tag wrapping each error will use. If no information is supplied
(or the value is empty) then the errors will be wrapped in <b></b> tags.
Examples of the macros are outlined below some in FTL and some in VTL. Where usage differences exist between the two languages, they are
explained in the notes.
<!-- the Name field example from above using form macros in VTL -->
...
Name:
#springFormInput("command.name" "")<br>
#showErrors("<br>" "")<br>
The formInput macro takes the path parameter (command.name) and an additional attributes parameter which is empty in the example above. The
macro, along with all other form generation macros, performs an implicit spring bind on the path parameter. The binding remains valid until a new
bind occurs so the showErrors macro doesn't need to pass the path parameter again - it simply operates on whichever field a bind was last created for.
The showErrors macro takes a separator parameter (the characters that will be used to separate multiple errors on a given field) and also accepts a
second parameter, this time a class name or style attribute. Note that FreeMarker is able to specify default values for the attributes parameter, unlike
Velocity, and the two macro calls above could be expressed as follows in FTL:
<@spring.formInput "command.name"/>
<@spring.showErrors "<br>"/>
Output is shown below of the form fragment generating the name field, and displying a validation error after the form was submitted with no value in
the field. Validation occurs through Spring's Validation framework.
The generated HTML looks like this:
Name:
<input type="text" name="name" value=""
>
<br>
<b>required</b>
<br>
<br>
The formTextarea macro works the same way as the formInput macro and accepts the same parameter list. Commonly, the second parameter
(attributes) will be used to pass style information or rows and cols attributes for the textarea.
Four selection field macros can be used to generate common UI value selection inputs in your HTML forms.
● formSingleSelect
● formMultiSelect
● formRadioButtons
● formCheckboxes
Each of the four macros accepts a Map of options containing the value for the form field, and the label corresponding to that value. The value and the
label can be the same.
An example of radio buttons in FTL is below. The form backing object specifies a default value of 'London' for this field and so no validation is
necessary. When the form is rendered, the entire list of cities to choose from is supplied as reference data in the model under the name 'cityMap'.
>
London
<input type="radio" name="address.town" value="Paris"
checked="checked"
>
Paris
<input type="radio" name="address.town" value="New York"
>
New York
If your application expects to handle cities by internal codes for example, the map of codes would be created with suitable keys like the example
below.
protected Map referenceData(HttpServletRequest request) throws Exception {
Map cityMap = new LinkedHashMap();
cityMap.put("LDN", "London");
cityMap.put("PRS", "Paris");
cityMap.put("NYC", "New York");
>
London
<input type="radio" name="address.town" value="PRS"
checked="checked"
>
Paris
<input type="radio" name="address.town" value="NYC"
>
New York
Default usage of the form macros above will result in HTML tags that are HTML 4.01 compliant and that use the default value for HTML escaping
defined in your web.xml as used by Spring's bind support. In order to make the tags XHTML compliant or to override the default HTML escaping
value, you can specify two variables in your template (or in your model where they will be visible to your templates). The advantage of specifying
them in the templates is that they can be changed to different values later in the template processing to provide different behaviour for different fields
in your form.
To switch to XHTML compliance for your tags, specify a value of 'true' for a model/context variable named xhtmlCompliant:
## for Velocity..
#set($springXhtmlCompliant = true)
13.5. XSLT
XSLT is a transformation language for XML and is popular as a view technology within web applications. XSLT can be a good choice as a view
technology if your application naturally deals with XML, or if your model can easily be converted to XML. The following section shows how to
produce an XML document as model data and have it transformed with XSLT in a Spring application.
Configuration is standard for a simple Spring application. The dispatcher servlet config file contains a reference to a ViewResolver, URL mappings
and a single controller bean..
<bean id="homeController"class="xslt.HomeController"/>
..that implements our word generation 'logic'.
The controller logic is encapsulated in a subclass of AbstractController, with the handler method being defined like so..
protected ModelAndView handleRequestInternal(
HttpServletRequest req,
HttpServletResponse resp)
throws Exception {
wordList.add("hello");
wordList.add("world");
map.put("wordList", wordList);
In order to create a DOM document from our list of words or any other model data, we subclass
org.springframework.web.servlet.view.xslt.AbstractXsltView. In doing so, we must implement the abstract method
createDomNode(). The first parameter passed to this method is our model Map. Here's the complete listing of the HomePage class in our trivial
word application - it uses JDOM to build the XML document before converting it to the required W3C Node, but this is simply because I find JDOM
(and Dom4J) easier API's to handle than the W3C API.
package xslt;
A series of parameter name/value pairs can optionally be defined by your subclass which will be added to the transformation object. The parameter
names must match those defined in your XSLT template declared with <xsl:param name="myParam">defaultValue</xsl:param> To
specify the parameters, override the method getParameters() from AbstractXsltView and return a Map of the name/value pairs. If your
parameters need to derive information from the current request, you can (from version 1.1) override the
getParameters(HttpServletRequest request) method instead.
Unlike JSTL and Velocity, XSLT has relatively poor support for locale based currency and date formatting. In recognition of the fact, Spring provides
a helper class that you can use from within your createDomNode() methods to get such support. See the javadocs for
org.springframework.web.servlet.view.xslt.FormatHelper
The views.properties file (or equivalent xml definition if you're using an XML based view resolver as we did in the Velocity examples above) looks
like this for the one-view application that is 'My First Words'..
home.class=xslt.HomePage
home.stylesheetLocation=/WEB-INF/xsl/home.xslt
home.root=words
Here, you can see how the view is tied in with the HomePage class just written which handles the model domification in the first property '.class'. The
stylesheetLocation property obviously points to the XSLT file which will handle the XML transformation into HTML for us and the final property
'.root' is the name that will be used as the root of the XML document. This gets passed to the HomePage class above in the second parameter to the
createDomNode method.
Finally, we have the XSLT code used for transforming the above document. As highlighted in the views.properties file, it is called home.xslt and it
lives in the war file under WEB-INF/xsl.
<?xml version="1.0"?>
<xsl:template match="/">
<html>
<head><title>Hello!</title></head>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
13.5.2. Summary
A summary of the files discussed and their location in the WAR file is shown in the simplified WAR structure below.
ProjectRoot
|
+- WebContent
|
+- WEB-INF
|
+- classes
| |
| +- xslt
| | |
| | +- HomePageController.class
| | +- HomePage.class
| |
| +- views.properties
|
+- lib
| |
| +- spring.jar
|
+- xsl
| |
| +- home.xslt
|
+- frontcontroller-servlet.xml
You will also need to ensure that an XML parser and an XSLT engine are available on the classpath. JDK 1.4 provides them by default, and most
J2EE containers will also make them available by default, but it's a possible source of errors to be aware of.
Firstly, let's amend the views.properties file (or xml equivalent) and add a simple view definition for both document types. The entire file now looks
like this with the XSLT view shown from earlier..
xl.class=excel.HomePage
pdf.class=pdf.HomePage
If you want to start with a template spreadsheet to add your model data to, specify the location as the 'url' property in the view definition
The controller code we'll use remains exactly the same from the XSLT example earlier other than to change the name of the view to use. Of course,
you could be clever and have this selected based on a URL parameter or some other logic - proof that Spring really is very good at decoupling the
views from the controllers!
Exactly as we did for the XSLT example, we'll subclass suitable abstract classes in order to implement custom behaviour in generating our output
documents. For Excel, this involves writing a subclass of
org.springframework.web.servlet.view.document.AbstractExcelView and implementing the buildExcelDocument
Here's the complete listing for our Excel view which displays the word list from the model map in consecutive rows of the first column of a new
spreadsheet..
package excel;
HSSFSheet sheet;
HSSFRow sheetRow;
HSSFCell cell;
// write a text at A1
cell = getCell( sheet, 0, 0 );
setText(cell,"Spring-Excel test");
}
}
}
If you now amend the controller such that it returns xl as the name of the view (return new ModelAndView("xl", map);) and run your
application again, you should find that the Excel spreadsheet is created and downloaded automagically when you request the same page as before.
The PDF version of the word list is even simpler. This time, the class extends
org.springframework.web.servlet.view.document.AbstractPdfView and implements the buildPdfDocument() method as
}
}
Once again, amend the controller to return the pdf view with a return new ModelAndView("pdf", map); and reload the URL in your
application. This time a PDF document should appear listing each of the words in the model map.
13.7. Tapestry
Tapestry is a powerful, component-oriented web application framework from Apache's Jakarta project (http://jakarta.apache.org/tapestry). While
Spring has its own powerful web ui layer, there are a number of unique advantages to building a J2EE application using a combination of Tapestry for
the web ui, and the Spring container for the lower layers. This document attempts to detail a few best practices for combining these two frameworks. It
is expected that you are relatively familiar with both Tapestry and Spring Framework basics, so they will not be explained here. General introductory
documentation for both Tapestry and Spring Framework are available on their respective web sites.
13.7.1. Architecture
A typical layered J2EE application built with Tapestry and Spring will consist of a top UI layer built with Tapestry, and a number of lower layers,
hosted out of one or more Spring Application Contexts.
● User Interface Layer:
- concerned with the user interface
- contains some application logic
- provided by Tapestry
- aside from providing UI via Tapestry, code in this layer does its work via objects which implement interfaces from the Service Layer. The
actual objects which implement these service layer interfaces are obtained from a Spring Application Context.
● Service Layer:
- application specific 'service' code
- works with domain objects, and uses the Mapper API to get those domain objects into and out of some sort of repository (database)
- hosted in one or more Spring contexts
- code in this layer manipulates objects in the domain model, in an application specific fashion. It does its work via other code in this layer, and
via the Mapper API. An object in this layer is given the specific mapper implementations it needs to work with, via the Spring context.
- since code in this layer is hosted in the Spring context, it may be transactionally wrapped by the Spring context, as opposed to managing its
own transactions
● Domain Model:
- domain specific object hierarchy, which deals with data and logic specific to this domain
- although the domain object hierarchy is built with the idea that it is persisted somehow and makes some general concessions to this (for
example, bidirectional relationships), it generally has no knowledge of other layers. As such, it may be tested in isolation, and used with
13.7.2. Implementation
The only real question (which needs to be addressed by this document), is how Tapestry pages get access to service implementations, which are simply
beans defined in an instance of the Spring Application Context.
Assume we have the following simple Application Context definition, in xml form:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!--
- Defines a transaction manager for usage in business or data access objects.
- No special treatment by the context, just a bean instance available as
reference
- for business objects that want to handle transactions, e.g. via
TransactionTemplate.
-->
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
</bean>
<bean id="mapper"
class="com.whatever.dataaccess.mapper.hibernate.MapperImpl">
<property name="sessionFactory"><ref bean="hibSessionFactory"/></property>
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager"><ref
bean="transactionManager"/></property>
<property name="target"><ref bean="authenticationServiceTarget"/></property>
<property name="proxyInterfacesOnly"><value>true</value></property>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager"><ref
bean="transactionManager"/></property>
<property name="target"><ref bean="userServiceTarget"/></property>
<property name="proxyInterfacesOnly"><value>true</value></property>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
</beans>
Inside the Tapestry application, we need to load this application context, and allow Tapestry pages to get the authenticationService and userService
beans, which implement the AuthenticationService and UserService interfaces, respectively.
At this point, the application context is available to a web application by calling Spring's static utility function
WebApplicationContextUtils.getApplicationContext(servletContext), where servletContext is the standard
ServletContext from the J2EE Servlet specification. As such, one simple mechanism for a page to get an instance of the UserService, for
example, would be with code such as:
WebApplicationContext appContext =
WebApplicationContextUtils.getApplicationContext(
getRequestCycle().getRequestContext().getServlet().getServletContext());
UserService userService = (UserService) appContext.getBean("userService");
... some code which uses UserService
This mechanism does work. It can be made a lot less verbose by encapsulating most of the functionality in a method in the base class for the page or
component. However, in some respects it goes against the Inversion of Control approach which Spring encourages, which is being used in other layers
of this app, in that ideally you would like the page to not have to ask the context for a specific bean by name, and in fact, the page would ideally not
know about the context at all.
Luckily, there is a mechanism to allow this. We rely upon the fact that Tapestry already has a mechanism to declaratively add properties to a page, and
it is in fact the preferred approach to manage all properties on a page in this declarative fashion, so that Tapestry can properly manage their lifecycle as
First we need to make the ApplicationContext available to the Tapestry page or Component without having to have the ServletContext;
this is because at the stage in the page's/component's lifecycle when we need to access the ApplicationContext, the ServletContext won't
be easily available to the page, so we can't use WebApplicationContextUtils.getApplicationContext(servletContext)
directly. One way is by defining a custom version of the Tapestry IEngine which exposes this for us:
package com.whatever.web.xportal;
...
import ...
...
public class MyEngine extends org.apache.tapestry.engine.BaseEngine {
/**
* @see
org.apache.tapestry.engine.AbstractEngine#setupForRequest(org.apache.tapestry.request.RequestContext)
*/
protected void setupForRequest(RequestContext context) {
super.setupForRequest(context);
Now in our page or component definition file (*.page or *.jwc), we simply add property-specification elements to grab the beans we need out of the
ApplicationContext, and create page or component properties for them. For example:
<property-specification name="userService"
type="com.whatever.services.service.user.UserService">
global.appContext.getBean("userService")
</property-specification>
<property-specification name="authenticationService"
type="com.whatever.services.service.user.AuthenticationService">
global.appContext.getBean("authenticationService")
</property-specification>
The OGNL expression inside the property-specification specifies the initial value for the property, as a bean obtained from the context. The entire page
definition might look like this:
<page-specification class="com.whatever.web.xportal.pages.Login">
type="com.whatever.services.service.user.AuthenticationService">
global.appContext.getBean("authenticationService")
</property-specification>
</page-specification>
Now in the Java class definition for the page or component itself, all we need to do is add an abstract getter method for the properties we have defined,
to access them. When the page or component is actually loaded by Tapestry, it performs runtime code instrumentation on the classfile to add the
properties which have been defined, and hook up the abstract getter methods to the newly created fields. For example:
// our UserService implementation; will come from page definition
public abstract UserService getUserService();
// our AuthenticationService implementation; will come from page definition
public abstract AuthenticationService getAuthenticationService();
For completeness, the entire Java class, for a login page in this example, might look like this:
package com.whatever.web.xportal.pages;
/**
* Allows the user to login, by providing username and password.
* After succesfully logging in, a cookie is placed on the client browser
* that provides the default username for future logins (the cookie
* persists for a week).
*/
public abstract class Login extends BasePage implements ErrorProperty,
/** the key under which the authenticated user object is stored in the visit as
*/
public static final String USER_KEY = "user";
/**
* The name of a cookie to store on the user's machine that will identify
* them next time they log in.
**/
private static final String COOKIE_NAME = Login.class.getName() + ".username";
private final static int ONE_WEEK = 7 * 24 * 60 * 60;
// --- attributes
// --- methods
/**
* Attempts to login.
*
* <p>If the user name is not known, or the password is invalid, then an error
* message is displayed.
*
**/
public void attemptLogin(IRequestCycle cycle) {
setPassword(null);
IValidationDelegate delegate = getValidationDelegate();
delegate.setFormComponent((IFormComponent) getComponent("inputPassword"));
delegate.recordFieldInputValue(null);
if (delegate.getHasErrors())
return;
/**
* Sets up the {@link User} as the logged in user, creates
* a cookie for their username (for subsequent logins),
* and redirects to the appropriate page, or
* a specified page).
*
**/
public void loginUser(User user, IRequestCycle cycle) {
if (callback == null)
cycle.activate("Home");
else
callback.performCallback(cycle);
// I've found that failing to set a maximum age and a path means that
// the browser (IE 5.0 anyway) quietly drops the cookie.
cycle.getRequestContext().addCookie(cookie);
engine.forgetPage(getPageName());
}
setUsername(getRequestCycle().getRequestContext().getCookieValue(COOKIE_NAME));
}
}
13.7.3. Summary
In this example, we've managed to allow service beans defined in the Spring ApplicationContext to be provided to the page in a declarative
fashion. The page class does not know where the service implementations are coming from, and in fact it is easy to slip in another implementation, for
example, during testing. This inversion of control is one of the prime goals and benefits of the Spring Framework, and we have managed to extend it
Prev Up Next
Chapter 12. Web framework Home Chapter 14. JMS
domains. As an example of a functional difference that was removed, if you use a JMS 1.1 provider you can
transactionally consume a message from one domain and produce a message on the other using the same
Session.
The JMS 1.1 specification was released in April 2002 and incorporated as part of J2EE 1.4 in November
2003. As a result, most application servers that are currently in use are only required to support JMS 1.0.2.
14.3. JmsTemplate
Two implementations of the JmsTemplate are provided. The class JmsTemplate uses the JMS 1.1 API
and the subclass JmsTemplate102 uses the JMS 1.0.2 API.
Code that uses the JmsTemplate only needs to implement callback interfaces giving them a clearly defined
contract. The MessageCreator callback interface creates a message given a Session provided by the
calling code in JmsTemplate. In order to allow for more complex usage of the JMS API, the callback
SessionCallback provides the user with the JMS session and the callback ProducerCallback
exposes a Session and MessageProducer pair.
The JMS API exposes two types of send methods, one that takes delivery mode, priority, and time-to-live as
quality of service (QOS) parameters and one that takes no QOS parameters which uses default values. Since
there are many send methods in JmsTemplate, the setting of the QOS parameters have been exposed as bean
properties to avoid duplication in the number of send methods. Similarly, the timeout value for synchronous
receive calls is set using the property setReceiveTimeout.
Some JMS providers allow the setting of default QOS values administratively through the configuration of
the ConnectionFactory. This has the effect that a call to MessageProducer's send method
send(Destination destination, Message message) will use QOS different default values
than those specified in the JMS specification. Therefore, in order to provide consistent management of QOS
values, the JmsTemplate must be specifically enabled to use its own QOS values by setting the boolean
property isExplicitQosEnabled to true.
14.3.1. ConnectionFactory
The JmsTemplate requires a reference to a ConnectionFactory. The ConnectionFactory is part of
the JMS specification and serves as the entry point for working with JMS. It is used by the client application
as a factory to create connections with the JMS provider and encapsulates various configuration parameters,
many of which are vendor specific such as SSL configuration options.
When using JMS inside an EJB the vendor provides implementations the JMS interfaces so that they can
participate in declarative transaction management and perform pooling of connections and session. In order
to use this implementation, J2EE containers typically require that you declare a JMS connection factory as a
resource-ref inside the EJB or servlet deployment descriptors. To ensure the use of these features with
the JmsTemplate inside an EJB, the client application should ensure that it references the managed
implementation of the ConnectionFactory.
Spring provides an implementation of the ConnectionFactory interface, SingleConnectionFactory,
that will return the same Connection on all createConnection calls and ignore calls to close. This is
useful for testing and standalone environments so that the same connection can be used for multiple
JmsTemplate calls that may span any number of transactions. SingleConnectionFactory takes a reference to a
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.JmsTemplate102;
import org.springframework.jms.core.MessageCreator;
This example uses the MessageCreator callback to create a text message from the supplied Session
object and the JmsTemplate is constructed by passing a reference to a ConnectionFactory and a boolean
specifying the messaging domain. A zero argument constructor and a setConnectionFactory/Queue method
are also provided and can be used for constructing the instance using a BeanFactory. The method simpleSend
modified to send to a topic instead of a queue is shown below
When configuring the 1.0.2 in an application context it is important to remember setting the value of the
boolean property PubSubDomain property in order to indicate if you want to send to Queues or Topics.
The method send(String destinationName, MessageCreator c) lets you send to a message
using the string name of the destination. If these names are registered in JNDI, you should set the
DestinationResolver property of the template to an instance of JndiDestinationResolver.
If you created the JmsTemplate and specified a default destination, the send(MessageCreator c)
sends a message to that destination.
return message;
}
});
}
MapMessage={
Header={
... standard headers ...
CorrelationID={123-00001}
}
Properties={
AccountID={Integer:1234}
}
Fields={
Name={String:Mark}
Age={Integer:35}
}
}
Prev Up Next
Chapter 13. Integrating view Chapter 15. Accessing and
Home
technologies implementing EJBs
for us to switch to a POJO (plain java object) implementation of the service if it makes sense to do so) Of course well also
need to implement the local home interface and provide a bean implementation class that implements SessionBean and the
MyComponent business methods interface. Now the only Java coding well need to do to hook up our web tier controller to
the EJB implementation is to expose a setter method of type MyComponent on the controller. This will save the reference
as an instance variable in the controller:
private MyComponent myComponent;
MyComponent _myComp;
/**
Prev Up Next
// Account service
public interface AccountService {
We will start exposing the service to a remote client by using RMI and talk a bit about the drawbacks of using RMI. We'll then
continue to show an example for Hessian.
<bean class="org.springframework.remoting.rmi.RmiServiceExporter">
<!-- does not necessarily have to be the same name as the bean to be exported
-->
<property name="serviceName"><value>AccountService</value></property>
<property name="service"><ref bean="accountService"/></property>
<property
name="serviceInterface"><value>example.AccountService</value></property>
<!-- defaults to 1099 -->
<property name="registryPort"><value>1199</value></property>
</bean>
As you can see, we're overriding the port for the RMI registry. Often, your application server also maintains an RMI registry
and it is wise to not interfere with that one. Furthermore, the service name is used to bind the service under. So right now, the
service will be bound at rmi://HOST:1199/AccountService. We'll use the URL later on to link in the service at the
client side.
Note: We've left out one property, i.e. the servicePort property, which is 0 by default. This means an anonymous port will
be used to communicate with the service. You can specify a different port if you like.
To link in the service on the client, we'll create a separate bean factory, containing the simple object and the service linking
configuration bits:
<bean class="example.SimpleObject">
<property name="accountService"><ref bean="accountService"/></bean>
</bean>
<bean id="accountService"
class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property
name="serviceUrl"><value>rmi://HOST:1199/AccountService</value></property>
<property
name="serviceInterface"><value>example.AccountService</value></property>
</bean>
That's all we need to do to support the remote account service on the client. Spring will transparently create an invoker and
remotely enable the account service through the RmiServiceExporter. At the client we're linking it in using the
RmiProxyFactoryBean.
<servlet>
<servlet-name>remote</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
You're probably familiar with Spring's DispatcherServlet principles and if so, you know that know you'll have to create an
application context named remote-servlet.xml (after the name of your servlet) in the WEB-INF directory. The
<bean name="/AccountService"
class="org.springframework.remoting.caucho.HessianServiceExporter">
<property name="service"><ref bean="accountService"/></property>
<property name="serviceInterface">
<value>example.AccountService</value>
</property>
</bean>
Now we're ready to link in the service at the client. No handler mapping is specified mapping requests (urls) onto services and
that's why the BeanNameUrlHandlerMapping will be used, hence the service will be exported at the URL
http://HOST:8080/AccountService.
<bean class="example.SimpleObject">
<property name="accountService"><ref bean="accountService"/></property>
</bean>
<bean id="accountService"
class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
<property
name="serviceUrl"><value>http://remotehost:8080/AccountService</value></property>
<property
name="ServiceInterface"><value>example.AccountService</value></property>
</bean>
features, for example. Usually, you don't use per-user security credentials here, but rather shared credentials defined at the
Hessian/BurlapProxyFactoryBean level (similar to a JDBC DataSource).
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
<property name="interceptors">
<list>
<ref bean="authorizationInterceptor"/>
</list>
</property>
</bean>
<bean id="authorizationInterceptor"
class="org.springframework.web.servlet.handler.UserRoleAuthorizationInterceptor">
<property name="authorizedRoles">
<list>
<value>administrator</value>
<value>operator</value>
</list>
</property>
</bean>
This an example where we explicitly mention the BeanNameUrlHandlerMapping and set an interceptor allowing only
administrators and operators to call the beans mentioned in this application context.
Note: Of course, this example doesn't show a flexible kind of security infrastructure. For more options as far as security is
concerned, have a look at the Acegi Security System for Spring, to be found at http://acegisecurity.sourceforge.net.
<bean name="/AccountService"
class="org.sprfr.remoting.httpinvoker.HttpInvokerServiceExporter">
<property name="service"><ref bean="accountService"/></property>
<property name="serviceInterface">
<value>example.AccountService</value>
</property>
</bean>
<bean id="httpInvokerProxy"
class="org.sprfr.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
<property name="serviceUrl">
<value>http://remotehost:8080/AccountService</value>
</property>
<property name="serviceInterface">
<value>example.AccountService</value>
</property>
</bean>
As mentioned before, you can choose what HTTP client you want to use. By default, the HttpInvokerProxy uses the J2SE
HTTP functionality, but you can also use the Commons HttpClient by setting the httpInvokerRequestExecutor
property:
<property name="httpInvokerRequestExecutor">
<bean
class="org.springframework.remoting.httpinvoker.CommonsHttpInvokerRequestExecutor"/>
</property>
Prev Up Next
Chapter 15. Accessing and implementing Chapter 17. Sending Email with Spring
Home
EJBs mail abstraction layer
/**
* Send the given simple mail message.
* @param simpleMessage message to send
* @throws MailException in case of message, authentication, or send errors
*/
public void send(SimpleMailMessage simpleMessage) throws MailException;
/**
* Send the given array of simple mail messages in batch.
* @param simpleMessages messages to send
* @throws MailException in case of message, authentication, or send errors
*/
public void send(SimpleMailMessage[] simpleMessages) throws MailException;
}
JavaMailSender:
public interface JavaMailSender extends MailSender {
/**
* Create a new JavaMail MimeMessage for the underlying JavaMail Session
* of this sender. Needs to be called to create MimeMessage instances
* that can be prepared by the client and passed to send(MimeMessage).
* @return the new MimeMessage instance
* @see #send(MimeMessage)
* @see #send(MimeMessage[])
*/
/**
* Send the given JavaMail MIME message.
* The message needs to have been created with createMimeMessage.
* @param mimeMessage message to send
* @throws MailException in case of message, authentication, or send errors
* @see #createMimeMessage
*/
public void send(MimeMessage mimeMessage) throws MailException;
/**
* Send the given array of JavaMail MIME messages in batch.
* The messages need to have been created with createMimeMessage.
* @param mimeMessages messages to send
* @throws MailException in case of message, authentication, or send errors
* @see #createMimeMessage
*/
public void send(MimeMessage[] mimeMessages) throws MailException;
/**
* Send the JavaMail MIME message prepared by the given MimeMessagePreparator.
* Alternative way to prepare MimeMessage instances, instead of createMimeMessage
* and send(MimeMessage) calls. Takes care of proper exception conversion.
* @param mimeMessagePreparator the preparator to use
* @throws MailException in case of message, authentication, or send errors
*/
public void send(MimeMessagePreparator mimeMessagePreparator) throws
MailException;
/**
* Send the JavaMail MIME messages prepared by the given MimeMessagePreparators.
* Alternative way to prepare MimeMessage instances, instead of createMimeMessage
* and send(MimeMessage[]) calls. Takes care of proper exception conversion.
* @param mimeMessagePreparators the preparator to use
* @throws MailException in case of message, authentication, or send errors
*/
public void send(MimeMessagePreparator[] mimeMessagePreparators) throws
MailException;
}
MimeMessagePreparator:
public interface MimeMessagePreparator {
/**
* Prepare the given new MimeMessage instance.
* @param mimeMessage the message to prepare
* @throws MessagingException passing any exceptions thrown by MimeMessage
* methods through for automatic conversion to the MailException hierarchy
*/
void prepare(MimeMessage mimeMessage) throws MessagingException;
Here is what the bean definitions for the code above would look like:
<bean id="mailSender"
class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host"><value>mail.mycompany.com</value></property>
</bean>
<bean id="mailMessage"
class="org.springframework.mail.SimpleMailMessage">
<property name="from"><value>[email protected]</value></property>
<property name="subject"><value>Your order</value></property>
</bean>
<bean id="orderManager"
class="com.mycompany.businessapp.support.OrderManagerImpl">
<property name="mailSender"><ref bean="mailSender"/></property>
<property name="message"><ref bean="mailMessage"/></property>
</bean>
Here is the implementation of OrderManager using MimeMessagePreparator callback interface. Please note that the
mailSender property is of type JavaMailSender in this case in order to be able to use JavaMail MimeMessage:
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;
}
};
try{
mailSender.send(preparator);
}
catch(MailException ex) {
//log it and go on
System.err.println(ex.getMessage());
}
}
}
If you want to use JavaMail MimeMessage to the full power, the MimeMessagePreparator is available at your fingertips.
Please note that the mail code is a crosscutting concern and is a perfect candidate for refactoring into a custom SpringAOP
advice, which then could easily be applied to OrderManager target. Please see the AOP chapter.
sender.send(message);
// let's include the infamous windows Sample file (this time copied to c:/)
FileSystemResource res = new FileSystemResource(new File("c:/Sample.jpg"));
helper.addInline("identifier1234", res);
sender.send(message);
Inline resources are added to the mime message using the Content-ID specified as you've seen just now (identifier1234
in this case). The order in which you're adding the text and the resource are VERY important. First add the resource and after
that the text. If you're doing it the other way around, it won't work!
Prev Up Next
Chapter 16. Remoting and web services Chapter 18. Scheduling jobs using
Home
using Spring Quartz or Timer
The job detail bean has all information it needs to run the job (ExampleJob). The timeout is specified as the job data map. The
job data map is available through the JobExecutionContext (passed to you at execution time), but the JobDetailBean also
maps the properties from the job data map to properties of the actual job. So in this case, if the ExampleJob contains a property
named timeout, the JobDetailBean will automatically apply it:
package example;
/**
* Setter called after the ExampleJob is instantiated
* with the value from the JobDetailBean (5)
*/
}
}
All additional settings from the job detail bean are by the way available to you as well.
Note: Using the name and group properties, you can modify in which group the job runs and using what name. By default
the name of the job equals the bean name of the job detail bean (in the example above this is exampleJob).
<bean id="methodInvokingJobDetail"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject"><ref bean="exampleBusinessObject"/></property>
<property name="targetMethod"><value>doIt</value></property>
</bean>
The above example will result in the doIt being called on the exampleBusinessObject (see below):
Using the MethodInvokingJobDetailFactoryBean 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.
By default, Quartz Jobs are stateless, resulting in the possibility of jobs interfering with eachother. If you specify two triggers
for the same JobDetail, it might be possible that before the first job has finished, the second one will start. If JobDetail objects
implement the Stateful interface, this won't happen. The second job will not start before the first one has finished. To make
jobs resulting from the MethodInvokingJobDetailFactoryBEan non-concurrent set the concurrent flag to false.
<bean id="methodInvokingJobDetail"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject"><ref bean="exampleBusinessObject"/></property>
<property name="targetMethod"><value>doIt</value></property>
</bean>
<bean id="simpleTrigger"
class="org.springframework.scheduling.quartz.SimpleTriggerBean">
<property name="jobDetail">
<!-- see the example of method invoking job above -->
<ref bean="methodInvokingJobDetail"/>
</property>
<property name="startDelay">
<!-- 10 seconds -->
<value>10000</value>
</property>
<property name="repeatInterval">
<!-- repeat every 50 seconds -->
<value>50000</value>
</property>
</bean>
Ok, 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. To finalize everything we need to set up the SchedulerFactoryBean:
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref local="cronTrigger"/>
<ref local="simpleTrigger"/>
</list>
</property>
</bean>
More properties are available for the SchedulerFactoryBean for you to set, such as the Calendars used by the job details,
properties to customize Quartz with, etcetera. Have a look at the JavaDOC
(http://www.springframework.org/docs/api/org/springframework/scheduling/quartz/SchedulerFactoryBean.html) for more
information.
}
}
Wiring it up is simple:
<bean id="scheduledTask"
class="org.springframework.scheduling.timer.ScheduledTimerTask">
<!-- wait 10 seconds before starting repeated execution -->
<property name="delay">
<value>10000</value>
</property>
<!-- run every 50 seconds -->
<property name="period">
<value>50000</value>
</property>
<property name="timerTask">
<ref local="checkEmail"/>
</property>
</bean>
<bean id="methodInvokingTask"
class="org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean">
<property name="targetObject"><ref bean="exampleBusinessObject"/></property>
<property name="targetMethod"><value>doIt</value></property>
</bean>
The above example will result in the doIt being called on the exampleBusinessObject (see below):
Changing the reference of the above example in which the ScheduledTimerTask is mentioned to the
methodInvokingTask will result in this task to be executed.
<bean id="timerFactory"
class="org.springframework.scheduling.timer.TimerFactoryBean">
<property name="scheduledTimerTasks">
<list>
<!-- see the example above -->
<ref local="scheduledTask"/>
</list>
</property>
</bean>
That's all!
Prev Up Next
Chapter 17. Sending Email with Spring Appendix A. Spring's beans.dtd
Home
mail abstraction layer
<!--
Spring XML Beans DTD
Authors: Rod Johnson, Juergen Hoeller, Alef Arendsen, Colin Sampaleanu
XML documents that conform to this DTD should declare the following doctype:
<!--
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*,
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-dependency-check (none | objects | simple | all) "none">
<!ATTLIST beans default-autowire (no | byName | byType | constructor | autodetect)
"no">
<!--
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 #IMPLIED>
<!--
Defines a single named bean.
-->
<!ELEMENT bean (
description?,
(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>
<!--
<!--
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.
The remaining settings will <i>always</i> be taken from the child definition:
depends on, autowire mode, dependency check, singleton, lazy init.
-->
<!ATTLIST bean parent 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.
-->
<!ATTLIST bean abstract (true | false) "false">
<!--
Is this bean a "singleton" (one shared instance, which will
be returned by all calls to getBean() with the id),
or a "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.
-->
<!ATTLIST bean singleton (true | false) "true">
<!--
If this bean should be lazily initialized.
If false, it will get instantiated on startup by bean factories
that perform eager initialization of singletons.
-->
<!ATTLIST bean lazy-init (true | false | default) "default">
<!--
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.
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.
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.
<!--
Optional attribute controlling whether to check whether all this
beans dependencies, expressed in its properties, are satisfied.
Default is no dependency checking.
<!--
The names of the beans that this bean depends on being initialized.
The bean factory will guarantee that these beans get initialized before.
<!--
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 singleton beans!
-->
<!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.
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.
<!--
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 | list | set | map | props | value | null)
)>
<!--
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.
<!--
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>
<!--
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
<!--
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 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>
<!--
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
<!--
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>
<!--
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>
<!--
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 helper 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>
<!--
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 | list | set | map | props | value | null)*
)>
<!--
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 | list | set | map | props | value | null)*
)>
<!--
A Spring map is a mapping from a string key to object.
Maps may be empty.
-->
<!ELEMENT map (
(entry)*
)>
<!--
A map entry can be an inner bean, ref, collection, or value.
The name of the property is given by the "key" attribute.
-->
<!ELEMENT entry (
(bean | ref | idref | list | set | map | props | value | null)
)>
<!--
Each map element must specify its key.
-->
<!ATTLIST entry key CDATA #REQUIRED>
<!--
Props elements differ from map elements in that values must be strings.
Props may be empty.
-->
<!ELEMENT props (
(prop)*
)>
<!--
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>
<!--
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 objects.
<!--
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)>
Prev Up
Chapter 18. Scheduling jobs using
Home
Quartz or Timer