Spring Framework 3.2.5.RELEASE Reference Documentation
Spring Framework 3.2.5.RELEASE Reference Documentation
Spring Framework 3.2.5.RELEASE Reference Documentation
Documentation
Authors
Rod Johnson, Juergen Hoeller, Keith Donald, Colin Sampaleanu, Rob Harrop, Thomas
Risberg, Alef Arendsen, Darren Davison, Dmitriy Kopylenko, Mark Pollack, Thierry
Templier, Erwin Vervaet, Portia Tung, Ben Hale, Adrian Colyer, John Lewis, Costin Leau,
Mark Fisher, Sam Brannen, Ramnivas Laddad, Arjen Poutsma, Chris Beams, Tareq
Abedrabbo, Andy Clement, Dave Syer, Oliver Gierke, Rossen Stoyanchev, Phillip Webb
3.2.5.RELEASE
Copyright 2004-2013
Copies of this document may be made for your own use and for distribution to others, provided that
you do not charge any fee for such copies and further provided that each copy contains this
Copyright Notice, whether distributed in print or electronically.
Table of Contents
5.4. Dependencies
5.9.1. @Required
5.9.2. @Autowired
5.9.3. Fine-tuning annotation-based autowiring with qualifiers
5.9.4. CustomAutowireConfigurer
5.9.5. @Resource
5.9.6. @PostConstruct and @PreDestroy
6. Resources
6.1. Introduction
6.2. The Resource interface
6.3. Built-in Resource implementations
6.3.1. UrlResource
6.3.2. ClassPathResource
6.3.3. FileSystemResource
6.3.4. ServletContextResource
6.3.5. InputStreamResource
6.3.6. ByteArrayResource
8.1. Introduction
8.2. Feature Overview
8.3. Expression Evaluation using Spring's Expression
Interface
8.3.1. The EvaluationContext interface
Type Conversion
Advice ordering
9.3.4. Introductions
9.3.5. Aspect instantiation models
9.3.6. Advisors
9.3.7. Example
10.2.1. Concepts
10.2.2. Operations on pointcuts
10.2.3. AspectJ expression pointcuts
10.2.4. Convenience pointcut implementations
Static pointcuts
Dynamic pointcuts
10.2.5. Pointcut superclasses
10.2.6. Custom pointcuts
11. Testing
11.1. Introduction to Spring Testing
11.2. Unit Testing
11.3.1. Overview
11.3.2. Goals of Integration Testing
Context management and caching
Dependency Injection of test fixtures
Transaction management
Support classes for integration testing
11.3.3. JDBC Testing Support
11.3.4. Annotations
Spring Testing Annotations
Standard Annotation Support
Spring JUnit Testing Annotations
11.3.5. Spring TestContext Framework
Key abstractions
Context management
Dependency injection of test fixtures
Testing request and session scoped beans
Transaction management
TestContext Framework support classes
11.3.6. Spring MVC Test Framework
Server-Side Tests
Client-Side REST Tests
11.3.7. PetClinic Example
14.3.1. DataSource
14.3.2. DataSourceUtils
14.3.3. SmartDataSource
14.3.4. AbstractDataSource
14.3.5. SingleConnectionDataSource
14.3.6. DriverManagerDataSource
14.3.7. TransactionAwareDataSourceProxy
14.3.8. DataSourceTransactionManager
14.3.9. NativeJdbcExtractor
15.3. Hibernate
15.4. JDO
15.5. JPA
16.5. JAXB
16.5.1. Jaxb2Marshaller
XML Schema-based Configuration
16.6. Castor
16.6.1. CastorMarshaller
16.6.2. Mapping
XML Schema-based Configuration
16.7. XMLBeans
16.7.1. XmlBeansMarshaller
XML Schema-based Configuration
16.8. JiBX
16.8.1. JibxMarshaller
XML Schema-based Configuration
16.9. XStream
16.9.1. XStreamMarshaller
V. The Web
17. Web MVC framework
17.1. Introduction to Spring Web MVC framework
17.1.1. Features of Spring Web MVC
17.1.2. Pluggability of other MVC implementations
17.8.1. AcceptHeaderLocaleResolver
17.8.2. CookieLocaleResolver
17.8.3. SessionLocaleResolver
17.8.4. LocaleChangeInterceptor
17.10.1. Introduction
17.10.2. Using a MultipartResolver with Commons FileUpload
17.10.3. Using a MultipartResolver with Servlet 3.0
17.10.4. Handling a file upload in a form
17.10.5. Handling a file upload request from programmatic clients
17.11.1. HandlerExceptionResolver
17.11.2. @ExceptionHandler
17.11.3. Handling Standard Spring MVC Exceptions
17.11.4. Annotating Business Exceptions With @ResponseStatus
17.11.5. Customizing the Default Servlet Container Error Page
17.15.1. Enabling the MVC Java Config or the MVC XML Namespace
17.15.2. Customizing the Provided Configuration
17.15.3. Configuring Interceptors
17.15.4. Configuring Content Negotiation
17.15.5. Configuring View Controllers
17.15.6. Configuring Serving of Resources
17.15.7. mvc:default-servlet-handler
17.15.8. More Spring Web MVC Resources
17.15.9. Advanced Customizations with MVC Java Config
17.15.10. Advanced Customizations with the MVC Namespace
18.3. Tiles
18.3.1. Dependencies
18.3.2. How to integrate Tiles
UrlBasedViewResolver
ResourceBundleViewResolver
SimpleSpringPreparerFactory and
SpringBeanPreparerFactory
18.4.1. Dependencies
18.4.2. Context configuration
18.4.3. Creating templates
18.4.4. Advanced configuration
velocity.properties
FreeMarker
18.4.5. Bind support and form handling
The bind macros
Simple binding
Form input generation macros
HTML escaping and XHTML compliance
18.5. XSLT
18.7. JasperReports
18.7.1. Dependencies
18.7.2. Configuration
Configuring the ViewResolver
Configuring the Views
About Report Files
Using JasperReportsMultiFormatView
18.7.3. Populating the ModelAndView
18.7.4. Working with Sub-Reports
Configuring Sub-Report Files
Configuring Sub-Report Data Sources
18.7.5. Configuring Exporter Parameters
20.5.1. PortletModeHandlerMapping
20.5.2. ParameterHandlerMapping
20.5.3. PortletModeParameterHandlerMapping
20.5.4. Adding HandlerInterceptors
20.5.5. HandlerInterceptorAdapter
20.5.6. ParameterMappingInterceptor
VI. Integration
21. Remoting and web services using Spring
21.1. Introduction
21.2. Exposing services using RMI
21.6. JMS
21.9.1. RestTemplate
Working with the URI
Dealing with request and response headers
21.9.2. HTTP Message Conversion
StringHttpMessageConverter
FormHttpMessageConverter
ByteArrayHttpMessageConverter
MarshallingHttpMessageConverter
MappingJackson2HttpMessageConverter (or
MappingJacksonHttpMessageConverter with Jackson 1.x)
SourceHttpMessageConverter
BufferedImageHttpMessageConverter
22.2.1. Concepts
22.2.2. Accessing local SLSBs
22.2.3. Accessing remote SLSBs
22.2.4. Accessing EJB 2.x SLSBs versus EJB 3 SLSBs
23.2.1. JmsTemplate
23.2.2. Connections
Caching Messaging Resources
SingleConnectionFactory
CachingConnectionFactory
23.2.3. Destination Management
23.2.4. Message Listener Containers
SimpleMessageListenerContainer
DefaultMessageListenerContainer
23.2.5. Transaction management
24. JMX
24.1. Introduction
24.2. Exporting your beans to JMX
25.4.1. MappingRecordOperation
25.4.2. MappingCommAreaOperation
25.4.3. Automatic output record generation
25.4.4. Summary
25.4.5. Example for MappingRecordOperation usage
25.4.6. Example for MappingCommAreaOperation usage
25.5. Transactions
26. Email
26.1. Introduction
26.2. Usage
Attachments
Inline resources
26.3.2. Creating email content using a templating library
A Velocity-based example
28.4. Scenarios
VII. Appendices
A. Classic Spring Usage
A.1.1. Hibernate
The HibernateTemplate
Implementing Spring-based DAOs without callbacks
A.1.2. JDO
JdoTemplate and JdoDaoSupport
A.1.3. JPA
JpaTemplate and JpaDaoSupport
A.3.1. JmsTemplate
A.3.2. Asynchronous Message Reception
A.3.3. Connections
A.3.4. Transaction Management
B. Classic Spring AOP Usage
B.1.1. Concepts
B.1.2. Operations on pointcuts
B.1.3. AspectJ expression pointcuts
B.1.4. Convenience pointcut implementations
Static pointcuts
Dynamic pointcuts
B.1.5. Pointcut superclasses
B.1.6. Custom pointcuts
E.1. Introduction
E.2. XML Schema-based configuration
F.1. Introduction
F.2. Authoring the schema
F.3. Coding a NamespaceHandler
F.4. Coding a BeanDefinitionParser
G. spring.tld
G.1. Introduction
G.2. The bind tag
G.3. The escapeBody tag
G.4. The hasBindErrors tag
G.5. The htmlEscape tag
G.6. The message tag
G.7. The nestedPath tag
G.8. The theme tag
G.9. The transform tag
G.10. The url tag
G.11. The eval tag
H. spring-form.tld
H.1. Introduction
H.2. The checkbox tag
H.3. The checkboxes tag
H.4. The errors tag
H.5. The form tag
H.6. The hidden tag
H.7. The input tag
H.8. The label tag
H.9. The option tag
H.10. The options tag
H.11. The password tag
H.12. The radiobutton tag
H.13. The radiobuttons tag
H.14. The select tag
H.15. The textarea tag
Spring is designed to be non-intrusive, meaning that your domain logic code generally has
no dependencies on the framework itself. In your integration layer (such as the data access
layer), some dependencies on the data access technology and the Spring libraries will
exist. However, it should be easy to isolate these dependencies from the rest of your code
base.
This document is a reference guide to Spring Framework features. If you have any
requests, comments, or questions on this document, please post them on the user mailing
list or on the support forums at http://forum.springsource.org/.
Background
The question is, what aspect of
control are [they] inverting?
Martin Fowler posed this
question about Inversion of
Control (IoC) on his site in 2004.
Fowler suggested renaming the
principle to make it more selfexplanatory and came up with
Dependency Injection.
For insight into IoC and DI, refer
to Fowler's article at
http://martinfowler.com/articles/injection.html.
1.2 Modules
The Spring Framework consists of features organized into about 20 modules. These
modules are grouped into Core Container, Data Access/Integration, Web, AOP (Aspect
Oriented Programming), Instrumentation, and Test, as shown in the following diagram.
The ORM module provides integration layers for popular object-relational mapping APIs,
including JPA, JDO, Hibernate, and iBatis. Using the ORM package you can use all of
these O/R-mapping frameworks in combination with all of the other features Spring offers,
such as the simple declarative transaction management feature mentioned previously.
The OXM module provides an abstraction layer that supports Object/XML mapping
implementations for JAXB, Castor, XMLBeans, JiBX and XStream.
The Java Messaging Service (JMS) module contains features for producing and
consuming messages.
The Transaction module supports programmatic and declarative transaction management
for classes that implement special interfaces and for all your POJOs (plain old Java
objects).
1.2.3 Web
The Web layer consists of the Web, Web-Servlet, Web-Struts, and Web-Portlet modules.
Spring's Web module provides basic web-oriented integration features such as multipart
file-upload functionality and the initialization of the IoC container using servlet listeners
and a web-oriented application context. It also contains the web-related parts of Spring's
remoting support.
The Web-Servlet module contains Spring's model-view-controller (MVC) implementation
for web applications. Spring's MVC framework provides a clean separation between
domain model code and web forms, and integrates with all the other features of the Spring
Framework.
The Web-Struts module contains the support classes for integrating a classic Struts web
tier within a Spring application. Note that this support is now deprecated as of Spring 3.0.
Consider migrating your application to Struts 2.0 and its Spring integration or to a Spring
MVC solution.
The Web-Portlet module provides the MVC implementation to be used in a portlet
environment and mirrors the functionality of Web-Servlet module.
1.2.5 Test
The Test module supports the testing of Spring components with JUnit or TestNG. It
provides consistent loading of Spring ApplicationContexts and caching of those contexts. It
also provides mock objects that you can use to test your code in isolation.
The Spring Framework does not force you to use everything within it; it is not an all-ornothing solution. Existing front-ends built with WebWork, Struts, Tapestry, or other UI
frameworks can be integrated with a Spring-based middle-tier, which allows you to use
Spring transaction features. You simply need to wire up your business logic using an
ApplicationContext and use a WebApplicationContext to integrate your web
layer.
features of Spring into your application (like dependency injection) you need to assemble
all the libraries needed (jar files) and get them onto your classpath at runtime, and possibly
at compile time. These dependencies are not virtual components that are injected, but
physical resources in a file system (typically). The process of dependency management
involves locating those resources, storing them and adding them to classpaths.
Dependencies can be direct (e.g. my application depends on Spring at runtime), or indirect
(e.g. my application depends on commons-dbcp which depends on commons-pool).
The indirect dependencies are also known as "transitive" and it is those dependencies that
are hardest to identify and manage.
If you are going to use Spring you need to get a copy of the jar libraries that comprise the
pieces of Spring that you need. To make this easier Spring is packaged as a set of
modules that separate the dependencies as much as possible, so for example if you don't
want to write a web application you don't need the spring-web modules. To refer to Spring
library modules in this guide we use a shorthand naming convention spring-* or
spring-*.jar, where "*" represents the short name for the module (e.g. springcore, spring-webmvc, spring-jms, etc.). The actual jar file name that you use may
be in this form (see below) or it may not, and normally it also has a version number in the
file name (e.g. spring-core-3.0.0.RELEASE.jar).
In general, Spring publishes its artifacts to four different places:
On the community download site http://www.springsource.org/download/community.
Here you find all the Spring jars bundled together into a zip file for easy download. The
names of the jars here since version 3.0 are in the form org.springframework.*<version>.jar.
Maven Central, which is the default repository that Maven queries, and does not
require any special configuration to use. Many of the common libraries that Spring
depends on also are available from Maven Central and a large section of the Spring
community uses Maven for dependency management, so this is convenient for them.
The names of the jars here are in the form spring-*-<version>.jar and the
Maven groupId is org.springframework.
The Enterprise Bundle Repository (EBR), which is run by SpringSource and also
hosts all the libraries that integrate with Spring. Both Maven and Ivy repositories are
available here for all Spring jars and their dependencies, plus a large number of other
common libraries that people use in applications with Spring. Both full releases and
also milestones and development snapshots are deployed here. The names of the jar
files are in the same form as the community download (org.springframework.*<version>.jar), and the dependencies are also in this "long" form, with external
libraries (not from SpringSource) having the prefix com.springsource. See the
FAQ for more information.
In a public Maven repository hosted on Amazon S3 for development snapshots and
milestone releases (a copy of the final releases is also held here). The jar file names
are in the same form as Maven Central, so this is a useful place to get development
versions of Spring to use with other libraries deployed in Maven Central.
So the first thing you need to decide is how to manage your dependencies: most people
use an automated system like Maven or Ivy, but you can also do it manually by
downloading all the jars yourself. When obtaining Spring with Maven or Ivy you have then
to decide which place you'll get it from. In general, if you care about OSGi, use the EBR,
since it houses OSGi compatible artifacts for all of Spring's dependencies, such as
Hibernate and Freemarker. If OSGi does not matter to you, either place works, though there
are some pros and cons between them. In general, pick one place or the other for your
project; do not mix them. This is particularly important since EBR artifacts necessarily use
a different naming convention than Maven Central artifacts.
Feature
Maven Central
EBR
OSGi
Compatible
Not explicit
Yes
Number of
Artifacts
Consistent
Naming
Conventions
No
Yes
Naming
Convention:
GroupId
Naming
Convention:
ArtifactId
Naming
Convention:
Version
Publishing
Quality
Assurance
By policy. Accuracy is
responsibility of
authors.
Hosting
Contegix. Funded by
Sonatype with several
mirrors.
S3 funded by SpringSource.
Search
Utilities
Various
http://www.springsource.com/repository
Integration
with
SpringSource
Tools
use Maven.
That's it. Note the scope can be declared as runtime if you don't need to compile against
Spring APIs, which is typically the case for basic dependency injection use cases.
We used the Maven Central naming conventions in the example above, so that works with
Maven Central or the SpringSource S3 Maven repository. To use the S3 Maven repository
(e.g. for milestones or developer snapshots), you need to specify the repository location in
your Maven configuration. For full releases:
<repositories>
<repository>
<id>com.springsource.repository.maven.release</id>
<url>http://repo.springsource.org/release/</url>
<snapshots><enabled>false</enabled></snapshots>
</repository>
</repositories>
For milestones:
<repositories>
<repository>
<id>com.springsource.repository.maven.milestone</id>
<url>http://repo.springsource.org/milestone/</url>
<snapshots><enabled>false</enabled></snapshots>
</repository>
</repositories>
To use the SpringSource EBR you would need to use a different naming convention for the
dependencies. The names are usually easy to guess, e.g. in this case it is:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.context</artifactId>
<version>3.0.0.RELEASE</version>
<scope>runtime</scope>
</dependency>
</dependencies>
You also need to declare the location of the repository explicitly (only the URL is
important):
<repositories>
<repository>
<id>com.springsource.repository.bundles.release</id>
<url>http://repository.springsource.com/maven/bundles/release/</url>
</repository>
</repositories>
If you are managing your dependencies by hand, the URL in the repository declaration
The XML above is not valid because the lines are too long - if you copy-paste then remove
the extra line endings in the middle of the url patterns.
Once Ivy is configured to look in the EBR adding a dependency is easy. Simply pull up the
details page for the bundle in question in the repository browser and you'll find an Ivy
snippet ready for you to include in your dependencies section. For example (in ivy.xml):
<dependency org="org.springframework"
name="org.springframework.core" rev="3.0.0.RELEASE" conf="compile->runtime"/>
1.3.2 Logging
Logging is a very important dependency for Spring because a) it is the only mandatory
external dependency, b) everyone likes to see some output from the tools they are using,
and c) Spring integrates with lots of other tools all of which have also made a choice of
logging dependency. One of the goals of an application developer is often to have unified
logging configured in a central place for the whole application, including all external
components. This is more difficult than it might have been since there are so many choices
of logging framework.
The mandatory logging dependency in Spring is the Jakarta Commons Logging API (JCL).
We compile against JCL and we also make JCL Log objects visible for classes that extend
the Spring Framework. It's important to users that all versions of Spring use the same
logging library: migration is easy because backwards compatibility is preserved even with
applications that extend Spring. The way we do this is to make one of the modules in
Spring depend explicitly on commons-logging (the canonical implementation of JCL),
and then make all the other modules depend on that at compile time. If you are using
Maven for example, and wondering where you picked up the dependency on commonslogging, then it is from Spring and specifically from the central module called springcore.
The nice thing about commons-logging is that you don't need anything else to make
your application work. It has a runtime discovery algorithm that looks for other logging
frameworks in well known places on the classpath and uses one that it thinks is
appropriate (or you can tell it which one if you need to). If nothing else is available you get
pretty nice looking logs just from the JDK (java.util.logging or JUL for short). You should
find that your Spring application works and logs happily to the console out of the box in
most situations, and that's important.
Now this application is probably broken because there is no implementation of the JCL
API on the classpath, so to fix it a new one has to be provided. In the next section we show
you how to provide an alternative implementation of JCL using SLF4J as an example.
Using SLF4J
SLF4J is a cleaner dependency and more efficient at runtime than commons-logging
because it uses compile-time bindings instead of runtime discovery of the other logging
frameworks it integrates. This also means that you have to be more explicit about what you
want to happen at runtime, and declare it or configure it accordingly. SLF4J provides
bindings to many common logging frameworks, so you can usually choose one that you
already use, and bind to that for configuration and management.
SLF4J provides bindings to many common logging frameworks, including JCL, and it also
does the reverse: bridges between other logging frameworks and itself. So to use SLF4J
with Spring you need to replace the commons-logging dependency with the SLF4J-JCL
bridge. Once you have done that then logging calls from within Spring will be translated
into logging calls to the SLF4J API, so if other libraries in your application use that API,
then you have a single place to configure and manage logging.
A common choice might be to bridge Spring to SLF4J, and then provide explicit binding
from SLF4J to Log4J. You need to supply 4 dependencies (and exclude the existing
commons-logging): the bridge, the SLF4J API, the binding to Log4J, and the Log4J
implementation itself. In Maven you would do that like this
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.0.0.RELEASE</version>
<scope>runtime</scope>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.5.8</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.5.8</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.5.8</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
<scope>runtime</scope>
</dependency>
</dependencies>
That might seem like a lot of dependencies just to get some logging. Well it is, but it is
optional, and it should behave better than the vanilla commons-logging with respect to
classloader issues, notably if you are in a strict container like an OSGi platform. Allegedly
there is also a performance benefit because the bindings are at compile-time not runtime.
A more common choice amongst SLF4J users, which uses fewer steps and generates
fewer dependencies, is to bind directly to Logback. This removes the extra binding step
because Logback implements SLF4J directly, so you only need to depend on two libraries
not four (jcl-over-slf4j and logback). If you do that you might also need to exclude
the slf4j-api dependency from other external dependencies (not Spring), because you only
want one version of that API on the classpath.
Using Log4J
Many people use Log4j as a logging framework for configuration and management
purposes. It's efficient and well-established, and in fact it's what we use at runtime when
we build and test Spring. Spring also provides some utilities for configuring and initializing
Log4j, so it has an optional compile-time dependency on Log4j in some modules.
To make Log4j work with the default JCL dependency (commons-logging) all you need
to do is put Log4j on the classpath, and provide it with a configuration file
(log4j.properties or log4j.xml in the root of the classpath). So for Maven users
this is your dependency declaration:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.0.0.RELEASE</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
<scope>runtime</scope>
</dependency>
</dependencies>
Many people run their Spring applications in a container that itself provides an
implementation of JCL. IBM Websphere Application Server (WAS) is the archetype. This
often causes problems, and unfortunately there is no silver bullet solution; simply
excluding commons-logging from your application is not enough in most situations.
To be clear about this: the problems reported are usually not with JCL per se, or even with
commons-logging: rather they are to do with binding commons-logging to another
framework (often Log4J). This can fail because commons-logging changed the way
they do the runtime discovery in between the older versions (1.0) found in some containers
and the modern versions that most people use now (1.1). Spring does not use any unusual
parts of the JCL API, so nothing breaks there, but as soon as Spring or your application
tries to do any logging you can find that the bindings to Log4J are not working.
In such cases with WAS the easiest thing to do is to invert the class loader hierarchy (IBM
calls it "parent last") so that the application controls the JCL dependency, not the container.
That option isn't always open, but there are plenty of other suggestions in the public
domain for alternative approaches, and your mileage may vary depending on the exact
version and feature set of the container.
2.1 Java 5
The entire framework code has been revised to take advantage of Java 5 features like
generics, varargs and other language improvements. We have done our best to still keep
the code backwards compatible. We now have consistent use of generic Collections and
Maps, consistent use of generic FactoryBeans, and also consistent resolution of bridge
methods in the Spring AOP API. Generic ApplicationListeners automatically receive
specific event types only. All callback interfaces such as TransactionCallback and
HibernateCallback declare a generic result value now. Overall, the Spring core codebase
is now freshly revised and optimized for Java 5.
Spring's TaskExecutor abstraction has been updated for close integration with Java 5's
java.util.concurrent facilities. We provide first-class support for Callables and Futures now,
as well as ExecutorService adapters, ThreadFactory integration, etc. This has been
aligned with JSR-236 (Concurrency Utilities for Java EE 6) as far as possible.
Furthermore, we provide support for asynchronous method invocations through the use of
Note:
The spring.jar artifact that
contained almost the entire
framework is no longer provided.
This functionality is also available if you prefer to configure your components using
annotations:
@Repository
public class RewardsTestDatabase {
@Value("#{systemProperties.databaseName}")
To get this to work you need to add the following component scanning entry in your
minimal application context XML file.
<context:component-scan base-package="org.example.config"/>
<util:properties id="jdbcProperties" location="classpath:org/example/config/jdbc.properties"/>
@MVC additions
A mvc namespace has been introduced that greatly simplifies Spring MVC configuration.
Additional annotations such as @CookieValue and @RequestHeaders have been
added. See Mapping cookie values with the @CookieValue annotation and Mapping
request header attributes with the @RequestHeader annotation for more information.
We provide support for asynchronous method invocations through the use of the new
@Async annotation (or EJB 3.1's @Asynchronous annotation).
JSR 303, JSF 2.0, JPA 2.0, etc
Javadoc
In most cases the new classes can be used as a more flexible alternative to the existing
UriTemplate especially since UriTemplate relies on those same classes internally.
A ServletUriComponentsBuilder sub-class provides static factory methods to copy
information from a Servlet request. See Section 17.7, Building URIs.
scanning.
4.10 Tiles 3
Tiles 3 is now supported in addition to Tiles 2.x. Configuring it should be very similar to the
Tiles 2 configuration, i.e. the combination of TilesConfigurer, TilesViewResolver
and TilesView except using the tiles3 instead of the tiles2 package.
Also note that besides the version number change, the tiles dependencies have also
changed. You will need to have a subset or all of tiles-request-api, tiles-api,
tiles-core, tiles-servlet, tiles-jsp, tiles-el.
This chapter covers the Spring Framework implementation of the Inversion of Control (IoC)
[1] principle. IoC
objects define their dependencies, that is, the other objects they work with, only through
constructor arguments, arguments to a factory method, or properties that are set on the
object instance after it is constructed or returned from a factory method. The container then
injects those dependencies when it creates the bean. This process is fundamentally the
inverse, hence the name Inversion of Control (IoC), of the bean itself controlling the
instantiation or location of its dependencies by using direct construction of classes, or a
mechanism such as the Service Locator pattern.
The org.springframework.beans and org.springframework.context
packages are the basis for Spring Framework's IoC container. The BeanFactory
interface provides an advanced configuration mechanism capable of managing any type of
object. ApplicationContext is a sub-interface of BeanFactory. It adds easier
integration with Spring's AOP features; message resource handling (for use in
internationalization), event publication; and application-layer specific contexts such as the
WebApplicationContext for use in web applications.
In short, the BeanFactory provides the configuration framework and basic functionality,
and the ApplicationContext adds more enterprise-specific functionality. The
ApplicationContext is a complete superset of the BeanFactory, and is used
exclusively in this chapter in descriptions of Spring's IoC container. For more information
on using the BeanFactory instead of the ApplicationContext, refer to
Section 5.15, The BeanFactory.
In Spring, the objects that form the backbone of your application and that are managed by
the Spring IoC container are called beans. A bean is an object that is instantiated,
assembled, and otherwise managed by a Spring IoC container. Otherwise, a bean is
simply one of many objects in your application. Beans, and the dependencies among
them, are reflected in the configuration metadata used by a container.
created and initialized, you have a fully configured and executable system or application.
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="..." class="...">
<!-- collaborators and configuration for this bean go here -->
</bean>
<bean id="..." class="...">
<!-- collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions go here -->
</beans>
The id attribute is a string that you use to identify the individual bean definition. The
class attribute defines the type of the bean and uses the fully qualified classname. The
value of the id attribute refers to collaborating objects. The XML for referring to
collaborating objects is not shown in this example; see Dependencies for more
information.
Note
After you learn about Spring's IoC container, you may want to know
more about Spring's Resource abstraction, as described in Chapter 6,
Resources, which provides a convenient mechanism for reading an
InputStream from locations defined in a URI syntax. In particular,
Resource paths are used to construct applications contexts as
described in Section 6.7, Application contexts and Resource paths.
The following example shows the service layer objects (services.xml) configuration
file:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- services -->
<bean id="petStore"
class="org.springframework.samples.jpetstore.services.PetStoreServiceImpl">
<property name="accountDao" ref="accountDao"/>
<property name="itemDao" ref="itemDao"/>
<!-- additional collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions for services go here -->
</beans>
The following example shows the data access objects daos.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="accountDao"
class="org.springframework.samples.jpetstore.dao.ibatis.SqlMapAccountDao">
<!-- additional collaborators and configuration for this bean go here -->
</bean>
<bean id="itemDao" class="org.springframework.samples.jpetstore.dao.ibatis.SqlMapItemDao">
<!-- additional collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions for data access objects go here -->
</beans>
In the preceding example, external bean definitions are loaded from three files,
services.xml, messageSource.xml, and themeSource.xml. All location paths
are relative to the definition file doing the importing, so services.xml must be in the
same directory or classpath location as the file doing the importing, while
messageSource.xml and themeSource.xml must be in a resources location
below the location of the importing file. As you can see, a leading slash is ignored, but
given that these paths are relative, it is better form not to use the slash at all. The contents
of the files being imported, including the top level <beans/> element, must be valid XML
bean definitions according to the Spring Schema or DTD.
Note
It is possible, but not recommended, to reference files in parent
directories using a relative "../" path. Doing so creates a dependency
on a file that is outside the current application. In particular, this
reference is not recommended for "classpath:" URLs (for example,
"classpath:../services.xml"), where the runtime resolution process
chooses the "nearest" classpath root and then looks into its parent
directory. Classpath configuration changes may lead to the choice of a
different, incorrect directory.
You can always use fully qualified resource locations instead of
relative paths: for example, "file:C:/config/services.xml" or
"classpath:/config/services.xml". However, be aware that you are
coupling your application's configuration to specific absolute locations.
It is generally preferable to keep an indirection for such absolute
locations, for example, through "${...}" placeholders that are resolved
against JVM system properties at runtime.
Explained in...
class
name
scope
constructor arguments
properties
autowiring mode
lazy-initialization mode
initialization method
destruction method
In addition to bean definitions that contain information on how to create a specific bean, the
ApplicationContext implementations also permit the registration of existing objects
that are created outside the container, by users. This is done by accessing the
ApplicationContext's BeanFactory via the method getBeanFactory() which returns the
BeanFactory implementation DefaultListableBeanFactory.
DefaultListableBeanFactory supports this registration through the methods
registerSingleton(..) and registerBeanDefinition(..). However, typical
applications work solely with beans defined through metadata bean definitions.
'accountService',
'userDao',
'loginController', and
so forth.
Naming beans consistently
makes your configuration easier
to read and understand, and if
you are using Spring AOP it
helps a lot when applying advice
to a set of beans related by
name.
having its own set of object definitions. In XMLbased configuration metadata, you can use the
<alias/> element to accomplish this.
<alias name="fromName" alias="toName"/>
In this case, a bean in the same container which is named fromName, may also after the
use of this alias definition, be referred to as toName.
For example, the configuration metadata for subsystem A may refer to a DataSource via
the name 'subsystemA-dataSource. The configuration metadata for subsystem B may refer
to a DataSource via the name 'subsystemB-dataSource'. When composing the main
application that uses both these subsystems the main application refers to the DataSource
via the name 'myApp-dataSource'. To have all three names refer to the same object you
add to the MyApp configuration metadata the following aliases definitions:
<alias name="subsystemA-dataSource" alias="subsystemB-dataSource"/>
<alias name="subsystemA-dataSource" alias="myApp-dataSource" />
Now each component and the main application can refer to the dataSource through a
name that is unique and guaranteed not to clash with any other definition (effectively
creating a namespace), yet they refer to the same bean.
com.example.Foo$Bar
Notice the use of the $ character
in the name to separate the inner
class name from the outer class
name.
For details about the mechanism for supplying arguments to the constructor (if required)
and setting object instance properties after the object is constructed, see Injecting
Dependencies.
For details about the mechanism for supplying (optional) arguments to the factory method
and setting object instance properties after the object is returned from the factory, see
Dependencies and configuration in detail.
One factory class can also hold more than one factory method as shown here:
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
<!-- inject any dependencies required by this locator bean -->
</bean>
<bean id="clientService"
factory-bean="serviceLocator"
factory-method="createClientServiceInstance"/>
<bean id="accountService"
factory-bean="serviceLocator"
factory-method="createAccountServiceInstance"/>
public class DefaultServiceLocator {
private static ClientService clientService = new ClientServiceImpl();
private static AccountService accountService = new AccountServiceImpl();
private DefaultServiceLocator() {}
public ClientService createClientServiceInstance() {
return clientService;
}
public AccountService createAccountServiceInstance() {
return accountService;
}
}
This approach shows that the factory bean itself can be managed and configured through
dependency injection (DI). See Dependencies and configuration in detail.
Note
In Spring documentation, factory bean refers to a bean that is
configured in the Spring container that will create objects through an
instance or static factory method. By contrast, FactoryBean (notice
the capitalization) refers to a Spring-specific FactoryBean .
5.4 Dependencies
A typical enterprise application does not consist of a single object (or bean in the Spring
parlance). Even the simplest application has a few objects that work together to present
what the end-user sees as a coherent application. This next section explains how you go
from defining a number of bean definitions that stand alone to a fully realized application
where objects collaborate to achieve a goal.
No potential ambiguity exists, assuming that Bar and Baz classes are not related by
inheritance. Thus the following configuration works fine, and you do not need to specify the
constructor argument indexes and/or types explicitly in the <constructor-arg/>
element.
<beans>
<bean id="foo" class="x.y.Foo">
<constructor-arg ref="bar"/>
<constructor-arg ref="baz"/>
</bean>
<bean id="bar" class="x.y.Bar"/>
<bean id="baz" class="x.y.Baz"/>
</beans>
When another bean is referenced, the type is known, and matching can occur (as was the
case with the preceding example). When a simple type is used, such as
<value>true<value>, Spring cannot determine the type of the value, and so cannot
match by type without help. Consider the following class:
package examples;
public class ExampleBean {
// No. of years to the calculate the Ultimate Answer
private int years;
// The Answer to Life, the Universe, and Everything
private String ultimateAnswer;
public ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
}
}
Keep in mind that to make this work out of the box your code must be compiled with the
debug flag enabled so that Spring can look up the parameter name from the constructor. If
you can't compile your code with debug flag (or don't want to) you can use
@ConstructorProperties JDK annotation to explicitly name your constructor
arguments. The sample class would then have to look as follows:
package examples;
public class ExampleBean {
// Fields omitted
@ConstructorProperties({"years", "ultimateAnswer"})
public ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
}
}
Circular dependencies
If you use predominantly
constructor injection, it is
possible to create an
unresolvable circular
dependency scenario.
For example: Class A requires
an instance of class B through
constructor injection, and class B
requires an instance of class A
through constructor injection. If
BeanCurrentlyInCreationException.
One possible solution is to edit
the source code of some classes
to be configured by setters rather
than constructors. Alternatively,
avoid constructor injection and
use setter injection only. In other
words, although it is not
recommended, you can
configure circular dependencies
with setter injection.
Unlike the typical case (with no
circular dependencies), a circular
dependency between bean A
and bean B forces one of the
beans to be injected into the
other prior to being fully
initialized itself (a classic
chicken/egg scenario).
In the preceding example, setters are declared to match against the properties specified in
the XML file. The following example uses constructor-based DI:
<bean id="exampleBean" class="examples.ExampleBean">
<!-- constructor injection using the nested <ref/> element -->
<constructor-arg>
<ref bean="anotherExampleBean"/>
</constructor-arg>
<!-- constructor injection using the neater 'ref' attribute -->
<constructor-arg ref="yetAnotherBean"/>
<constructor-arg type="int" value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
public class ExampleBean {
private AnotherBean beanOne;
private YetAnotherBean beanTwo;
private int i;
public ExampleBean(
AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
this.beanOne = anotherBean;
this.beanTwo = yetAnotherBean;
this.i = i;
}
}
The constructor arguments specified in the bean definition will be used as arguments to
the constructor of the ExampleBean.
Now consider a variant of this example, where instead of using a constructor, Spring is told
to call a static factory method to return an instance of the object:
<bean id="exampleBean" class="examples.ExampleBean"
factory-method="createInstance">
<constructor-arg ref="anotherExampleBean"/>
<constructor-arg ref="yetAnotherBean"/>
<constructor-arg value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
public class ExampleBean {
// a private constructor
private ExampleBean(...) {
...
}
// a static factory method; the arguments to this method can be
// considered the dependencies of the bean that is returned,
// regardless of how those arguments are actually used.
public static ExampleBean createInstance (
AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
ExampleBean eb = new ExampleBean (...);
// some other operations...
return eb;
}
}
The following example uses the p-namespace for even more succinct XML configuration.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://localhost:3306/mydb"
p:username="root"
p:password="masterkaoli"/>
</beans>
The preceding XML is more succinct; however, typos are discovered at runtime rather than
design time, unless you use an IDE such as IntelliJ IDEA or the SpringSource Tool Suite
(STS) that support automatic property completion when you create bean definitions. Such
IDE assistance is highly recommended.
You can also configure a java.util.Properties instance as:
<bean id="mappings"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<!-- typed as a java.util.Properties -->
<property name="properties">
<value>
jdbc.driver.className=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mydb
</value>
</property>
</bean>
The Spring container converts the text inside the <value/> element into a
java.util.Properties instance by using the JavaBeans PropertyEditor
mechanism. This is a nice shortcut, and is one of a few places where the Spring team do
favor the use of the nested <value/> element over the value attribute style.
The above bean definition snippet is exactly equivalent (at runtime) to the following
snippet:
<bean id="theTargetBean" class="..." />
<bean id="client" class="...">
<property name="targetName" value="theTargetBean" />
</bean>
The first form is preferable to the second, because using the idref tag allows the
container to validate at deployment time that the referenced, named bean actually exists. In
the second variation, no validation is performed on the value that is passed to the
targetName property of the client bean. Typos are only discovered (with most likely
fatal results) when the client bean is actually instantiated. If the client bean is a
prototype bean, this typo and the resulting exception may only be discovered long after the
container is deployed.
Additionally, if the referenced bean is in the same XML unit, and the bean name is the
bean id, you can use the local attribute, which allows the XML parser itself to validate the
bean id earlier, at XML document parse time.
<property name="targetName">
<!-- a bean with id 'theTargetBean' must exist; otherwise an exception will be thrown -->
<idref local="theTargetBean"/>
</property>
A common place (at least in versions earlier than Spring 2.0) where the <idref/> element
brings value is in the configuration of AOP interceptors in a ProxyFactoryBean bean
definition. Using <idref/> elements when you specify the interceptor names prevents you
from misspelling an interceptor id.
Specifying the target bean through 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 issues 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 as early as possible) if the target bean is in the same
XML file.
<ref local="someBean"/>
Specifying the target bean through the parent attribute creates a reference to a bean that
is in a parent container of the current container. The value of the parent 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, and the target bean must be in a parent container of the current
one. You use this bean reference variant mainly when you have a hierarchy of containers
and you want to wrap an existing bean in a parent container with a proxy that will have the
same name as the parent bean.
<!-- in the parent context -->
<bean id="accountService" class="com.foo.SimpleAccountService">
<!-- insert dependencies as required as here -->
</bean>
Inner beans
A <bean/> element inside the <property/> or <constructor-arg/> elements
defines a so-called inner bean.
<bean id="outer" class="...">
<!-- instead of using a reference to a target bean, simply define the target bean inline -->
<property name="target">
<bean class="com.example.Person"> <!-- this is the inner bean -->
<property name="name" value="Fiona Apple"/>
<property name="age" value="25"/>
</bean>
</property>
</bean>
An inner bean definition does not require a defined id or name; the container ignores these
values. It also ignores the scope flag. Inner beans are always anonymous and they are
always created with the outer bean. It is not possible to inject inner beans into
collaborating beans other than into the enclosing bean.
Collections
In the <list/>, <set/>, <map/>, and <props/> elements, you set the properties and
arguments of the Java Collection types List, Set, Map, and Properties,
respectively.
<bean id="moreComplexObject" class="example.ComplexObject">
<!-- results in a setAdminEmails(java.util.Properties) call -->
<property name="adminEmails">
<props>
<prop key="administrator">administrator@example.org</prop>
<prop key="support">support@example.org</prop>
<prop key="development">development@example.org</prop>
</props>
</property>
<!-- results in a setSomeList(java.util.List) call -->
<property name="someList">
<list>
<value>a list element followed by a reference</value>
<ref bean="myDataSource" />
</list>
</property>
<!-- results in a setSomeMap(java.util.Map) call -->
<property name="someMap">
<map>
<entry key="an entry" value="just some string"/>
<entry key ="a ref" value-ref="myDataSource"/>
</map>
</property>
<!-- results in a setSomeSet(java.util.Set) call -->
<property name="someSet">
<set>
<value>just some string</value>
<ref bean="myDataSource" />
</set>
</property>
</bean>
The value of a map key or value, or a set value, can also again be any of the following
elements:
bean | ref | idref | list | set | map | props | value | null
Collection merging
As of Spring 2.0, the container supports the merging of collections. An application
developer can define a parent-style <list/>, <map/>, <set/> or <props/> element,
and have child-style <list/>, <map/>, <set/> or <props/> elements inherit and
override values from the parent collection. That is, the child collection's values are the
result of merging the elements of the parent and child collections, with the child's collection
elements overriding values specified in the parent collection.
This section on merging discusses the parent-child bean mechanism. Readers unfamiliar
with parent and child bean definitions may wish to read the relevant section before
continuing.
The following example demonstrates collection merging:
<beans>
<bean id="parent" abstract="true" class="example.ComplexObject">
<property name="adminEmails">
<props>
<prop key="administrator">administrator@example.com</prop>
<prop key="support">support@example.com</prop>
</props>
</property>
</bean>
<bean id="child" parent="parent">
<property name="adminEmails">
<!-- the merge is specified on the *child* collection definition -->
<props merge="true">
<prop key="sales">sales@example.com</prop>
<prop key="support">support@example.co.uk</prop>
</props>
</property>
</bean>
<beans>
Notice the use of the merge=true attribute on the <props/> element of the
adminEmails property of the child bean definition. When the child bean is resolved
and instantiated by the container, the resulting instance has an adminEmails
Properties collection that contains the result of the merging of the child's
adminEmails collection with the parent's adminEmails collection.
administrator=administrator@example.com
sales=sales@example.com
support=support@example.co.uk
The child Properties collection's value set inherits all property elements from the parent
<props/>, and the child's value for the support value overrides the value in the parent
collection.
This merging behavior applies similarly to the <list/>, <map/>, and <set/> collection
types. In the specific case of the <list/> element, the semantics associated with the
List collection type, that is, the notion of an ordered collection of values, is maintained;
the parent's values precede all of the child list's values. In the case of the Map, Set, and
Properties collection types, no ordering exists. Hence no ordering semantics are in
effect for the collection types that underlie the associated Map, Set, and Properties
implementation types that the container uses internally.
When the accounts property of the foo bean is prepared for injection, the generics
information about the element type of the strongly-typed Map<String, Float> is
available by reflection. Thus Spring's type conversion infrastructure recognizes the various
value elements as being of type Float, and the string values 9.99, 2.75, and 3.99
are converted into an actual Float type.
The example shows an attribute in the p-namespace called email in the bean definition.
This tells Spring to include a property declaration. As previously mentioned, the pnamespace does not have a schema definition, so you can set the name of the attribute to
the property name.
This next example includes two more bean definitions that both have a reference to
another bean:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="john-classic" class="com.example.Person">
<property name="name" value="John Doe"/>
<property name="spouse" ref="jane"/>
</bean>
<bean name="john-modern"
class="com.example.Person"
p:name="John Doe"
p:spouse-ref="jane"/>
<bean name="jane" class="com.example.Person">
<property name="name" value="Jane Doe"/>
</bean>
</beans>
As you can see, this example includes not only a property value using the p-namespace,
but also uses a special format to declare property references. Whereas the first bean
definition uses <property name="spouse" ref="jane"/> to create a reference
from bean john to bean jane, the second bean definition uses p:spouseref="jane" as an attribute to do the exact same thing. In this case spouse is the
property name, whereas the -ref part indicates that this is not a straight value but rather a
reference to another bean.
Note
The p-namespace is not as flexible as the standard XML format. For
example, the format for declaring property references clashes with
properties that end in Ref, whereas the standard XML format does not.
We recommend that you choose your approach carefully and
communicate this to your team members, to avoid producing XML
documents that use all three approaches at the same time.
The c: namespace uses the same conventions as the p: one (trailing -ref for bean
references) for setting the constructor arguments by their names. And just as well, it needs
to be declared even though it is not defined in an XSD schema (but it exists inside the
Spring core).
For the rare cases where the constructor argument names are not available (usually if the
bytecode was compiled without debugging information), one can use fallback to the
argument indexes:
<-- 'c-namespace' index declaration -->
<bean id="foo" class="x.y.Foo" c:_0-ref="bar" c:_1-ref="baz">
Note
Due to the XML grammar, the index notation requires the presence of
the leading _ as XML attribute names cannot start with a number (even
though some IDE allow it).
In practice, the constructor resolution mechanism is quite efficient in matching arguments
so unless one really needs to, we recommend using the name notation through-out your
configuration.
The foo bean has a fred property, which has a bob property, which has a sammy
property, and that final sammy property is being set to the value 123. In order for this to
work, the fred property of foo, and the bob property of fred must not be null after the
bean is constructed, or a NullPointerException is thrown.
To express a dependency on multiple beans, supply a list of bean names as the value of
the depends-on attribute, with commas, whitespace and semicolons, used as valid
delimiters:
<bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao">
<property name="manager" ref="manager" />
</bean>
<bean id="manager" class="ManagerBean" />
<bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" />
Note
The depends-on attribute in the bean definition can specify both an
Mode
Explanation
no
byName
Autowiring by property name. Spring looks for a bean with the same
name as the property that needs to be autowired. For example, if a
bean definition is set to autowire by name, and it contains a master
property (that is, it has a setMaster(..) method), Spring looks for a
bean definition named master, and uses it to set the property.
byType
With byType or constructor autowiring mode, you can wire arrays and typed-collections. In
such cases all autowire candidates within the container that match the expected type are
provided to satisfy the dependency. You can autowire strongly-typed Maps if the expected
key type is String. An autowired Maps values will consist of all bean instances that
match the expected type, and the Maps keys will contain the corresponding bean names.
You can combine autowire behavior with dependency checking, which is performed after
autowiring completes.
Designate a single bean definition as the primary candidate by setting the primary
attribute of its <bean/> element to true.
If you are using Java 5 or later, implement the more fine-grained control available with
annotation-based configuration, as described in Section 5.9, Annotation-based
container configuration.
The preceding is not desirable, because the business code is aware of and coupled to the
Spring Framework. Method Injection, a somewhat advanced feature of the Spring IoC
container, allows this use case to be handled in a clean fashion.
In the client class containing the method to be injected (the CommandManager in this
case), the method to be injected requires a signature of the following form:
<public|protected> [abstract] <return-type> theMethodName(no-arguments);
The bean definition to deploy the original class and specify the method override would
look like this:
<bean id="myValueCalculator" class="x.y.z.MyValueCalculator">
<!-- arbitrary method replacement -->
<replaced-method name="computeValue" replacer="replacementComputeValue">
<arg-type>String</arg-type>
</replaced-method>
</bean>
<bean id="replacementComputeValue" class="a.b.c.ReplacementComputeValue"/>
You can use one or more contained <arg-type/> elements within the <replacedmethod/> element to indicate the method signature of the method being overridden. The
signature for the arguments is necessary only if the method is overloaded and multiple
variants exist within the class. For convenience, the type string for an argument may be a
substring of the fully qualified type name. For example, the following all match
java.lang.String:
java.lang.String
String
Str
Because the number of arguments is often enough to distinguish between each possible
choice, this shortcut can save a lot of typing, by allowing you to type only the shortest string
that will match an argument type.
Description
(Default) Scopes a single bean definition to a single object instance
per Spring IoC container.
request
session
global
session
Thread-scoped beans
As of Spring 3.0, a thread scope is available, but is not registered by
default. For more information, see the documentation for
SimpleThreadScope. For instructions on how to register this or any
other custom scope, see the section called Using a custom scope.
the Spring IoC container creates exactly one instance of the object defined by that bean
definition. This single instance is stored in a cache of such singleton beans, and all
subsequent requests and references for that named bean return the cached object.
Spring's concept of a singleton bean differs from the Singleton pattern as defined in the
Gang of Four (GoF) patterns book. The GoF Singleton hard-codes the scope of an object
such that one and only one instance of a particular class is created per ClassLoader.
The scope of the Spring singleton is best described as per container and per bean. This
means that if you define one bean for a particular class in a single Spring container, then
the Spring container creates one and only one instance of the class defined by that bean
definition. The singleton scope is the default scope in Spring. To define a bean as a
singleton in XML, you would write, for example:
<bean id="accountService" class="com.foo.DefaultAccountService"/>
<!-- the following is equivalent, though redundant (singleton scope is the default) -->
<bean id="accountService" class="com.foo.DefaultAccountService" scope="singleton"/>
In contrast to the other scopes, Spring does not manage the complete lifecycle of a
prototype bean: the container instantiates, configures, and otherwise assembles a
prototype object, and hands it to the client, with no further record of that prototype instance.
Thus, although initialization lifecycle callback methods are called on all objects regardless
of scope, in the case of prototypes, configured destruction lifecycle callbacks are not
called. The client code must clean up prototype-scoped objects and release expensive
resources that the prototype bean(s) are holding. To get the Spring container to release
resources held by prototype-scoped beans, try using a custom bean post-processor, which
holds a reference to beans that need to be cleaned up.
In some respects, the Spring container's role in regard to a prototype-scoped bean is a
replacement for the Java new operator. All lifecycle management past that point must be
handled by the client. (For details on the lifecycle of a bean in the Spring container, see
Section 5.6.1, Lifecycle callbacks.)
If you use an older web container (Servlet 2.3), use the provided
javax.servlet.Filter implementation. The following snippet of XML configuration
must be included in the web.xml file of your web application if you want to access webscoped beans in requests outside of Spring's DispatcherServlet on a Servlet 2.3 container.
(The filter mapping depends on the surrounding web application configuration, so you
must change it as appropriate.)
<web-app>
..
<filter>
<filter-name>requestContextFilter</filter-name>
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>requestContextFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
...
</web-app>
Request scope
Consider the following bean definition:
<bean id="loginAction" class="com.foo.LoginAction" scope="request"/>
The Spring container creates a new instance of the LoginAction bean by using the
loginAction bean definition for each and every HTTP request. That is, the
loginAction bean is scoped at the HTTP request level. You can change the internal
state of the instance that is created as much as you want, because other instances created
from the same loginAction bean definition will not see these changes in state; they are
particular to an individual request. When the request completes processing, the bean that
is scoped to the request is discarded.
Session scope
Consider the following bean definition:
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>
The Spring container creates a new instance of the UserPreferences bean by using
the userPreferences bean definition for the lifetime of a single HTTP Session. In
other words, the userPreferences bean is effectively scoped at the HTTP Session
level. As with request-scoped beans, you can change the internal state of the instance
that is created as much as you want, knowing that other HTTP Session instances that are
also using instances created from the same userPreferences bean definition do not
see these changes in state, because they are particular to an individual HTTP Session.
When the HTTP Session is eventually discarded, the bean that is scoped to that
particular HTTP Session is also discarded.
The global session scope is similar to the standard HTTP Session scope
(described above), and applies only in the context of portlet-based web applications. The
portlet specification defines the notion of a global Session that is shared among all
portlets that make up a single portlet web application. Beans defined at the global
session scope are scoped (or bound) to the lifetime of the global portlet Session.
If you write a standard Servlet-based web application and you define one or more beans
as having global session scope, the standard HTTP Session scope is used, and no
error is raised.
In the preceding example, the singleton bean userManager is injected with a reference
to the HTTP Session-scoped bean userPreferences. The salient point here is that
the userManager bean is a singleton: it will be instantiated exactly once per container,
and its dependencies (in this case only one, the userPreferences bean) are also
injected only once. This means that the userManager bean will only operate on the exact
same userPreferences object, that is, the one that it was originally injected with.
This is not the behavior you want when injecting a shorter-lived scoped bean into a longerlived scoped bean, for example injecting an HTTP Session-scoped collaborating bean
as a dependency into singleton bean. Rather, you need a single userManager object,
and for the lifetime of an HTTP Session, you need a userPreferences object that is
specific to said HTTP Session. Thus the container creates an object that exposes the
exact same public interface as the UserPreferences class (ideally an object that is a
UserPreferences instance) which can fetch the real UserPreferences object from
the scoping mechanism (HTTP request, Session, etc.). The container injects this proxy
object into the userManager bean, which is unaware that this UserPreferences
reference is a proxy. In this example, when a UserManager instance invokes a method
on the dependency-injected UserPreferences object, it actually is invoking a method
on the proxy. The proxy then fetches the real UserPreferences object from (in this
case) the HTTP Session, and delegates the method invocation onto the retrieved real
UserPreferences object.
Thus you need the following, correct and complete, configuration when injecting
request-, session-, and globalSession-scoped beans into collaborating objects:
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session">
<aop:scoped-proxy/>
</bean>
<bean id="userManager" class="com.foo.UserManager">
<property name="userPreferences" ref="userPreferences"/>
</bean>
based proxies means that you do not need additional libraries in your application
classpath to effect such proxying. However, it also means that the class of the scoped bean
must implement at least one interface, and that all collaborators into which the scoped
bean is injected must reference the bean through one of its interfaces.
<!-- DefaultUserPreferences implements the UserPreferences interface -->
<bean id="userPreferences" class="com.foo.DefaultUserPreferences" scope="session">
<aop:scoped-proxy proxy-target-class="false"/>
</bean>
<bean id="userManager" class="com.foo.UserManager">
<property name="userPreferences" ref="userPreferences"/>
</bean>
The following method removes the object from the underlying scope. The session scope
implementation for example, removes the session-scoped bean from the underlying
session. The object should be returned, but you can return null if the object with the
specified name is not found.
Object remove(String name)
The following method registers the callbacks the scope should execute when it is
destroyed or when the specified object in the scope is destroyed. Refer to the Javadoc or a
Spring scope implementation for more information on destruction callbacks.
void registerDestructionCallback(String name, Runnable destructionCallback)
The following method obtains the conversation identifier for the underlying scope. This
identifier is different for each scope. For a session scoped implementation, this identifier
can be the session identifier.
String getConversationId()
You then create bean definitions that adhere to the scoping rules of your custom Scope:
<bean id="..." class="..." scope="thread">
With a custom Scope implementation, you are not limited to programmatic registration of
the scope. You can also do the Scope registration declaratively, using the
CustomScopeConfigurer class:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="thread">
<bean class="org.springframework.context.support.SimpleThreadScope"/>
</entry>
</map>
</property>
</bean>
<bean id="bar" class="x.y.Bar" scope="thread">
<property name="name" value="Rick"/>
<aop:scoped-proxy/>
</bean>
<bean id="foo" class="x.y.Foo">
<property name="bar" ref="bar"/>
</bean>
</beans>
Note
When you place <aop:scoped-proxy/> in a FactoryBean
implementation, it is the factory bean itself that is scoped, not the object
returned from getObject().
Initialization callbacks
The org.springframework.beans.factory.InitializingBean interface
allows a bean to perform initialization work after all necessary properties on the bean have
been set by the container. The InitializingBean interface specifies a single method:
void afterPropertiesSet() throws Exception;
Destruction callbacks
Implementing the org.springframework.beans.factory.DisposableBean
interface allows a bean to get a callback when the container containing it is destroyed. The
It is recommended that you do not use the DisposableBean callback interface because
it unnecessarily couples the code to Spring. Alternatively, use the @PreDestroy
annotation or specify a generic method that is supported by bean definitions. With XMLbased configuration metadata, you use the destroy-method attribute on the <bean/>.
For example, the following definition:
<bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/>
<beans default-init-method="init">
<bean id="blogService" class="com.foo.DefaultBlogService">
<property name="blogDao" ref="blogDao" />
</bean>
</beans>
Any Spring-managed object may implement that interface. Then, when the
ApplicationContext itself starts and stops, it will cascade those calls to all Lifecycle
implementations defined within that context. It does this by delegating to a
LifecycleProcessor:
public interface LifecycleProcessor extends Lifecycle {
void onRefresh();
void onClose();
}
When starting, the objects with the lowest phase start first, and when stopping, the reverse
order is followed. Therefore, an object that implements SmartLifecycle and whose
getPhase() method returns Integer.MIN_VALUE would be among the first to start and
the last to stop. At the other end of the spectrum, a phase value of Integer.MAX_VALUE
would indicate that the object should be started last and stopped first (likely because it
depends on other processes to be running). When considering the phase value, it's also
important to know that the default phase for any "normal" Lifecycle object that does not
implement SmartLifecycle would be 0. Therefore, any negative phase value would
indicate that an object should start before those standard components (and stop after
them), and vice versa for any positive phase value.
As you can see the stop method defined by SmartLifecycle accepts a callback. Any
implementation must invoke that callback's run() method after that implementation's
shutdown process is complete. That enables asynchronous shutdown where necessary
since the default implementation of the LifecycleProcessor interface,
DefaultLifecycleProcessor, will wait up to its timeout value for the group of objects
within each phase to invoke that callback. The default per-phase timeout is 30 seconds.
You can override the default lifecycle processor instance by defining a bean named
"lifecycleProcessor" within the context. If you only want to modify the timeout, then defining
the following would be sufficient:
which exposes additional functionality. One use would be the programmatic retrieval of
other beans. Sometimes this capability is useful; however, in general you should avoid it,
because it couples the code to Spring and does not follow the Inversion of Control style,
where collaborators are provided to beans as properties. Other methods of the
ApplicationContext provide access to file resources, publishing application events, and
accessing a MessageSource. These additional features are described in Section 5.14,
Additional Capabilities of the ApplicationContext
As of Spring 2.5, autowiring is another alternative to obtain reference to the
ApplicationContext. The "traditional" constructor and byType autowiring
modes (as described in Section 5.4.5, Autowiring collaborators) can provide a
dependency of type ApplicationContext for a constructor argument or setter method
parameter, respectively. For more flexibility, including the ability to autowire fields and
multiple parameter methods, use the new annotation-based autowiring features. If you do,
the ApplicationContext is autowired into a field, constructor argument, or method
parameter that is expecting the ApplicationContext type if the field, constructor, or
method in question carries the @Autowired annotation. For more information, see
Section 5.9.2, @Autowired.
When an ApplicationContext creates a class that implements the
org.springframework.beans.factory.BeanNameAware interface, the class is
provided with a reference to the name defined in its associated object definition.
public interface BeanNameAware {
void setBeanName(string name) throws BeansException;
}
The callback is invoked after population of normal bean properties but before an
initialization callback such as InitializingBeans afterPropertiesSet or a custom initmethod.
Injected Dependency
Explained in...
Declaring
ApplicationContext
Section 5.6.2,
ApplicationContextAware
and BeanNameAware
BeanClassLoaderAware
BeanFactoryAware
Declaring BeanFactory
Section 5.6.2,
ApplicationContextAware
and BeanNameAware
BeanNameAware
Section 5.6.2,
ApplicationContextAware
and BeanNameAware
Resource adapter
BootstrapContext the
BootstrapContextAware
LoadTimeWeaverAware
MessageSourceAware
NotificationPublisherAware
PortletConfigAware
Current PortletConfig
the container runs in.
Valid only in a web-aware
Spring
ApplicationContext
PortletContextAware
Current
PortletContext the
container runs in. Valid
only in a web-aware
Spring
ApplicationContext
ResourceLoaderAware
Chapter 6, Resources
ServletConfigAware
Current ServletConfig
the container runs in.
Valid only in a web-aware
Spring
ApplicationContext
ServletContextAware
Current
ServletContext the
container runs in. Valid
only in a web-aware
Spring
ApplicationContext
Note again that usage of these interfaces ties your code to the Spring API and does not
follow the Inversion of Control style. As such, they are recommended for infrastructure
beans that require programmatic access to the container.
class="org.springframework.beans.TestBean">
<property name="name" value="parent"/>
<property name="age" value="1"/>
</bean>
<bean id="inheritsWithDifferentClass"
class="org.springframework.beans.DerivedTestBean"
parent="inheritedTestBean" init-method="initialize">
<property name="name" value="override"/>
<!-- the age property value of 1 will be inherited from
parent -->
</bean>
A child bean definition uses 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, that is, it must accept the parent's property values.
A child bean definition inherits constructor argument values, property values, and method
overrides from the parent, with the option to add new values. Any initialization method,
destroy method, and/or static factory method settings that you specify will override the
corresponding parent settings.
The remaining settings are always taken from the child definition: depends on, autowire
mode, dependency check, singleton, scope, lazy init.
The preceding example explicitly marks the parent bean definition as abstract by using the
abstract attribute. If the parent definition does not specify a class, explicitly marking the
parent bean definition as abstract is required, as follows:
<bean id="inheritedTestBeanWithoutClass" abstract="true">
<property name="name" value="parent"/>
<property name="age" value="1"/>
</bean>
<bean id="inheritsWithClass" class="org.springframework.beans.DerivedTestBean"
parent="inheritedTestBeanWithoutClass" init-method="initialize">
<property name="name" value="override"/>
<!-- age will inherit the value of 1 from the parent bean definition-->
</bean>
The parent bean cannot be instantiated on its own because it is incomplete, and it is also
explicitly marked as abstract. When a definition is abstract like this, it is usable only
as a pure template bean definition that serves as a parent definition for child definitions.
Trying to use such an abstract parent bean on its own, by referring to it as a ref property
of another bean or doing an explicit getBean() call with the parent bean id, returns an
error. Similarly, the container's internal preInstantiateSingletons() method
ignores bean definitions that are defined as abstract.
Note
ApplicationContext pre-instantiates all singletons by default.
Therefore, it is important (at least for singleton beans) that if you have a
(parent) bean definition which you intend to use only as a template, and
this definition specifies a class, you must make sure to set the abstract
attribute to true, otherwise the application context will actually (attempt
to) pre-instantiate the abstract bean.
resolution logic, and so forth. If you want to implement some custom logic after the Spring
container finishes instantiating, configuring, and initializing a bean, you can plug in one or
more BeanPostProcessor implementations.
You can configure multiple BeanPostProcessor instances, and you can control the
order in which these BeanPostProcessors execute by setting the order property. You
can set this property only if the BeanPostProcessor implements the Ordered
interface; if you write your own BeanPostProcessor you should consider implementing
the Ordered interface too. For further details, consult the Javadoc for the
BeanPostProcessor and Ordered interfaces. See also the note below on
programmatic registration of BeanPostProcessors
Note
BeanPostProcessors operate on bean (or object) instances; that is
to say, the Spring IoC container instantiates a bean instance and then
BeanPostProcessors do their work.
BeanPostProcessors are scoped per-container. This is only
relevant if you are using container hierarchies. If you define a
BeanPostProcessor in one container, it will only post-process the
beans in that container. In other words, beans that are defined in one
container are not post-processed by a BeanPostProcessor defined
in another container, even if both containers are part of the same
hierarchy.
To change the actual bean definition (i.e., the blueprint that defines the
bean), you instead need to use a BeanFactoryPostProcessor as
described in Section 5.8.2, Customizing configuration metadata with a
BeanFactoryPostProcessor.
The org.springframework.beans.factory.config.BeanPostProcessor
interface consists of exactly two callback methods. When such a class is registered as a
post-processor with the container, for each bean instance that is created by the container,
the post-processor gets a callback from the container both before container initialization
methods (such as InitializingBean's afterPropertiesSet() and any declared init method) are
called as well as after any bean initialization callbacks. The post-processor can take any
action with the bean instance, including ignoring the callback completely. A bean postprocessor typically checks for callback interfaces or may wrap a bean with a proxy. Some
Spring AOP infrastructure classes are implemented as bean post-processors in order to
provide proxy-wrapping logic.
An ApplicationContext automatically detects any beans that are defined in the
configuration metadata which implement the BeanPostProcessor interface. The
ApplicationContext registers these beans as post-processors so that they can be
called later upon bean creation. Bean post-processors can be deployed in the container
just like any other beans.
Programmatically registering BeanPostProcessors
While the recommended approach for BeanPostProcessor
registration is through ApplicationContext auto-detection (as
described above), it is also possible to register them programmatically
against a ConfigurableBeanFactory using the
addBeanPostProcessor method. This can be useful when needing
to evaluate conditional logic before registration, or even for copying
bean post processors across contexts in a hierarchy. Note however that
BeanPostProcessors added programmatically do not respect the
Ordered interface. Here it is the order of registration that dictates the
order of execution. Note also that BeanPostProcessors registered
programmatically are always processed before those registered
through auto-detection, regardless of any explicit ordering.
BeanPostProcessors and AOP auto-proxying
</beans>
The actual values come from another file in the standard Java Properties format:
jdbc.driverClassName=org.hsqldb.jdbcDriver
jdbc.url=jdbc:hsqldb:hsql://production:9002
jdbc.username=sa
jdbc.password=root
Therefore, the string ${jdbc.username} is replaced at runtime with the value 'sa', and
the same applies for other placeholder values that match keys in the properties file. The
PropertyPlaceholderConfigurer checks for placeholders in most properties and
attributes of a bean definition. Furthermore, the placeholder prefix and suffix can be
customized.
With the context namespace introduced in Spring 2.5, it is possible to configure property
placeholders with a dedicated configuration element. One or more locations can be
provided as a comma-separated list in the location attribute.
<context:property-placeholder location="classpath:com/foo/jdbc.properties"/>
If the class cannot be resolved at runtime to a valid class, resolution of the bean fails when it is
about to be created, which is during the preInstantiateSingletons() phase of an
ApplicationContext for a non-lazy-init bean.
For example:
dataSource.driverClassName=com.mysql.jdbc.Driver
dataSource.url=jdbc:mysql:mydb
This example file can be used with a container definition that contains a bean called
dataSource, which has driver and url properties.
Compound property names are also supported, as long as every component of the path
except the final property being overridden is already non-null (presumably initialized by the
constructors). In this example...
foo.fred.bob.sammy=123
... the sammy property of the bob property of the fred property of the foo bean is set to
the scalar value 123.
Note
Specified override values are always literal values; they are not
translated into bean references. This convention also applies when the
original value in the XML bean definition specifies a bean reference.
With the context namespace introduced in Spring 2.5, it is possible to configure property
overriding with a dedicated configuration element:
<context:property-override location="classpath:override.properties"/>
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
</beans>
5.9.1 @Required
The @Required annotation applies to bean property setter methods, as in the following
example:
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Required
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}
This annotation simply indicates that the affected bean property must be populated at
configuration time, through an explicit property value in a bean definition or through
autowiring. The container throws an exception if the affected bean property has not been
populated; this allows for eager and explicit failure, avoiding NullPointerExceptions
or the like later on. It is still recommended that you put assertions into the bean class itself,
for example, into an init method. Doing so enforces those required references and values
even when you use the class outside of a container.
5.9.2 @Autowired
As expected, you can apply the @Autowired annotation to "traditional" setter methods:
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Autowired
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}
Note
JSR 330's @Inject annotation can be used in place of Spring's
@Autowired annotation in the examples below. See here for more
details
You can also apply the annotation to methods with arbitrary names and/or multiple
arguments:
public class MovieRecommender {
private MovieCatalog movieCatalog;
private CustomerPreferenceDao customerPreferenceDao;
@Autowired
public void prepare(MovieCatalog movieCatalog,
CustomerPreferenceDao customerPreferenceDao) {
this.movieCatalog = movieCatalog;
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
Even typed Maps can be autowired as long as the expected key type is String. The Map
values will contain all beans of the expected type, and the keys will contain the
corresponding bean names:
public class MovieRecommender {
private Map<String, MovieCatalog> movieCatalogs;
@Autowired
public void setMovieCatalogs(Map<String, MovieCatalog> movieCatalogs) {
this.movieCatalogs = movieCatalogs;
}
// ...
}
By default, the autowiring fails whenever zero candidate beans are available; the default
behavior is to treat annotated methods, constructors, and fields as indicating required
dependencies. This behavior can be changed as demonstrated below.
Note
Only one annotated constructor per-class can be marked as required,
but multiple non-required constructors can be annotated. In that case,
each is considered among the candidates and Spring uses the
greediest constructor whose dependencies can be satisfied, that is the
constructor that has the largest number of arguments.
@Autowired's required attribute is recommended over the
@Required annotation. The required attribute indicates that the
property is not required for autowiring purposes, the property is ignored
if it cannot be autowired. @Required, on the other hand, is stronger in
that it enforces the property that was set by any means supported by
the container. If no value is injected, a corresponding exception is
raised.
You can also use @Autowired for interfaces that are well-known resolvable
dependencies: BeanFactory, ApplicationContext, Environment,
ResourceLoader, ApplicationEventPublisher, and MessageSource. These
interfaces and their extended interfaces, such as
ConfigurableApplicationContext or ResourcePatternResolver, are
automatically resolved, with no special setup necessary.
public class MovieRecommender {
@Autowired
private ApplicationContext context;
public MovieRecommender() {
}
// ...
}
Note
@Autowired, @Inject, @Resource, and @Value annotations are
handled by a Spring BeanPostProcessor implementations which in
turn means that you cannot apply these annotations within your own
BeanPostProcessor or BeanFactoryPostProcessor types (if
any). These types must be 'wired up' explicitly via XML or using a
Spring @Bean method.
method parameters:
public class MovieRecommender {
private MovieCatalog movieCatalog;
private CustomerPreferenceDao customerPreferenceDao;
@Autowired
public void prepare(@Qualifier("main") MovieCatalog movieCatalog,
CustomerPreferenceDao customerPreferenceDao) {
this.movieCatalog = movieCatalog;
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
The corresponding bean definitions appear as follows. The bean with qualifier value
"main" is wired with the constructor argument that is qualified with the same value.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<bean class="example.SimpleMovieCatalog">
<qualifier value="main"/>
<!-- inject any dependencies required by this bean -->
</bean>
<bean class="example.SimpleMovieCatalog">
<qualifier value="action"/>
<!-- inject any dependencies required by this bean -->
</bean>
<bean id="movieRecommender" class="example.MovieRecommender"/>
</beans>
For a fallback match, the bean name is considered a default qualifier value. Thus you can
define the bean with an id "main" instead of the nested qualifier element, leading to the
same matching result. However, although you can use this convention to refer to specific
beans by name, @Autowired is fundamentally about type-driven injection with optional
semantic qualifiers. This means that qualifier values, even with the bean name fallback,
always have narrowing semantics within the set of type matches; they do not semantically
express a reference to a unique bean id. Good qualifier values are "main" or "EMEA" or
"persistent", expressing characteristics of a specific component that are independent from
the bean id, which may be auto-generated in case of an anonymous bean definition like
the one in the preceding example.
Qualifiers also apply to typed collections, as discussed above, for example, to
Set<MovieCatalog>. In this case, all matching beans according to the declared
qualifiers are injected as a collection. This implies that qualifiers do not have to be unique;
they rather simply constitute filtering criteria. For example, you can define multiple
MovieCatalog beans with the same qualifier value "action"; all of which would be
injected into a Set<MovieCatalog> annotated with @Qualifier("action").
Tip
If you intend to express annotation-driven injection by name, do not
primarily use @Autowired, even if is technically capable of referring
to a bean name through @Qualifier values. Instead, use the JSR250 @Resource annotation, which is semantically defined to identify a
specific target component by its unique name, with the declared type
being irrelevant for the matching process.
As a specific consequence of this semantic difference, beans that are
themselves defined as a collection or map type cannot be injected
through @Autowired, because type matching is not properly
Then you can provide the custom qualifier on autowired fields and parameters:
public class MovieRecommender {
@Autowired
@Genre("Action")
private MovieCatalog actionCatalog;
private MovieCatalog comedyCatalog;
@Autowired
public void setComedyCatalog(@Genre("Comedy") MovieCatalog comedyCatalog) {
this.comedyCatalog = comedyCatalog;
}
// ...
}
Next, provide the information for the candidate bean definitions. You can add
<qualifier/> tags as sub-elements of the <bean/> tag and then specify the type and
value to match your custom qualifier annotations. The type is matched against the fullyqualified class name of the annotation. Or, as a convenience if no risk of conflicting names
exists, you can use the short class name. Both approaches are demonstrated in the
following example.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<bean class="example.SimpleMovieCatalog">
<qualifier type="Genre" value="Action"/>
<!-- inject any dependencies required by this bean -->
</bean>
<bean class="example.SimpleMovieCatalog">
<qualifier type="example.Genre" value="Comedy"/>
<!-- inject any dependencies required by this bean -->
</bean>
<bean id="movieRecommender" class="example.MovieRecommender"/>
</beans>
In Section 5.10, Classpath scanning and managed components, you will see an
annotation-based alternative to providing the qualifier metadata in XML. Specifically, see
Section 5.10.7, Providing qualifier metadata with annotations.
In some cases, it may be sufficient to use an annotation without a value. This may be
useful when the annotation serves a more generic purpose and can be applied across
several different types of dependencies. For example, you may provide an offline catalog
several different types of dependencies. For example, you may provide an offline catalog
that would be searched when no Internet connection is available. First define the simple
annotation:
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Offline {
}
You can also define custom qualifier annotations that accept named attributes in addition
to or instead of the simple value attribute. If multiple attribute values are then specified on
a field or parameter to be autowired, a bean definition must match all such attribute values
to be considered an autowire candidate. As an example, consider the following annotation
definition:
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface MovieQualifier {
String genre();
Format format();
}
The fields to be autowired are annotated with the custom qualifier and include values for
both attributes: genre and format.
public class MovieRecommender {
@Autowired
@MovieQualifier(format=Format.VHS, genre="Action")
private MovieCatalog actionVhsCatalog;
@Autowired
@MovieQualifier(format=Format.VHS, genre="Comedy")
private MovieCatalog comedyVhsCatalog;
@Autowired
@MovieQualifier(format=Format.DVD, genre="Action")
private MovieCatalog actionDvdCatalog;
@Autowired
@MovieQualifier(format=Format.BLURAY, genre="Comedy")
private MovieCatalog comedyBluRayCatalog;
// ...
}
Finally, the bean definitions should contain matching qualifier values. This example also
demonstrates that bean meta attributes may be used instead of the <qualifier/> subelements. If available, the <qualifier/> and its attributes take precedence, but the
autowiring mechanism falls back on the values provided within the <meta/> tags if no
such qualifier is present, as in the last two bean definitions in the following example.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<bean class="example.SimpleMovieCatalog">
<qualifier type="MovieQualifier">
<attribute key="format" value="VHS"/>
<attribute key="genre" value="Action"/>
</qualifier>
<!-- inject any dependencies required by this bean -->
</bean>
<bean class="example.SimpleMovieCatalog">
<qualifier type="MovieQualifier">
<attribute key="format" value="VHS"/>
<attribute key="genre" value="Comedy"/>
</qualifier>
<!-- inject any dependencies required by this bean -->
</bean>
<bean class="example.SimpleMovieCatalog">
<meta key="format" value="DVD"/>
<meta key="genre" value="Action"/>
<!-- inject any dependencies required by this bean -->
</bean>
<bean class="example.SimpleMovieCatalog">
<meta key="format" value="BLURAY"/>
<meta key="genre" value="Comedy"/>
<!-- inject any dependencies required by this bean -->
</bean>
</beans>
5.9.4 CustomAutowireConfigurer
The CustomAutowireConfigurer is a BeanFactoryPostProcessor that enables
you to register your own custom qualifier annotation types even if they are not annotated
with Spring's @Qualifier annotation.
<bean id="customAutowireConfigurer"
class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">
<property name="customQualifierTypes">
<set>
<value>example.CustomQualifier</value>
</set>
</property>
</bean>
5.9.5 @Resource
Spring also supports injection using the JSR-250 @Resource annotation on fields or
bean property setter methods. This is a common pattern in Java EE 5 and 6, for example in
JSF 1.2 managed beans or JAX-WS 2.0 endpoints. Spring supports this pattern for Springmanaged objects as well.
@Resource takes a name attribute, and by default Spring interprets that value as the bean
name to be injected. In other words, it follows by-name semantics, as demonstrated in this
example:
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Resource(name="myMovieFinder")
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
}
If no name is specified explicitly, the default name is derived from the field name or setter
method. In case of a field, it takes the field name; in case of a setter method, it takes the
bean property name. So the following example is going to have the bean with name
"movieFinder" injected into its setter method:
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Resource
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
}
Note
The name provided with the annotation is resolved as a bean name by
the ApplicationContext of which the
CommonAnnotationBeanPostProcessor is aware. The names
can be resolved through JNDI if you configure Spring's
SimpleJndiBeanFactory explicitly. However, it is recommended
that you rely on the default behavior and simply use Spring's JNDI
lookup capabilities to preserve the level of indirection.
In the exclusive case of @Resource usage with no explicit name specified, and similar to
@Autowired, @Resource finds a primary type match instead of a specific named bean
and resolves well-known resolvable dependencies: the BeanFactory,
ApplicationContext, ResourceLoader, ApplicationEventPublisher,
and MessageSource interfaces.
Thus in the following example, the customerPreferenceDao field first looks for a bean
named customerPreferenceDao, then falls back to a primary type match for the type
CustomerPreferenceDao. The "context" field is injected based on the known
resolvable dependency type ApplicationContext.
public class MovieRecommender {
@Resource
private CustomerPreferenceDao customerPreferenceDao;
@Resource
private ApplicationContext context;
public MovieRecommender() {
}
// ...
}
Note
For details about the effects of combining various lifecycle
mechanisms, see the section called Combining lifecycle
mechanisms.
carry additional semantics in future releases of the Spring Framework. Thus, if you are
choosing between using @Component or @Service for your service layer, @Service is
clearly the better choice. Similarly, as stated above, @Repository is already supported
as a marker for automatic exception translation in your persistence layer.
To autodetect these classes and register the corresponding beans, you need to include the
following element in XML, where the base-package element is a common parent package
for the two classes. (Alternatively, you can specify a comma-separated list that includes the
parent package of each class.)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="org.example"/>
</beans>
Tip
The use of <context:component-scan> implicitly enables the
functionality of <context:annotation-config>. There is usually
no need to include the <context:annotation-config> element
when using <context:component-scan>.
Note
The scanning of classpath packages requires the presence of
corresponding directory entries in the classpath. When you build JARs
with Ant, make sure that you do not activate the files-only switch of the
JAR task.
Furthermore, the AutowiredAnnotationBeanPostProcessor and
CommonAnnotationBeanPostProcessor are both included implicitly when you use
the component-scan element. That means that the two components are autodetected and
wired together - all without any bean configuration metadata provided in XML.
Note
You can disable the registration of
AutowiredAnnotationBeanPostProcessor and
CommonAnnotationBeanPostProcessor by including the
annotation-config attribute with a value of false.
Example Expression
annotation
org.example.SomeAnnotation
Description
An annotation to be present at the type
level in target components.
assignable org.example.SomeClass
aspectj
org.example..*Service+
regex
org\.example\.Default.*
custom
org.example.MyTypeFilter
The following example shows the XML configuration ignoring all @Repository
annotations and using "stub" repositories instead.
<beans>
<context:component-scan base-package="org.example">
<context:include-filter type="regex" expression=".*Stub.*Repository"/>
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
</beans>
Note
You can also disable the default filters by providing use-defaultfilters="false" as an attribute of the <component-scan/> element. This
will in effect disable automatic detection of classes annotated with
@Component, @Repository, @Service, or @Controller.
}
}
This class is a Spring component that has application-specific code contained in its
doWork() method. However, it also contributes a bean definition that has a factory
method referring to the method publicInstance(). The @Bean annotation identifies
the factory method and other bean definition properties, such as a qualifier value through
the @Qualifier annotation. Other method level annotations that can be specified are
@Scope, @Lazy, and custom qualifier annotations. Autowired fields and methods are
supported as previously discussed, with additional support for autowiring of @Bean
methods:
@Component
public class FactoryMethodComponent {
private static int i;
@Bean @Qualifier("public")
public TestBean publicInstance() {
return new TestBean("publicInstance");
}
// use of a custom qualifier and autowiring of method parameters
@Bean
protected TestBean protectedInstance(@Qualifier("public") TestBean spouse,
@Value("#{privateInstance.age}") String country) {
TestBean tb = new TestBean("protectedInstance", 1);
tb.setSpouse(tb);
tb.setCountry(country);
return tb;
}
@Bean @Scope(BeanDefinition.SCOPE_SINGLETON)
private TestBean privateInstance() {
return new TestBean("privateInstance", i++);
}
@Bean @Scope(value = WebApplicationContext.SCOPE_SESSION,
proxyMode = ScopedProxyMode.TARGET_CLASS)
public TestBean requestScopedInstance() {
return new TestBean("requestScopedInstance", 3);
}
}
The example autowires the String method parameter country to the value of the Age
property on another bean named privateInstance. A Spring Expression Language
element defines the value of the property through the notation #{ <expression> }. For
@Value annotations, an expression resolver is preconfigured to look for bean names
when resolving expression text.
The @Bean methods in a Spring component are processed differently than their
counterparts inside a Spring @Configuration class. The difference is that
@Component classes are not enhanced with CGLIB to intercept the invocation of methods
and fields. CGLIB proxying is the means by which invoking methods or fields within
@Configuration classes @Bean methods create bean metadata references to
collaborating objects. Methods are not invoked with normal Java semantics. In contrast,
calling a method or field within a @Component classes @Bean method has standard Java
semantics.
Note
If you do not want to rely on the default bean-naming strategy, you can
provide a custom bean-naming strategy. First, implement the
BeanNameGenerator interface, and be sure to include a default noarg constructor. Then, provide the fully-qualified class name when
configuring the scanner:
<beans>
<context:component-scan base-package="org.example"
name-generator="org.example.MyNameGenerator" />
</beans>
As a general rule, consider specifying the name with the annotation whenever other
components may be making explicit references to it. On the other hand, the auto-generated
names are adequate whenever the container is responsible for wiring.
Note
To provide a custom strategy for scope resolution rather than relying on
the annotation-based approach, implement the
ScopeMetadataResolver interface, and be sure to include a
default no-arg constructor. Then, provide the fully-qualified class name
when configuring the scanner:
<beans>
<context:component-scan base-package="org.example"
scope-resolver="org.example.MyScopeResolver" />
</beans>
When using certain non-singleton scopes, it may be necessary to generate proxies for the
scoped objects. The reasoning is described in the section called Scoped beans as
dependencies. For this purpose, a scoped-proxy attribute is available on the componentscan element. The three possible values are: no, interfaces, and targetClass. For example,
the following configuration will result in standard JDK dynamic proxies:
<beans>
<context:component-scan base-package="org.example"
scoped-proxy="interfaces" />
</beans>
Note
As with most annotation-based alternatives, keep in mind that the
annotation metadata is bound to the class definition itself, while the use
of XML allows for multiple beans of the same type to provide variations
in their qualifier metadata, because that metadata is provided perinstance rather than per-class.
As with @Autowired, it is possible to use @Inject at the class-level, field-level, methodlevel and constructor-argument level. If you would like to use a qualified name for the
dependency that should be injected, you should use the @Named annotation as follows:
import javax.inject.Inject;
import javax.inject.Named;
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Inject
public void setMovieFinder(@Named("main") MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}
It is very common to use @Component without specifying a name for the component.
@Named can be used in a similar fashion:
import javax.inject.Inject;
import javax.inject.Named;
@Named
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Inject
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}
When using @Named, it is possible to use component-scanning in the exact same way as
when using Spring annotations:
<beans>
<context:component-scan base-package="org.example"/>
</beans>
javax.inject.*
@Autowired
@Inject
@Component
@Named
@Scope("singleton") @Singleton
@Qualifier
@Named
@Value
no equivalent
@Required
no equivalent
@Lazy
no equivalent
methods.
@Configuration
public class AppConfig {
@Bean
public MyService myService() {
return new MyServiceImpl();
}
}
The AppConfig class above would be equivalent to the following Spring <beans/>
XML:
<beans>
<bean id="myService" class="com.acme.services.MyServiceImpl"/>
</beans>
The @Bean and @Configuration annotations will be discussed in depth in the sections
below. First, however, we'll cover the various ways of creating a spring container using
Java-based configuration.
Simple construction
In much the same way that Spring XML files are used as input when instantiating a
ClassPathXmlApplicationContext, @Configuration classes may be used as
input when instantiating an AnnotationConfigApplicationContext. This allows
for completely XML-free usage of the Spring container:
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
MyService myService = ctx.getBean(MyService.class);
myService.doStuff();
}
myService.doStuff();
}
In the example above, the com.acme package will be scanned, looking for any
@Component-annotated classes, and those classes will be registered as Spring bean
definitions within the container. AnnotationConfigApplicationContext exposes
the scan(String...) method to allow for the same component-scanning functionality:
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.scan("com.acme");
ctx.refresh();
MyService myService = ctx.getBean(MyService.class);
}
Note
Remember that @Configuration classes are meta-annotated with
@Component, so they are candidates for component-scanning! In the
example above, assuming that AppConfig is declared within the
com.acme package (or any package underneath), it will be picked up
during the call to scan(), and upon refresh() all its @Bean
methods will be processed and registered as bean definitions within
the container.
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</init-param>
<!-- Again, config locations must consist of one or more comma- or space-delimited
and fully-qualified @Configuration classes -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.acme.web.MvcConfig</param-value>
</init-param>
</servlet>
<!-- map all requests for /app/* to the dispatcher servlet -->
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
</web-app>
Declaring a bean
To declare a bean, simply annotate a method with the @Bean annotation. You use this
method to register a bean definition within an ApplicationContext of the type
specified as the method's return value. By default, the bean name will be the same as the
method name. The following is a simple example of a @Bean method declaration:
@Configuration
public class AppConfig {
@Bean
public TransferService transferService() {
return new TransferServiceImpl();
}
}
Of course, in the case of Foo above, it would be equally as valid to call the init()
method directly during construction:
@Configuration
public class AppConfig {
@Bean
public Foo foo() {
Foo foo = new Foo();
foo.init();
return foo;
}
// ...
}
Tip
When you work directly in Java, you can do anything you like with your
objects and do not always need to rely on the container lifecycle!
Bean aliasing
As discussed in Section 5.3.1, Naming beans, it is sometimes desirable to give a single
bean multiple names, otherwise known as bean aliasing. The name attribute of the @Bean
annotation accepts a String array for this purpose.
@Configuration
public class AppConfig {
@Bean(name = { "dataSource", "subsystemA-dataSource", "subsystemB-dataSource" })
public DataSource dataSource() {
// instantiate, configure and return DataSource bean...
}
}
In the example above, the foo bean receives a reference to bar via constructor injection.
Note
This method of declaring inter-bean dependencies only works when
the @Bean method is declared within a @Configuration class. You
cannot declare inter-bean dependencies using plain @Component
classes.
Now, rather than needing to specify both ConfigA.class and ConfigB.class when
instantiating the context, only ConfigB needs to be supplied explicitly:
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigB.class);
// now both beans A and B will be available...
A a = ctx.getBean(A.class);
B b = ctx.getBean(B.class);
}
This approach simplifies container instantiation, as only one class needs to be dealt with,
rather than requiring the developer to remember a potentially large number of
@Configuration classes during construction.
}
}
@Configuration
public interface RepositoryConfig {
@Bean AccountRepository accountRepository();
}
@Configuration
public class DefaultRepositoryConfig implements RepositoryConfig {
public @Bean AccountRepository accountRepository() {
return new JdbcAccountRepository(...);
}
}
@Configuration
@Import({ServiceConfig.class, DefaultRepositoryConfig.class}) // import the concrete config!
public class SystemTestConfig {
public @Bean DataSource dataSource() { /* return DataSource */ }
}
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);
TransferService transferService = ctx.getBean(TransferService.class);
transferService.transfer(100.00, "A123", "C456");
}
system-test-config.xml
<beans>
<!-- enable processing of annotations such as @Autowired and @Configuration -->
<context:annotation-config/>
<context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>
<bean class="com.acme.AppConfig"/>
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
</beans>
jdbc.properties
jdbc.url=jdbc:hsqldb:hsql://localhost/xdb
jdbc.username=sa
jdbc.password=
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:/com/acme/system-test-config.xml");
TransferService transferService = ctx.getBean(TransferService.class);
// ...
}
Note
In system-test-config.xml above, the AppConfig<bean/>
does not declare an id element. While it would be acceptable to do so,
it is unnecessary given that no other bean will ever refer to it, and it is
unlikely that it will be explicitly fetched from the container by name.
Likewise with the DataSource bean - it is only ever autowired by
type, so an explicit bean id is not strictly required.
jdbc.properties
jdbc.url=jdbc:hsqldb:hsql://localhost/xdb
jdbc.username=sa
jdbc.password=
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
TransferService transferService = ctx.getBean(TransferService.class);
// ...
}
In the example it is assumed you have three resource bundles defined in your classpath
called format, exceptions and windows. Any request to resolve a message will be
handled in the JDK standard way of resolving messages through ResourceBundles. For
the purposes of the example, assume the contents of two of the above resource bundle
files are...
# in format.properties
message=Alligators rock!
# in exceptions.properties
argument.required=The '{0}' argument is required.
The resulting output from the invocation of the execute() method will be...
The userDao argument is required.
The resulting output from the running of the above program will be...
Ebagum lad, the 'userDao' argument is required, I say, required.
You can also use the MessageSourceAware interface to acquire a reference to any
MessageSource that has been defined. Any bean that is defined in an
ApplicationContext that implements the MessageSourceAware interface is
injected with the application context's MessageSource when the bean is created and
configured.
Note
As an alternative to ResourceBundleMessageSource, Spring
provides a ReloadableResourceBundleMessageSource class.
This variant supports the same bundle file format but is more flexible
than the standard JDK based ResourceBundleMessageSource
implementation. In particular, it allows for reading files from any Spring
resource location (not just from the classpath) and supports hot
reloading of bundle property files (while efficiently caching them in
between). Check out the
ReloadableResourceBundleMessageSource javadoc for
details.
Explanation
ContextStartedEvent
ContextStoppedEvent
ContextClosedEvent
RequestHandledEvent
You can also create and publish your own custom events. This example demonstrates a
simple class that extends Spring's ApplicationEvent base class:
public class BlackListEvent extends ApplicationEvent {
private final String address;
private final String test;
public BlackListEvent(Object source, String address, String test) {
super(source);
this.address = address;
this.test = test;
}
// accessor and other methods...
}
}
}
At configuration time, the Spring container will detect that EmailService implements
ApplicationEventPublisherAware and will automatically call
setApplicationEventPublisher(). In reality, the parameter passed in will be the
Spring container itself; you're simply interacting with the application context via its
ApplicationEventPublisher interface.
To receive the custom ApplicationEvent, create a class that implements
ApplicationListener and register it as a Spring bean. The following example
demonstrates such a class:
public class BlackListNotifier implements ApplicationListener<BlackListEvent> {
private String notificationAddress;
public void setNotificationAddress(String notificationAddress) {
this.notificationAddress = notificationAddress;
}
public void onApplicationEvent(BlackListEvent event) {
// notify appropriate parties via notificationAddress...
}
}
Putting it all together, when the sendEmail() method of the emailService bean is
called, if there are any emails that should be blacklisted, a custom event of type
BlackListEvent is published. The blackListNotifier bean is registered as an
ApplicationListener and thus receives the BlackListEvent, at which point it can
notify appropriate parties.
Note
Spring's eventing mechanism is designed for simple communication
between Spring beans within the same application context. However,
for more sophisticated enterprise integration needs, the separatelymaintained Spring Integration project provides complete support for
building lightweight, pattern-oriented, event-driven architectures that
build upon the well-known Spring programming model.
<load-on-startup>1</load-on-startup>
</servlet>
-->
BeanFactory
ApplicationContext
Bean instantiation/wiring
Yes
Yes
Automatic
BeanPostProcessor
registration
No
Yes
Automatic
BeanFactoryPostProcessor No
registration
Yes
Convenient MessageSource
access (for i18n)
No
Yes
ApplicationEvent
publication
No
Yes
In both cases, the explicit registration step is inconvenient, which is one reason why the
various ApplicationContext implementations are preferred above plain
BeanFactory implementations in the vast majority of Spring-backed applications,
especially when using BeanFactoryPostProcessors and BeanPostProcessors.
These mechanisms implement important functionality such as property placeholder
replacement and AOP.
[1]
[2]
See Background
See Section 5.4.1, Dependency injection
6. Resources
6.1 Introduction
Java's standard java.net.URL class and standard handlers for various URL prefixes
unfortunately are not quite adequate enough for all access to low-level resources. For
example, there is no standardized URL implementation that may be used to access a
resource that needs to be obtained from the classpath, or relative to a ServletContext.
While it is possible to register new handlers for specialized URL prefixes (similar to existing
handlers for prefixes such as http:), this is generally quite complicated, and the URL
interface still lacks some desirable functionality, such as a method to check for the
existence of the resource being pointed to.
Some of the most important methods from the Resource interface are:
getInputStream(): locates and opens the resource, returning an InputStream
for reading from the resource. It is expected that each invocation returns a fresh
InputStream. It is the responsibility of the caller to close the stream.
exists(): returns a boolean indicating whether this resource actually exists in
physical form.
isOpen(): returns a boolean indicating whether this resource represents a handle
with an open stream. If true, the InputStream cannot be read multiple times, and
must be read once only and then closed to avoid resource leaks. Will be false for all
usual resource implementations, with the exception of InputStreamResource.
getDescription(): returns a description for this resource, to be used for error
output when working with the resource. This is often the fully qualified file name or the
actual URL of the resource.
Other methods allow you to obtain an actual URL or File object representing the resource
(if the underlying implementation is compatible, and supports that functionality).
The Resource abstraction is used extensively in Spring itself, as an argument type in
many method signatures when a resource is needed. Other methods in some Spring APIs
(such as the constructors to various ApplicationContext implementations), take a
String which in unadorned or simple form is used to create a Resource appropriate to
that context implementation, or via special prefixes on the String path, allow the caller to
specify that a specific Resource implementation must be created and used.
While the Resource interface is used a lot with Spring and by Spring, it's actually very
useful to use as a general utility class by itself in your own code, for access to resources,
even when your code doesn't know or care about any other parts of Spring. While this
couples your code to Spring, it really only couples it to this small set of utility classes,
which are serving as a more capable replacement for URL, and can be considered
equivalent to any other library you would use for this purpose.
It is important to note that the Resource abstraction does not replace functionality: it
wraps it where possible. For example, a UrlResource wraps a URL, and uses the
wrapped URL to do its work.
6.3.1 UrlResource
The UrlResource wraps a java.net.URL, and may be used to access any object that
is normally accessible via a URL, such as files, an HTTP target, an FTP target, etc. All
URLs have a standardized String representation, such that appropriate standardized
prefixes are used to indicate one URL type from another. This includes file: for
accessing filesystem paths, http: for accessing resources via the HTTP protocol, ftp:
for accessing resources via FTP, etc.
A UrlResource is created by Java code explicitly using the UrlResource constructor,
but will often be created implicitly when you call an API method which takes a String
argument which is meant to represent a path. For the latter case, a JavaBeans
PropertyEditor will ultimately decide which type of Resource to create. If the path
string contains a few well-known (to it, that is) prefixes such as classpath:, it will create
an appropriate specialized Resource for that prefix. However, if it doesn't recognize the
prefix, it will assume the this is just a standard URL string, and will create a
UrlResource.
6.3.2 ClassPathResource
This class represents a resource which should be obtained from the classpath. This uses
either the thread context class loader, a given class loader, or a given class for loading
resources.
This Resource implementation supports resolution as java.io.File if the class path
resource resides in the file system, but not for classpath resources which reside in a jar
and have not been expanded (by the servlet engine, or whatever the environment is) to the
filesystem. To address this the various Resource implementations always support
resolution as a java.net.URL.
A ClassPathResource is created by Java code explicitly using the
ClassPathResource constructor, but will often be created implicitly when you call an
API method which takes a String argument which is meant to represent a path. For the
latter case, a JavaBeans PropertyEditor will recognize the special prefix
classpath:on the string path, and create a ClassPathResource in that case.
6.3.3 FileSystemResource
This is a Resource implementation for java.io.File handles. It obviously supports
resolution as a File, and as a URL.
6.3.4 ServletContextResource
This is a Resource implementation for ServletContext resources, interpreting
relative paths within the relevant web application's root directory.
This always supports stream access and URL access, but only allows java.io.File
access when the web application archive is expanded and the resource is physically on
the filesystem. Whether or not it's expanded and on the filesystem like this, or accessed
directly from the JAR or somewhere else like a DB (it's conceivable) is actually dependent
on the Servlet container.
6.3.5 InputStreamResource
A Resource implementation for a given InputStream. This should only be used if no
specific Resource implementation is applicable. In particular, prefer
ByteArrayResource or any of the file-based Resource implementations where
possible.
In contrast to other Resource implementations, this is a descriptor for an already opened
resource - therefore returning true from isOpen(). Do not use it if you need to keep the
resource descriptor somewhere, or if you need to read a stream multiple times.
6.3.6 ByteArrayResource
This is a Resource implementation for a given byte array. It creates a
ByteArrayInputStream for the given byte array.
It's useful for loading content from any given byte array, without having to resort to a singleuse InputStreamResource.
All application contexts implement the ResourceLoader interface, and therefore all
application contexts may be used to obtain Resource instances.
When you call getResource() on a specific application context, and the location path
specified doesn't have a specific prefix, you will get back a Resource type that is
appropriate to that particular application context. For example, assume the following
snippet of code was executed against a ClassPathXmlApplicationContext
instance:
Resource template = ctx.getResource("some/resource/path/myTemplate.txt");
Similarly, one can force a UrlResource to be used by specifying any of the standard
java.net.URL prefixes:
Resource template = ctx.getResource("file:/some/resource/path/myTemplate.txt");
The following table summarizes the strategy for converting Strings to Resources:
Example
classpath: classpath:com/myapp/config.xml
file:
file:/data/config.xml
http:
http://myserver/logo.png
(none)
Explanation
Loaded from the
classpath.
Loaded as a URL, from
the filesystem. [1]
Loaded as a URL.
Depends on the
underlying
(none)
[1]
/data/config.xml
underlying
ApplicationContext.
Note that the resource path has no prefix, so because the application context itself is going
to be used as the ResourceLoader, the resource itself will be loaded via a
The bean definitions will be loaded from the classpath, as a ClassPathResource will
be used. But if you create a FileSystemXmlApplicationContext as follows:
ApplicationContext ctx =
new FileSystemXmlApplicationContext("conf/appContext.xml");
The bean definition will be loaded from a filesystem location, in this case relative to the
current working directory.
Note that the use of the special classpath prefix or a standard URL prefix on the location
path will override the default type of Resource created to load the definition. So this
FileSystemXmlApplicationContext...
ApplicationContext ctx =
new FileSystemXmlApplicationContext("classpath:conf/appContext.xml");
... will actually load its bean definitions from the classpath. However, it is still a
FileSystemXmlApplicationContext. If it is subsequently used as a
ResourceLoader, any unprefixed paths will still be treated as filesystem paths.
Ant-style Patterns
When the path location contains an Ant-style pattern, for example:
/WEB-INF/*-context.xml
com/mycompany/**/applicationContext.xml
file:C:/some/path/*-context.xml
classpath:com/mycompany/**/applicationContext.xml
... the resolver follows a more complex but defined procedure to try to resolve the wildcard.
It produces a Resource for the path up to the last non-wildcard segment and obtains a URL
from it. If this URL is not a "jar:" URL or container-specific variant (e.g. "zip:" in
WebLogic, "wsjar" in WebSphere, etc.), then a java.io.File is obtained from it and
used to resolve the wildcard by traversing the filesystem. In the case of a jar URL, the
resolver either gets a java.net.JarURLConnection from it or manually parses the jar
URL and then traverses the contents of the jar file to resolve the wildcards.
Implications on portability
If the specified path is already a file URL (either explicitly, or implicitly because the base
ResourceLoader is a filesystem one, then wildcarding is guaranteed to work in a
completely portable fashion.
If the specified path is a classpath location, then the resolver must obtain the last nonwildcard path segment URL via a Classloader.getResource() call. Since this is
just a node of the path (not the file at the end) it is actually undefined (in the
ClassLoader Javadocs) exactly what sort of a URL is returned in this case. In practice, it
is always a java.io.File representing the directory, where the classpath resource
resolves to a filesystem location, or a jar URL of some sort, where the classpath resource
resolves to a jar location. Still, there is a portability concern on this operation.
If a jar URL is obtained for the last non-wildcard segment, the resolver must be able to get
a java.net.JarURLConnection from it, or manually parse the jar URL, to be able to
walk the contents of the jar, and resolve the wildcard. This will work in most environments,
but will fail in others, and it is strongly recommended that the wildcard resolution of
resources coming from jars be thoroughly tested in your specific environment before you
rely on it.
This special prefix specifies that all classpath resources that match the given name must
be obtained (internally, this essentially happens via a
ClassLoader.getResources(...) call), and then merged to form the final
application context definition.
Classpath*: portability
The wildcard classpath relies on the getResources() method of the underlying
classloader. As most application servers nowadays supply their own classloader
implementation, the behavior might differ especially when dealing with jar files. A simple test
to check if classpath* works is to use the classloader to load a file from within a jar on the
classpath:
getClass().getClassLoader().getResources("<someFileInsideTheJar>").
Try this test with files that have the same name but are placed inside two different locations. In
case an inappropriate result is returned, check the application server documentation for
settings that might affect the classloader behavior.
The "classpath*:" prefix can also be combined with a PathMatcher pattern in the
rest of the location path, for example "classpath*:META-INF/*-beans.xml". In this
case, the resolution strategy is fairly simple: a ClassLoader.getResources() call is used on
the last non-wildcard path segment to get all the matching resources in the class loader
hierarchy, and then off each resource the same PathMatcher resolution strategy described
above is used for the wildcard subpath.
is used to try to resolve it, the resolver will work off the (first) URL returned by
getResource("com/mycompany");. If this base package node exists in multiple
classloader locations, the actual end resource may not be underneath. Therefore,
preferably, use "classpath*:" with the same Ant-style pattern in such a case, which will
search all class path locations that contain the root package.
As are the following: (Even though it would make sense for them to be different, as one
case is relative and the other absolute.)
FileSystemXmlApplicationContext ctx = ...;
ctx.getResource("some/resource/path/myTemplate.txt");
FileSystemXmlApplicationContext ctx = ...;
ctx.getResource("/some/resource/path/myTemplate.txt");
In practice, if true absolute filesystem paths are needed, it is better to forgo the use of
absolute paths with FileSystemResource /
FileSystemXmlApplicationContext, and just force the use of a UrlResource, by
using the file: URL prefix.
// actual context type doesn't matter, the Resource will always be UrlResource
ctx.getResource("file:/some/resource/path/myTemplate.txt");
We're going to provide validation behavior for the Person class by implementing the
following two methods of the org.springframework.validation.Validator
interface:
supports(Class) - Can this Validator validate instances of the supplied
Class?
validate(Object, org.springframework.validation.Errors) validates the given object and in case of validation errors, registers those with the
given Errors object
Implementing a Validator is fairly straightforward, especially when you know of the
ValidationUtils helper class that the Spring Framework also provides.
public class PersonValidator implements Validator {
/**
* This Validator validates *just* Person instances
*/
public boolean supports(Class clazz) {
return Person.class.equals(clazz);
}
public void validate(Object obj, Errors e) {
ValidationUtils.rejectIfEmpty(e, "name", "name.empty");
Person p = (Person) obj;
if (p.getAge() < 0) {
e.rejectValue("age", "negativevalue");
} else if (p.getAge() > 110) {
e.rejectValue("age", "too.darn.old");
}
}
}
the nested objects in a rich object, it may be better to encapsulate the validation logic for
each nested class of object in its own Validator implementation. A simple example of a
'rich' object would be a Customer that is composed of two String properties (a first and
second name) and a complex Address object. Address objects may be used
independently of Customer objects, and so a distinct AddressValidator has been
implemented. If you want your CustomerValidator to reuse the logic contained within
the AddressValidator class without resorting to copy-and-paste, you can dependencyinject or instantiate an AddressValidator within your CustomerValidator, and use
it like so:
public class CustomerValidator implements Validator {
private final Validator addressValidator;
public CustomerValidator(Validator addressValidator) {
if (addressValidator == null) {
throw new IllegalArgumentException(
"The supplied [Validator] is required and must not be null.");
}
if (!addressValidator.supports(Address.class)) {
throw new IllegalArgumentException(
"The supplied [Validator] must support the validation of [Address] instances.");
}
this.addressValidator = addressValidator;
}
/**
* This Validator validates Customer instances, and any subclasses of Customer too
*/
public boolean supports(Class clazz) {
return Customer.class.isAssignableFrom(clazz);
}
public void validate(Object target, Errors errors) {
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "firstName", "field.required");
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "surname", "field.required");
Customer customer = (Customer) target;
try {
errors.pushNestedPath("address");
ValidationUtils.invokeValidator(this.addressValidator, customer.getAddress(), errors);
} finally {
errors.popNestedPath();
}
}
}
Validation errors are reported to the Errors object passed to the validator. In case of
Spring Web MVC you can use <spring:bind/> tag to inspect the error messages, but
of course you can also inspect the errors object yourself. More information about the
methods it offers can be found from the Javadoc.
More information on the MessageCodesResolver and the default strategy can be found
online with the Javadocs for MessageCodesResolver and DefaultMessageCodesResolver
respectively.
Explanation
name
account.name
account[2]
Below you'll find some examples of working with the BeanWrapper to get and set
properties.
(This next section is not vitally 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;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Employee getManagingDirector() {
return this.managingDirector;
}
public void setManagingDirector(Employee managingDirector) {
this.managingDirector = managingDirector;
}
}
public class Employee {
private String name;
private float salary;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public float getSalary() {
return salary;
}
public void setSalary(float salary) {
this.salary = salary;
}
}
The following code snippets show some examples of how to retrieve and manipulate some
of the properties of instantiated Companies and Employees:
BeanWrapper company = BeanWrapperImpl(new Company());
// setting the company name..
company.setPropertyValue("name", "Some Company Inc.");
// ... can also be done like this:
PropertyValue value = new PropertyValue("name", "Some Company Inc.");
company.setPropertyValue(value);
// ok, let's create the director and tie it to the company:
BeanWrapper jim = BeanWrapperImpl(new Employee());
jim.setPropertyValue("name", "Jim Stravinsky");
company.setPropertyValue("managingDirector", jim.getWrappedInstance());
// retrieving the salary of the managingDirector through the company
Float salary = (Float) company.getPropertyValue("managingDirector.salary");
Explanation
ClassEditor
CustomBooleanEditor
CustomCollectionEditor
CustomDateEditor
CustomNumberEditor
FileEditor
InputStreamEditor
LocaleEditor
PropertiesEditor
StringTrimmerEditor
URLEditor
Note that you can also use the standard BeanInfo JavaBeans mechanism here as well
(described in not-amazing-detail here). Find below an example of using the BeanInfo
mechanism for explicitly registering one or more PropertyEditor instances with the
properties of an associated class.
com
chank
pop
Foo
FooBeanInfo
Here is the Java source code for the referenced FooBeanInfo class. This would
associate a CustomNumberEditor with the age property of the Foo class.
public class FooBeanInfo extends SimpleBeanInfo {
public PropertyDescriptor[] getPropertyDescriptors() {
try {
final PropertyEditor numberPE = new CustomNumberEditor(Integer.class, true);
PropertyDescriptor ageDescriptor = new PropertyDescriptor("age", Foo.class) {
public PropertyEditor createPropertyEditor(Object bean) {
return numberPE;
};
};
return new PropertyDescriptor[] { ageDescriptor };
}
catch (IntrospectionException ex) {
throw new Error(ex.toString());
}
}
}
When things are properly set up, we want to be able to assign the type property as a string,
which a PropertyEditor will behind the scenes convert into an actual ExoticType
instance:
<bean id="sample" class="example.DependsOnExoticType">
<property name="type" value="aNameForExoticType"/>
</bean>
package example;
public class ExoticTypeEditor extends PropertyEditorSupport {
public void setAsText(String text) {
setValue(new ExoticType(text.toUpperCase()));
}
}
Using PropertyEditorRegistrars
Another mechanism for registering property editors with the Spring container is to create
and use a PropertyEditorRegistrar. This interface is particularly useful when you
need to use the same set of property editors in several different situations: write a
corresponding registrar and reuse that in each case. PropertyEditorRegistrars
work in conjunction with an interface called PropertyEditorRegistry, an interface
that is implemented by the Spring BeanWrapper (and DataBinder).
PropertyEditorRegistrars are particularly convenient when used in conjunction
with the CustomEditorConfigurer (introduced here), which exposes a property called
setPropertyEditorRegistrars(..): PropertyEditorRegistrars added to a
CustomEditorConfigurer in this fashion can easily be shared with DataBinder
and Spring MVC Controllers. Furthermore, it avoids the need for synchronization on
custom editors: a PropertyEditorRegistrar is expected to create fresh
PropertyEditor instances for each bean creation attempt.
Using a PropertyEditorRegistrar is perhaps best illustrated with an example. First
off, you need to create your own PropertyEditorRegistrar implementation:
package com.foo.editors.spring;
public final class CustomPropertyEditorRegistrar implements PropertyEditorRegistrar {
public void registerCustomEditors(PropertyEditorRegistry registry) {
// it is expected that new PropertyEditor instances are created
registry.registerCustomEditor(ExoticType.class, new ExoticTypeEditor());
// you could register as many custom property editors as are required here...
}
}
Finally, and in a bit of a departure from the focus of this chapter, for those of you using
Spring's MVC web framework, using PropertyEditorRegistrars in conjunction with
data-binding Controllers (such as SimpleFormController) can be very
convenient. Find below an example of using a PropertyEditorRegistrar in the
implementation of an initBinder(..) method:
public final class RegisterUserController extends SimpleFormController {
private final PropertyEditorRegistrar customPropertyEditorRegistrar;
public RegisterUserController(PropertyEditorRegistrar propertyEditorRegistrar) {
this.customPropertyEditorRegistrar = propertyEditorRegistrar;
}
protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder)
throws Exception {
this.customPropertyEditorRegistrar.registerCustomEditors(binder);
}
// other methods to do with registering a User
}
This style of PropertyEditor registration can lead to concise code (the implementation
of initBinder(..) is just one line long!), and allows common PropertyEditor
registration code to be encapsulated in a class and then shared amongst as many
Controllers as needed.
To create your own Converter, simply implement the interface above. Parameterize S as
the type you are converting from, and T as the type you are converting to. For each call to
convert(S), the source argument is guaranteed to be NOT null. Your Converter may throw
any Exception if conversion fails. An IllegalArgumentException should be thrown to report
an invalid source value. Take care to ensure your Converter implementation is thread-safe.
Several converter implementations are provided in the core.convert.support
package as a convenience. These include converters from Strings to Numbers and other
common types. Consider StringToInteger as an example Converter implementation:
package org.springframework.core.convert.support;
final class StringToInteger implements Converter<String, Integer> {
public Integer convert(String source) {
return Integer.valueOf(source);
}
}
7.5.2 ConverterFactory
When you need to centralize the conversion logic for an entire class hierarchy, for
example, when converting from String to java.lang.Enum objects, implement
ConverterFactory:
package org.springframework.core.convert.converter;
public interface ConverterFactory<S, R> {
<T extends R> Converter<S, T> getConverter(Class<T> targetType);
}
Parameterize S to be the type you are converting from and R to be the base type defining
the range of classes you can convert to. Then implement getConverter(Class<T>), where T
is a subclass of R.
Consider the StringToEnum ConverterFactory as an example:
package org.springframework.core.convert.support;
final class StringToEnumConverterFactory implements ConverterFactory<String, Enum> {
public <T extends Enum> Converter<String, T> getConverter(Class<T> targetType) {
return new StringToEnumConverter(targetType);
}
private final class StringToEnumConverter<T extends Enum> implements Converter<String, T> {
private Class<T> enumType;
public StringToEnumConverter(Class<T> enumType) {
this.enumType = enumType;
}
public T convert(String source) {
return (T) Enum.valueOf(this.enumType, source.trim());
}
}
}
7.5.3 GenericConverter
When you require a sophisticated Converter implementation, consider the
GenericConverter interface. With a more flexible but less strongly typed signature, a
GenericConverter supports converting between multiple source and target types. In
addition, a GenericConverter makes available source and target field context you can use
when implementing your conversion logic. Such context allows a type conversion to be
driven by a field annotation, or generic information declared on a field signature.
package org.springframework.core.convert.converter;
public interface GenericConverter {
public Set<ConvertiblePair> getConvertibleTypes();
Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
}
Note
Because GenericConverter is a more complex SPI interface, only use it
when you need it. Favor Converter or ConverterFactory for basic type
conversion needs.
ConditionalGenericConverter
Sometimes you only want a Converter to execute if a specific condition holds true. For
example, you might only want to execute a Converter if a specific annotation is present on
the target field. Or you might only want to execute a Converter if a specific method, such as
static valueOf method, is defined on the target class. ConditionalGenericConverter is an
subinterface of GenericConverter that allows you to define such custom matching criteria:
public interface ConditionalGenericConverter extends GenericConverter {
boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType);
}
In general, use the Converter SPI when you need to implement general-purpose type
conversion logic; for example, for converting between a java.util.Date and and
java.lang.Long. Use the Formatter SPI when you're working in a client environment, such
as a web application, and need to parse and print localized field values. The
ConversionService provides a unified type conversion API for both SPIs.
Where Formatter extends from the Printer and Parser building-block interfaces:
public interface Printer<T> {
String print(T fieldValue, Locale locale);
}
import java.text.ParseException;
public interface Parser<T> {
T parse(String clientValue, Locale locale) throws ParseException;
}
To create your own Formatter, simply implement the Formatter interface above.
Parameterize T to be the type of object you wish to format, for example,
java.util.Date. Implement the print() operation to print an instance of T for display
in the client locale. Implement the parse() operation to parse an instance of T from the
formatted representation returned from the client locale. Your Formatter should throw a
ParseException or IllegalArgumentException if a parse attempt fails. Take care to ensure
your Formatter implementation is thread-safe.
Several Formatter implementations are provided in format subpackages as a
convenience. The number package provides a NumberFormatter, CurrencyFormatter, and
PercentFormatter to format java.lang.Number objects using a java.text.NumberFormat. The
datetime package provides a DateFormatter to format java.util.Date objects with a
java.text.DateFormat. The datetime.joda package provides comprehensive datetime
formatting support based on the Joda Time library.
Consider DateFormatter as an example Formatter implementation:
package org.springframework.format.datetime;
public final class DateFormatter implements Formatter<Date> {
private String pattern;
public DateFormatter(String pattern) {
this.pattern = pattern;
}
public String print(Date date, Locale locale) {
if (date == null) {
return "";
}
return getDateFormat(locale).format(date);
}
public Date parse(String formatted, Locale locale) throws ParseException {
if (formatted.length() == 0) {
return null;
}
return getDateFormat(locale).parse(formatted);
}
protected DateFormat getDateFormat(Locale locale) {
DateFormat dateFormat = new SimpleDateFormat(this.pattern, locale);
dateFormat.setLenient(false);
return dateFormat;
}
Parameterize A to be the field annotationType you wish to associate formatting logic with,
for example org.springframework.format.annotation.DateTimeFormat.
Have getFieldTypes() return the types of fields the annotation may be used on. Have
getPrinter() return a Printer to print the value of an annotated field. Have
getParser() return a Parser to parse a clientValue for an annotated field.
The example AnnotationFormatterFactory implementation below binds the
@NumberFormat Annotation to a formatter. This annotation allows either a number style or
pattern to be specified:
public final class NumberFormatAnnotationFormatterFactory
implements AnnotationFormatterFactory<NumberFormat> {
public Set<Class<?>> getFieldTypes() {
return new HashSet<Class<?>>(asList(new Class<?>[] {
Short.class, Integer.class, Long.class, Float.class,
Double.class, BigDecimal.class, BigInteger.class }));
}
public Printer<Number> getPrinter(NumberFormat annotation, Class<?> fieldType) {
return configureFormatterFrom(annotation, fieldType);
}
public Parser<Number> getParser(NumberFormat annotation, Class<?> fieldType) {
return configureFormatterFrom(annotation, fieldType);
}
private Formatter<Number> configureFormatterFrom(NumberFormat annotation,
Class<?> fieldType) {
if (!annotation.pattern().isEmpty()) {
return new NumberFormatter(annotation.pattern());
} else {
Style style = annotation.style();
if (style == Style.PERCENT) {
return new PercentFormatter();
} else if (style == Style.CURRENCY) {
return new CurrencyFormatter();
} else {
return new NumberFormatter();
}
}
}
}
With this one-line of configuration, default formatters for Numbers and Date types will be
installed, including support for the @NumberFormat and @DateTimeFormat annotations.
Full support for the Joda Time formatting library is also installed if Joda Time is present on
the classpath.
To inject a ConversionService instance with custom formatters and converters registered,
set the conversion-service attribute and then specify custom converters, formatters, or
FormatterRegistrars as properties of the FormattingConversionServiceFactoryBean:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven conversion-service="conversionService"/>
<bean id="conversionService"
class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="org.example.MyConverter"/>
</set>
</property>
<property name="formatters">
<set>
<bean class="org.example.MyFormatter"/>
<bean class="org.example.MyAnnotationFormatterFactory"/>
</set>
</property>
<property name="formatterRegistrars">
<set>
<bean class="org.example.MyFormatterRegistrar"/>
</set>
</property>
</bean>
</beans>
Note
See Section 7.6.4, FormatterRegistrar SPI and the
FormattingConversionServiceFactoryBean for more
information on when to use FormatterRegistrars.
Note
Joda Time provides separate distinct types to represent date, time
and date-time values. The dateFormatter, timeFormatter
and dateTimeFormatter properties of the
JodaTimeFormatterRegistrar should be used to configure the
different formats for each type. The
DateTimeFormatterFactoryBean provides a convenient way to
create formatters.
If you are using Spring MVC remember to explicitly configure the conversion service that is
used. For Java based @Configuration this means extending the
WebMvcConfigurationSupport class and overriding the
mvcConversionService() method. For XML you should use the 'conversionservice' attribute of the mvc:annotation-driven element. See Section 7.6.5,
Configuring Formatting in Spring MVC for details.
JSR-303 allows you to define declarative validation constraints against such properties:
public class PersonForm {
@NotNull
@Size(max=64)
private String name;
@Min(0)
private int age;
}
When an instance of this class is validated by a JSR-303 Validator, these constraints will
be enforced.
For general information on JSR-303, see the Bean Validation Specification. For
information on the specific capabilities of the default reference implementation, see the
Hibernate Validator documentation. To learn how to setup a JSR-303 implementation as a
Spring bean, keep reading.
The basic configuration above will trigger JSR-303 to initialize using its default bootstrap
mechanism. A JSR-303 provider, such as Hibernate Validator, is expected to be present in
the classpath and will be detected automatically.
Injecting a Validator
most cases. There are a number of other configuration options for various JSR-303
constructs, from message interpolation to traversal resolution. See the JavaDocs of
LocalValidatorFactoryBean for more information on these options.
Spring MVC will validate a @Valid object after binding so-long as an appropriate Validator
has been configured.
Note
The @Valid annotation is part of the standard JSR-303 Bean
Validation API, and is not a Spring-specific construct.
To combine a global and a local validator, configure the global validator as shown above
and then add a local validator:
@Controller
public class MyController {
@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.addValidators(new FooValidator());
}
}
With this minimal configuration, anytime a @Valid @Controller input is encountered, it will
be validated by the JSR-303 provider. JSR-303, in turn, will enforce any constraints
declared against the input. Any ConstraintViolations will automatically be exposed as
errors in the BindingResult renderable by standard Spring MVC form tags.
While there are several other Java expression languages available, OGNL, MVEL, and
JBoss EL, to name a few, the Spring Expression Language was created to provide the
Spring community with a single well supported expression language that can be used
across all the products in the Spring portfolio. Its language features are driven by the
requirements of the projects in the Spring portfolio, including tooling requirements for code
completion support within the eclipse based SpringSource Tool Suite. That said, SpEL is
based on a technology agnostic API allowing other expression language implementations
to be integrated should the need arise.
While SpEL serves as the foundation for expression evaluation within the Spring portfolio,
it is not directly tied to Spring and can be used independently. In order to be self contained,
many of the examples in this chapter use SpEL as if it were an independent expression
language. This requires creating a few bootstrapping infrastructure classes such as the
parser. Most Spring users will not need to deal with this infrastructure and will instead only
author expression strings for evaluation. An example of this typical use is the integration of
SpEL into creating XML or annotated based bean definitions as shown in the section
Expression support for defining bean definitions.
This chapter covers the features of the expression language, its API, and its language
syntax. In several places an Inventor and Inventor's Society class are used as the target
objects for expression evaluation. These class declarations and the data used to populate
them are listed at the end of the chapter.
The SpEL classes and interfaces you are most likely to use are located in the packages
org.springframework.expression and its sub packages and spel.support.
The interface ExpressionParser is responsible for parsing an expression string. In this
example the expression string is a string literal denoted by the surrounding single quotes.
The interface Expression is responsible for evaluating the previously defined
expression string. There are two exceptions that can be thrown, ParseException and
EvaluationException when calling 'parser.parseExpression' and
'exp.getValue' respectively.
SpEL supports a wide range of features, such as calling methods, accessing properties,
and calling constructors.
As an example of method invocation, we call the 'concat' method on the string literal.
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("'Hello World'.concat('!')");
String message = (String) exp.getValue();
SpEL also supports nested properties using standard 'dot' notation, i.e. prop1.prop2.prop3
and the setting of property values
Public fields may also be accessed.
ExpressionParser parser = new SpelExpressionParser();
// invokes 'getBytes().length'
Expression exp = parser.parseExpression("'Hello World'.bytes.length");
int length = (Integer) exp.getValue();
In the last line, the value of the string variable 'name' will be set to "Nikola Tesla". The
class StandardEvaluationContext is where you can specify which object the "name"
property will be evaluated against. This is the mechanism to use if the root object is
unlikely to change, it can simply be set once in the evaluation context. If the root object is
likely to change repeatedly, it can be supplied on each call to getValue, as this next
example shows:
/ Create and set a calendar
GregorianCalendar c = new GregorianCalendar();
c.set(1856, 7, 9);
// The constructor arguments are name, birthday, and nationality.
Inventor tesla = new Inventor("Nikola Tesla", c.getTime(), "Serbian");
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("name");
String name = (String) exp.getValue(tesla);
In this case the inventor tesla has been supplied directly to getValue and the
expression evaluation infrastructure creates and manages a default evaluation context
internally - it did not require one to be supplied.
The StandardEvaluationContext is relatively expensive to construct and during repeated
usage it builds up cached state that enables subsequent expression evaluations to be
performed more quickly. For this reason it is better to cache and reuse them where
possible, rather than construct a new one for each expression evaluation.
In some cases it can be desirable to use a configured evaluation context and yet still
supply a different root object on each call to getValue. getValue allows both to be
specified on the same call. In these situations the root object passed on the call is
considered to override any (which maybe null) specified on the evaluation context.
Note
In standalone usage of SpEL there is a need to create the parser, parse
expressions and perhaps provide evaluation contexts and a root
context object. However, more common usage is to provide only the
SpEL expression string as part of a configuration file, for example for
Spring bean or Spring Web Flow definitions. In this case, the parser,
evaluation context, root object and any predefined variables are all set
up implicitly, requiring the user to specify nothing other than the
expressions.
As a final introductory example, the use of a boolean operator is shown using the Inventor
object in the previous example.
Expression exp = parser.parseExpression("name == 'Nikola Tesla'");
boolean result = exp.getValue(context, Boolean.class); // evaluates to true
Type Conversion
By default SpEL uses the conversion service available in Spring core
(org.springframework.core.convert.ConversionService). This conversion
service comes with many converters built in for common conversions but is also fully
extensible so custom conversions between types can be added. Additionally it has the key
capability that it is generics aware. This means that when working with generic types in
expressions, SpEL will attempt conversions to maintain type correctness for any objects it
encounters.
What does this mean in practice? Suppose assignment, using setValue(), is being
used to set a List property. The type of the property is actually List<Boolean>. SpEL
will recognize that the elements of the list need to be converted to Boolean before being
placed in it. A simple example:
class Simple {
public List<Boolean> booleanList = new ArrayList<Boolean>();
}
Simple simple = new Simple();
simple.booleanList.add(true);
StandardEvaluationContext simpleContext = new StandardEvaluationContext(simple);
// false is passed in here as a string. SpEL and the conversion service will
// correctly recognize that it needs to be a Boolean and convert it
parser.parseExpression("booleanList[0]").setValue(simpleContext, "false");
// b will be false
Boolean b = simple.booleanList.get(0);
You can also refer to other bean properties by name, for example.
<bean id="numberGuess" class="org.spring.samples.NumberGuess">
<property name="randomNumber" value="#{ T(java.lang.Math).random() * 100.0 }"/>
<!-- other properties -->
</bean>
<bean id="shapeGuess" class="org.spring.samples.ShapeGuess">
<property name="initialShapeSeed" value="#{ numberGuess.randomNumber }"/>
<!-- other properties -->
</bean>
Autowired methods and constructors can also use the @Value annotation.
public class SimpleMovieLister {
private MovieFinder movieFinder;
private String defaultLocale;
@Autowired
public void configure(MovieFinder movieFinder,
@Value("#{ systemProperties['user.region'] }") String defaultLocale) {
this.movieFinder = movieFinder;
this.defaultLocale = defaultLocale;
}
// ...
}
// ...
}
= (Double) parser.parseExpression("6.0221415E+23").getValue();
// evals to 2147483647
int maxValue = (Integer) parser.parseExpression("0x7FFFFFFF").getValue();
boolean trueValue = (Boolean) parser.parseExpression("true").getValue();
Object nullValue = parser.parseExpression("null").getValue();
Numbers support the use of the negative sign, exponential notation, and decimal points.
By default real numbers are parsed using Double.parseDouble().
Case insensitivity is allowed for the first letter of property names. The contents of arrays
and lists are obtained using square bracket notation.
ExpressionParser parser = new SpelExpressionParser();
// Inventions Array
StandardEvaluationContext teslaContext = new StandardEvaluationContext(tesla);
// evaluates to "Induction motor"
String invention = parser.parseExpression("inventions[3]").getValue(teslaContext,
String.class);
// Members List
StandardEvaluationContext societyContext = new StandardEvaluationContext(ieee);
// evaluates to "Nikola Tesla"
String name = parser.parseExpression("Members[0].Name").getValue(societyContext, String.class);
// List and Array navigation
// evaluates to "Wireless communication"
String invention = parser.parseExpression("Members[0].Inventions[6]").getValue(societyContext,
String.class);
The contents of maps are obtained by specifying the literal key value within the brackets. In
this case, because keys for the Officers map are strings, we can specify string literals.
// Officer's Dictionary
{} by itself means an empty list. For performance reasons, if the list is itself entirely
composed of fixed literals then a constant list is created to represent the expression, rather
than building a new list on each evaluation.
8.5.5 Methods
Methods are invoked using typical Java programming syntax. You may also invoke
methods on literals. Varargs are also supported.
// string literal, evaluates to "bc"
String c = parser.parseExpression("'abc'.substring(2, 3)").getValue(String.class);
// evaluates to true
boolean isMember = parser.parseExpression("isMember('Mihajlo Pupin')").getValue(societyContext,
Boolean.class);
8.5.6 Operators
Relational operators
The relational operators; equal, not equal, less than, less than or equal, greater than, and
greater than or equal are supported using standard operator notation.
// evaluates to true
boolean trueValue = parser.parseExpression("2 == 2").getValue(Boolean.class);
// evaluates to false
boolean falseValue = parser.parseExpression("2 < -5.0").getValue(Boolean.class);
// evaluates to true
boolean trueValue = parser.parseExpression("'black' < 'block'").getValue(Boolean.class);
In addition to standard relational operators SpEL supports the 'instanceof' and regular
expression based 'matches' operator.
// evaluates to false
boolean falseValue = parser.parseExpression("'xyz' instanceof T(int)").getValue(Boolean.class);
// evaluates to true
boolean trueValue =
parser.parseExpression("'5.00' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class);
//evaluates to false
boolean falseValue =
parser.parseExpression("'5.0067' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class);
Each symbolic operator can also be specified as a purely alphabetic equivalent. This
avoids problems where the symbols used have special meaning for the document type in
which the expression is embedded (eg. an XML document). The textual equivalents are
shown here: lt ('<'), gt ('>'), le ('<='), ge ('>='), eq ('=='), ne ('!='), div ('/'), mod ('%'), not ('!').
These are case insensitive.
Logical operators
The logical operators that are supported are and, or, and not. Their use is demonstrated
below.
// -- AND -// evaluates to false
boolean falseValue = parser.parseExpression("true and false").getValue(Boolean.class);
// evaluates to true
String expression = "isMember('Nikola Tesla') and isMember('Mihajlo Pupin')";
boolean trueValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class);
// -- OR -// evaluates to true
boolean trueValue = parser.parseExpression("true or false").getValue(Boolean.class);
// evaluates to true
String expression = "isMember('Nikola Tesla') or isMember('Albert Einstein')";
boolean trueValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class);
// -- NOT -// evaluates to false
boolean falseValue = parser.parseExpression("!true").getValue(Boolean.class);
// -- AND and NOT -String expression = "isMember('Nikola Tesla') and !isMember('Mihajlo Pupin')";
boolean falseValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class);
Mathematical operators
The addition operator can be used on numbers, strings and dates. Subtraction can be used
on numbers and dates. Multiplication and division can be used only on numbers. Other
mathematical operators supported are modulus (%) and exponential power (^). Standard
operator precedence is enforced. These operators are demonstrated below.
// Addition
int two = parser.parseExpression("1 + 1").getValue(Integer.class); // 2
String testString =
parser.parseExpression("'test' + ' ' + 'string'").getValue(String.class);
// 'test string'
// Subtraction
int four = parser.parseExpression("1 - -3").getValue(Integer.class); // 4
double d = parser.parseExpression("1000.00 - 1e4").getValue(Double.class); // -9000
// Multiplication
int six = parser.parseExpression("-2 * -3").getValue(Integer.class); // 6
double twentyFour = parser.parseExpression("2.0 * 3e0 * 4").getValue(Double.class); // 24.0
// Division
int minusTwo =
parser.parseExpression("6 / -3").getValue(Integer.class); // -2
parser.parseExpression("7 % 4").getValue(Integer.class); // 3
8.5.7 Assignment
Setting of a property is done by using the assignment operator. This would typically be
done within a call to setValue but can also be done inside a call to getValue.
Inventor inventor = new Inventor();
StandardEvaluationContext inventorContext = new StandardEvaluationContext(inventor);
parser.parseExpression("Name").setValue(inventorContext, "Alexander Seovic2");
// alternatively
String aleks = parser.parseExpression("Name = 'Alexandar Seovic'").getValue(inventorContext,
String.class);
8.5.8 Types
The special 'T' operator can be used to specify an instance of java.lang.Class (the 'type').
Static methods are invoked using this operator as well. The
StandardEvaluationContext uses a TypeLocator to find types and the
StandardTypeLocator (which can be replaced) is built with an understanding of the
java.lang package. This means T() references to types within java.lang do not need to be
fully qualified, but all other type references must be.
Class dateClass = parser.parseExpression("T(java.util.Date)").getValue(Class.class);
Class stringClass = parser.parseExpression("T(String)").getValue(Class.class);
boolean trueValue =
parser.parseExpression("T(java.math.RoundingMode).CEILING < T(java.math.RoundingMode).FLOOR")
.getValue(Boolean.class);
8.5.9 Constructors
Constructors can be invoked using the new operator. The fully qualified class name should
be used for all but the primitive type and String (where int, float, etc, can be used).
Inventor einstein =
p.parseExpression("new org.spring.samples.spel.inventor.Inventor('Albert Einstein',
'German')")
.getValue(Inventor.class);
//create new inventor instance within add method of List
p.parseExpression("Members.add(new org.spring.samples.spel.inventor.Inventor('Albert Einstein',
'German'))")
.getValue(societyContext);
8.5.10 Variables
Variables can be referenced in the expression using the syntax #variableName. Variables
are set using the method setVariable on the StandardEvaluationContext.
Inventor tesla = new Inventor("Nikola Tesla", "Serbian");
StandardEvaluationContext context = new StandardEvaluationContext(tesla);
context.setVariable("newName", "Mike Tesla");
parser.parseExpression("Name = #newName").getValue(context);
System.out.println(tesla.getName()) // "Mike Tesla"
The variable #this is always defined and refers to the current evaluation object (against
which unqualified references are resolved). The variable #root is always defined and refers
to the root context object. Although #this may vary as components of an expression are
evaluated, #root always refers to the root.
// create an array of integers
List<Integer> primes = new ArrayList<Integer>();
primes.addAll(Arrays.asList(2,3,5,7,11,13,17));
// create parser and set variable 'primes' as the array of integers
ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext();
context.setVariable("primes",primes);
// all prime numbers > 10 from the list (using selection ?{...})
// evaluates to [11, 13, 17]
List<Integer> primesGreaterThanTen =
(List<Integer>) parser.parseExpression("#primes.?[#this>10]").getValue(context);
8.5.11 Functions
You can extend SpEL by registering user defined functions that can be called within the
expression string. The function is registered with the StandardEvaluationContext
using the method.
public void registerFunction(String name, Method m)
A reference to a Java Method provides the implementation of the function. For example, a
utility method to reverse a string is shown below.
public abstract class StringUtils {
public static String reverseString(String input) {
StringBuilder backwards = new StringBuilder();
for (int i = 0; i < input.length(); i++)
backwards.append(input.charAt(input.length() - 1 - i));
}
return backwards.toString();
}
}
This method is then registered with the evaluation context and can be used within an
expression string.
ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext();
context.registerFunction("reverseString",
StringUtils.class.getDeclaredMethod("reverseString",
new Class[] { String.class }));
String helloWorldReversed =
parser.parseExpression("#reverseString('hello')").getValue(context, String.class);
In this case, the boolean false results in returning the string value 'falseExp'. A more
realistic example is shown below.
parser.parseExpression("Name").setValue(societyContext, "IEEE");
societyContext.setVariable("queryName", "Nikola Tesla");
expression = "isMember(#queryName)? #queryName + ' is a member of the ' " +
"+ Name + ' Society' : #queryName + ' is not a member of the ' + Name + ' Society'";
String queryResultString =
parser.parseExpression(expression).getValue(societyContext, String.class);
// queryResultString = "Nikola Tesla is a member of the IEEE Society"
Also see the next section on the Elvis operator for an even shorter syntax for the ternary
operator.
Instead you can use the Elvis operator, named for the resemblance to Elvis' hair style.
ExpressionParser parser = new SpelExpressionParser();
String name = parser.parseExpression("null?:'Unknown'").getValue(String.class);
System.out.println(name);
// 'Unknown'
Note
The Elvis operator can be used to apply default values in expressions,
e.g. in an @Value expression:
@Value("#{systemProperties['pop3.port'] ?: 25}")
Selection is possible upon both lists and maps. In the former case the selection criteria is
evaluated against each individual list element whilst against a map the selection criteria is
evaluated against each map entry (objects of the Java type Map.Entry). Map entries
have their key and value accessible as properties for use in the selection.
This expression will return a new map consisting of those elements of the original map
where the entry value is less than 27.
Map newMap = parser.parseExpression("map.?[value<27]").getValue();
In addition to returning all the selected elements, it is possible to retrieve just the first or the
last value. To obtain the first entry matching the selection the syntax is ^[...] whilst to
obtain the last matching selection the syntax is $[...].
A map can also be used to drive projection and in this case the projection expression is
evaluated against each entry in the map (represented as a Java Map.Entry). The result
of a projection across a map is a list consisting of the evaluation of the projection
expression against each map entry.
The string is evaluated by concatenating the literal text 'random number is ' with the result
of evaluating the expression inside the #{ } delimiter, in this case the result of calling that
random() method. The second argument to the method parseExpression() is of the
type ParserContext. The ParserContext interface is used to influence how the
expression is parsed in order to support the expression templating functionality. The
definition of TemplateParserContext is shown below.
public class TemplateParserContext implements ParserContext {
public String getExpressionPrefix() {
return "#{";
}
public String getExpressionSuffix() {
return "}";
}
public boolean isTemplate() {
return true;
}
}
String name;
String nationality;
String[] inventions;
Date birthdate;
PlaceOfBirth placeOfBirth;
this.inventions = inventions;
}
public String[] getInventions() {
return inventions;
}
}
PlaceOfBirth.java
package org.spring.samples.spel.inventor;
public class PlaceOfBirth {
private String city;
private String country;
public PlaceOfBirth(String city) {
this.city=city;
}
public PlaceOfBirth(String city, String country)
{
this(city);
this.country = country;
}
public String getCity() {
return city;
}
public void setCity(String s) {
this.city = s;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
Society.java
package org.spring.samples.spel.inventor;
import java.util.*;
public class Society {
private String name;
public static String Advisors = "advisors";
public static String President = "president";
private List<Inventor> members = new ArrayList<Inventor>();
private Map officers = new HashMap();
public List getMembers() {
return members;
}
public Map getOfficers() {
return officers;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isMember(String name)
{
boolean found = false;
for (Inventor inventor : members) {
if (inventor.getName().equals(name))
{
found = true;
break;
}
}
return found;
}
an IsModified interface, to simplify caching. (An introduction is known as an intertype declaration in the AspectJ community.)
Target object: object being advised by one or more aspects. Also referred to as the
advised object. Since Spring AOP is implemented using runtime proxies, this object
will always be a proxied object.
AOP proxy: an object created by the AOP framework in order to implement the aspect
contracts (advise method executions and so on). In the Spring Framework, an AOP
proxy will be a JDK dynamic proxy or a CGLIB proxy.
Weaving: linking aspects with other application types or objects to create an advised
object. This can be done at compile time (using the AspectJ compiler, for example),
load time, or at runtime. Spring AOP, like other pure Java AOP frameworks, performs
weaving at runtime.
Types of advice:
Before advice: Advice that executes before a join point, but which does not have the
ability to prevent execution flow proceeding to the join point (unless it throws an
exception).
After returning advice: Advice to be executed after a join point completes normally: for
example, if a method returns without throwing an exception.
After throwing advice: Advice to be executed if a method exits by throwing an
exception.
After (finally) advice: Advice to be executed regardless of the means by which a join
point exits (normal or exceptional return).
Around advice: Advice that surrounds a join point such as a method invocation. This is
the most powerful kind of advice. Around advice can perform custom behavior before
and after the method invocation. It is also responsible for choosing whether to proceed
to the join point or to shortcut the advised method execution by returning its own return
value or throwing an exception.
Around advice is the most general kind of advice. Since Spring AOP, like AspectJ,
provides a full range of advice types, we recommend that you use the least powerful
advice type that can implement the required behavior. 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 do not need to invoke the proceed()
method on the JoinPoint used for around advice, and hence cannot fail to invoke it.
In Spring 2.0, all advice parameters are statically typed, so that you work with advice
parameters of the appropriate type (the type of the return value from a method execution for
example) rather than Object arrays.
The concept of join points, matched by pointcuts, is the key to AOP which distinguishes it
from older technologies offering only interception. Pointcuts enable advice to be targeted
independently of the Object-Oriented hierarchy. For example, an around advice providing
declarative transaction management can be applied to a set of methods spanning multiple
objects (such as all business operations in the service layer).
Spring AOP's approach to AOP differs from that of most other AOP frameworks. The aim is
not to provide the most complete AOP implementation (although Spring AOP is quite
capable); it is rather to provide a close integration between AOP implementation and
Spring IoC to help solve common problems in enterprise applications.
Thus, for example, the Spring Framework's AOP functionality is normally used in
conjunction with the Spring IoC container. Aspects are configured using normal bean
definition syntax (although this allows powerful "autoproxying" capabilities): this is a
crucial difference from other AOP implementations. There are some things you cannot do
easily or efficiently with Spring AOP, such as advise very fine-grained objects (such as
domain objects typically): AspectJ is the best choice in such cases. However, our
experience is that Spring AOP provides an excellent solution to most problems in
enterprise Java applications that are amenable to AOP.
Spring AOP will never strive to compete with AspectJ to provide a comprehensive AOP
solution. We believe that both proxy-based frameworks like Spring AOP and full-blown
frameworks such as AspectJ are valuable, and that they are complementary, rather than in
competition. Spring 2.0 seamlessly integrates Spring AOP and IoC with AspectJ, to enable
all uses of AOP to be catered for within a consistent Spring-based application architecture.
This integration does not affect the Spring AOP API or the AOP Alliance API: Spring AOP
remains backward-compatible. See the following chapter for a discussion of the Spring
AOP APIs.
Note
One of the central tenets of the Spring Framework is that of noninvasiveness; this is the idea that you should not be forced to introduce
framework-specific classes and interfaces into your business/domain
model. However, in some places the Spring Framework does give you
the option to introduce Spring Framework-specific dependencies into
your codebase: the rationale in giving you such options is because in
certain scenarios it might be just plain easier to read or code some
specific piece of functionality in such a way. The Spring Framework
(almost) always offers you the choice though: you have the freedom to
make an informed decision as to which option best suits your particular
use case or scenario.
One such choice that is relevant to this chapter is that of which AOP
framework (and which AOP style) to choose. You have the choice of
AspectJ and/or Spring AOP, and you also have the choice of either the
@AspectJ annotation-style approach or the Spring XML configurationstyle approach. The fact that this chapter chooses to introduce the
@AspectJ-style approach first should not be taken as an indication that
the Spring team favors the @AspectJ annotation-style approach over
the Spring XML configuration-style.
See Section 9.4, Choosing which AOP declaration style to use for a
more complete discussion of the whys and wherefores of each style.
This assumes that you are using schema support as described in Appendix E, XML
Schema-based configuration. See Section E.2.7, The aop schema for how to import the
tags in the aop namespace.
If you are using the DTD, it is still possible to enable @AspectJ support by adding the
following definition to your application context:
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" />
Aspects (classes annotated with @Aspect) may have methods and fields just like any
other class. They may also contain pointcut, advice, and introduction (inter-type)
declarations.
Autodetecting aspects through component scanning
You may register aspect classes as regular beans in your Spring XML
configuration, or autodetect them through classpath scanning - just like
any other Spring-managed bean. However, note that the @Aspect
annotation is not sufficient for autodetection in the classpath: For that
purpose, you need to add a separate @Component annotation (or
alternatively a custom stereotype annotation that qualifies, as per the
rules of Spring's component scanner).
Advising aspects with other aspects?
In Spring AOP, it is not possible to have aspects themselves be the
target of advice from other aspects. The @Aspect annotation on a class
marks it as an aspect, and hence excludes it from auto-proxying.
The pointcut expression that forms the value of the @Pointcut annotation is a regular
AspectJ 5 pointcut expression. For a full discussion of AspectJ's pointcut language, see
the AspectJ Programming Guide (and for Java 5 based extensions, the AspectJ 5
Developers Notebook) or one of the books on AspectJ such as Eclipse AspectJ by
Colyer et. al. or AspectJ in Action by Ramnivas Laddad.
IllegalArgumentException
being thrown.
The set of pointcut designators
supported by Spring AOP may
be extended in future releases to
support more of the AspectJ
pointcut designators.
The 'idOrNameOfBean' token can be the name of any Spring bean: limited wildcard
support using the '*' character is provided, so if you establish some naming conventions
for your Spring beans you can quite easily write a 'bean' PCD expression to pick them out.
As is the case with other pointcut designators, the 'bean' PCD can be &&'ed, ||'ed, and !
(negated) too.
Note
Please note that the 'bean' PCD is only supported in Spring AOP - and
not in native AspectJ weaving. It is a Spring-specific extension to the
standard PCDs that AspectJ defines.
The 'bean' PCD operates at the instance level (building on the Spring
bean name concept) rather than at the type level only (which is what
weaving-based AOP is limited to). Instance-based pointcut designators
are a special capability of Spring's proxy-based AOP framework and its
close integration with the Spring bean factory, where it is natural and
straightforward to identify specific beans by name.
It is a best practice to build more complex pointcut expressions out of smaller named
components as shown above. When referring to pointcuts by name, normal Java visibility
rules apply (you can see private pointcuts in the same type, protected pointcuts in the
hierarchy, public pointcuts anywhere and so on). Visibility does not affect pointcut
matching.
/**
* A join point is in the data access layer if the method is defined
* in a type in the com.xyz.someapp.dao package or any sub-package
* under that.
*/
@Pointcut("within(com.xyz.someapp.dao..*)")
public void inDataAccessLayer() {}
/**
* A business service is the execution of any method defined on a service
* interface. This definition assumes that interfaces are placed in the
* "service" package, and that implementation types are in sub-packages.
*
* If you group service interfaces by functional area (for example,
* in packages com.xyz.someapp.abc.service and com.xyz.def.service) then
* the pointcut expression "execution(* com.xyz.someapp..service.*.*(..))"
* could be used instead.
*
* Alternatively, you can write the expression using the 'bean'
* PCD, like so "bean(*Service)". (This assumes that you have
* named your Spring service beans in a consistent fashion.)
*/
@Pointcut("execution(* com.xyz.someapp.service.*.*(..))")
public void businessService() {}
/**
* A data access operation is the execution of any method defined on a
* dao interface. This definition assumes that interfaces are placed in the
* "dao" package, and that implementation types are in sub-packages.
*/
@Pointcut("execution(* com.xyz.someapp.dao.*.*(..))")
public void dataAccessOperation() {}
}
The pointcuts defined in such an aspect can be referred to anywhere that you need a
pointcut expression. For example, to make the service layer transactional, you could write:
<aop:config>
<aop:advisor
pointcut="com.xyz.someapp.SystemArchitecture.businessService()"
advice-ref="tx-advice"/>
</aop:config>
<tx:advice id="tx-advice">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
Examples
Spring AOP users are likely to use the execution pointcut designator the most often.
The format of an execution expression is:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)
throws-pattern?)
All parts except the returning type pattern (ret-type-pattern in the snippet above), name
pattern, and parameters pattern are optional. The returning type pattern determines what
the return type of the method must be in order for a join point to be matched. Most
frequently you will use * as the returning type pattern, which matches any return type. A
fully-qualified type name will match only when the method returns the given type. The
name pattern matches the method name. You can use the * wildcard as all or part of a
name pattern. The parameters pattern is slightly more complex: () matches a method that
takes no parameters, whereas (..) matches any number of parameters (zero or more).
The pattern (*) matches a method taking one parameter of any type, (*,String)
matches a method taking two parameters, the first can be of any type, the second must be
a String. Consult the Language Semantics section of the AspectJ Programming Guide for
more information.
Some examples of common pointcut expressions are given below.
any join point (method execution only in Spring AOP) within the service package:
within(com.xyz.service.*)
any join point (method execution only in Spring AOP) within the service package or a
sub-package:
within(com.xyz.service..*)
any join point (method execution only in Spring AOP) where the proxy implements the
AccountService interface:
this(com.xyz.service.AccountService)
'this' is more commonly used in a binding form :- see the following section on advice
for how to make the proxy object available in the advice body.
any join point (method execution only in Spring AOP) where the target object
implements the AccountService interface:
target(com.xyz.service.AccountService)
'target' is more commonly used in a binding form :- see the following section on advice
for how to make the target object available in the advice body.
any join point (method execution only in Spring AOP) which takes a single parameter,
and where the argument passed at runtime is Serializable:
args(java.io.Serializable)
'args' is more commonly used in a binding form :- see the following section on advice
for how to make the method arguments available in the advice body.
Note that the pointcut given in this example is different to execution(*
*(java.io.Serializable)): the args version matches if the argument passed at
runtime is Serializable, the execution version matches if the method signature
declares a single parameter of type Serializable.
any join point (method execution only in Spring AOP) where the target object has an
@Transactional annotation:
@target(org.springframework.transaction.annotation.Transactional)
'@target' can also be used in a binding form :- see the following section on advice for
how to make the annotation object available in the advice body.
any join point (method execution only in Spring AOP) where the declared type of the
target object has an @Transactional annotation:
@within(org.springframework.transaction.annotation.Transactional)
'@within' can also be used in a binding form :- see the following section on advice for
how to make the annotation object available in the advice body.
any join point (method execution only in Spring AOP) where the executing method has
an @Transactional annotation:
@annotation(org.springframework.transaction.annotation.Transactional)
'@annotation' can also be used in a binding form :- see the following section on advice
for how to make the annotation object available in the advice body.
any join point (method execution only in Spring AOP) which takes a single parameter,
and where the runtime type of the argument passed has the @Classified
annotation:
@args(com.xyz.security.Classified)
'@args' can also be used in a binding form :- see the following section on advice for
how to make the annotation object(s) available in the advice body.
any join point (method execution only in Spring AOP) on a Spring bean named
'tradeService':
bean(tradeService)
any join point (method execution only in Spring AOP) on Spring beans having names
that match the wildcard expression '*Service':
bean(*Service)
Before advice
Before advice is declared in an aspect using the @Before annotation:
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class BeforeExample {
@Before("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
public void doAccessCheck() {
// ...
}
}
If using an in-place pointcut expression we could rewrite the above example as:
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class BeforeExample {
@Before("execution(* com.xyz.myapp.dao.*.*(..))")
public void doAccessCheck() {
// ...
}
}
Note: it is of course possible to have multiple advice declarations, and other members as
well, all inside the same aspect. We're just showing a single advice declaration in these
examples to focus on the issue under discussion at the time.
Sometimes you need access in the advice body to the actual value that was returned. You
can use the form of @AfterReturning that binds the return value for this:
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;
@Aspect
public class AfterReturningExample {
@AfterReturning(
pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",
returning="retVal")
public void doAccessCheck(Object retVal) {
// ...
}
}
The name used in the returning attribute must correspond to the name of a parameter
in the advice method. When a method execution returns, the return value will be passed to
the advice method as the corresponding argument value. A returning clause also
restricts matching to only those method executions that return a value of the specified type
(Object in this case, which will match any return value).
Please note that it is not possible to return a totally different reference when using afterreturning advice.
Often you want the advice to run only when exceptions of a given type are thrown, and you
also often need access to the thrown exception in the advice body. Use the throwing
attribute to both restrict matching (if desired, use Throwable as the exception type
otherwise) and bind the thrown exception to an advice parameter.
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;
@Aspect
public class AfterThrowingExample {
@AfterThrowing(
pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",
throwing="ex")
public void doRecoveryActions(DataAccessException ex) {
// ...
}
}
The name used in the throwing attribute must correspond to the name of a parameter in
the advice method. When a method execution exits by throwing an exception, the
exception will be passed to the advice method as the corresponding argument value. A
throwing clause also restricts matching to only those method executions that throw an
exception of the specified type (DataAccessException in this case).
Around advice
The final kind of advice is around advice. Around advice runs "around" a matched method
execution. It has the opportunity to do work both before and after the method executes, and
to determine when, how, and even if, the method actually gets to execute at all. Around
advice is often used if you need to share state before and after a method execution in a
thread-safe manner (starting and stopping a timer for example). Always use the least
powerful form of advice that meets your requirements (i.e. don't use around advice if simple
before advice would do).
Around advice is declared using the @Around annotation. The first parameter of the
advice method must be of type ProceedingJoinPoint. Within the body of the advice,
calling proceed() on the ProceedingJoinPoint causes the underlying method to
execute. The proceed method may also be called passing in an Object[] - the values
in the array will be used as the arguments to the method execution when it proceeds.
The behavior of proceed when called with an Object[] is a little different than the behavior
of proceed for around advice compiled by the AspectJ compiler. For around advice written
using the traditional AspectJ language, the number of arguments passed to proceed must
match the number of arguments passed to the around advice (not the number of arguments
taken by the underlying join point), and the value passed to proceed in a given argument
position supplants the original value at the join point for the entity the value was bound to
(Don't worry if this doesn't make sense right now!). The approach taken by Spring is
simpler and a better match to its proxy-based, execution only semantics. You only need to
be aware of this difference if you are compiling @AspectJ aspects written for Spring and
using proceed with arguments with the AspectJ compiler and weaver. There is a way to
write such aspects that is 100% compatible across both Spring AOP and AspectJ, and this
is discussed in the following section on advice parameters.
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.ProceedingJoinPoint;
@Aspect
public class AroundExample {
@Around("com.xyz.myapp.SystemArchitecture.businessService()")
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
// start stopwatch
Object retVal = pjp.proceed();
// stop stopwatch
return retVal;
}
}
The value returned by the around advice will be the return value seen by the caller of the
method. A simple caching aspect for example could return a value from a cache if it has
one, and invoke proceed() if it does not. Note that proceed may be invoked once, many
times, or not at all within the body of the around advice, all of these are quite legal.
Advice parameters
Spring 2.0 offers fully typed advice - meaning that you declare the parameters you need in
the advice signature (as we saw for the returning and throwing examples above) rather
than work with Object[] arrays all the time. We'll see how to make argument and other
contextual values available to the advice body in a moment. First let's take a look at how to
write generic advice that can find out about the method the advice is currently advising.
The args(account,..) part of the pointcut expression serves two purposes: firstly, it
restricts matching to only those method executions where the method takes at least one
parameter, and the argument passed to that parameter is an instance of Account;
secondly, it makes the actual Account object available to the advice via the account
parameter.
Another way of writing this is to declare a pointcut that "provides" the Account object
value when it matches a join point, and then just refer to the named pointcut from the
advice. This would look as follows:
@Pointcut("com.xyz.myapp.SystemArchitecture.dataAccessOperation() &&" +
"args(account,..)")
private void accountDataAccessOperation(Account account) {}
@Before("accountDataAccessOperation(account)")
public void validateAccount(Account account) {
// ...
}
The interested reader is once more referred to the AspectJ programming guide for more
details.
The proxy object (this), target object (target), and annotations (@within,
@target, @annotation, @args) can all be bound in a similar fashion. The following
example shows how you could match the execution of methods annotated with an
@Auditable annotation, and extract the audit code.
First the definition of the @Auditable annotation:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Auditable {
AuditCode value();
}
And then the advice that matches the execution of @Auditable methods:
@Before("com.xyz.lib.Pointcuts.anyPublicMethod() && " +
"@annotation(auditable)")
public void audit(Auditable auditable) {
AuditCode code = auditable.value();
// ...
}
You can restrict interception of method types to certain parameter types by simply typing
the advice parameter to the parameter type you want to intercept the method for:
@Before("execution(* ..Sample+.sampleGenericMethod(*)) && args(param)")
public void beforeSampleMethod(MyType param) {
// Advice implementation
}
That this works is pretty obvious as we already discussed above. However, it's worth
pointing out that this won't work for generic collections. So you cannot define a pointcut like
this:
@Before("execution(* ..Sample+.sampleGenericCollectionMethod(*)) && args(param)")
public void beforeSampleMethod(Collection<MyType> param) {
// Advice implementation
}
To make this work we would have to inspect every element of the collection, which is not
reasonable as we also cannot decide how to treat null values in general. To achieve
something similar to this you have to type the parameter to Collection<?> and
manually check the type of the elements.
2. Using the 'argNames' attribute is a little clumsy, so if the 'argNames' attribute has
not been specified, then Spring AOP will look at the debug information for the class
and try to determine the parameter names from the local variable table. This
information will be present as long as the classes have been compiled with debug
information ('-g:vars' at a minimum). The consequences of compiling with this flag
on are: (1) your code will be slightly easier to understand (reverse engineer), (2) the
class file sizes will be very slightly bigger (typically inconsequential), (3) the
optimization to remove unused local variables will not be applied by your compiler. In
other words, you should encounter no difficulties building with this flag on.
If an @AspectJ aspect has been compiled by the AspectJ compiler (ajc) even without
the debug information then there is no need to add the argNames attribute as the
compiler will retain the needed information.
3. If the code has been compiled without the necessary debug information, then Spring
AOP will attempt to deduce the pairing of binding variables to parameters (for
example, if only one variable is bound in the pointcut expression, and the advice
method only takes one parameter, the pairing is obvious!). If the binding of variables is
ambiguous given the available information, then an
AmbiguousBindingException will be thrown.
4. If all of the above strategies fail then an IllegalArgumentException will be
thrown.
In many cases you will be doing this binding anyway (as in the example above).
Advice ordering
What happens when multiple pieces of advice all want to run at the same join point?
Spring AOP follows the same precedence rules as AspectJ to determine the order of
advice execution. The highest precedence advice runs first "on the way in" (so given two
pieces of before advice, the one with highest precedence runs first). "On the way out" from
a join point, the highest precedence advice runs last (so given two pieces of after advice,
the one with the highest precedence will run second).
When two pieces of advice defined in different aspects both need to run at the same join
point, unless you specify otherwise the order of execution is undefined. You can control the
order of execution by specifying precedence. This is done in the normal Spring way by
either implementing the org.springframework.core.Ordered interface in the
aspect class or annotating it with the Order annotation. Given two aspects, the aspect
returning the lower value from Ordered.getValue() (or the annotation value) has the
higher precedence.
When two pieces of advice defined in the same aspect both need to run at the same join
point, the ordering is undefined (since there is no way to retrieve the declaration order via
reflection for javac-compiled classes). Consider collapsing such advice methods into one
advice method per join point in each aspect class, or refactor the pieces of advice into
separate aspect classes - which can be ordered at the aspect level.
9.2.5 Introductions
Introductions (known as inter-type declarations in AspectJ) enable an aspect to declare
that advised objects implement a given interface, and to provide an implementation of that
interface on behalf of those objects.
An introduction is made using the @DeclareParents annotation. This annotation is
used to declare that matching types have a new parent (hence the name). For example,
given an interface UsageTracked, and an implementation of that interface
DefaultUsageTracked, the following aspect declares that all implementors of service
interfaces also implement the UsageTracked interface. (In order to expose statistics via
JMX for example.)
@Aspect
public class UsageTracking {
@DeclareParents(value="com.xzy.myapp.service.*+",
defaultImpl=DefaultUsageTracked.class)
public static UsageTracked mixin;
@Before("com.xyz.myapp.SystemArchitecture.businessService() &&" +
"this(usageTracked)")
public void recordUsage(UsageTracked usageTracked) {
usageTracked.incrementUseCount();
}
}
The interface to be implemented is determined by the type of the annotated field. The
value attribute of the @DeclareParents annotation is an AspectJ type pattern :- any
bean of a matching type will implement the UsageTracked interface. Note that in the before
advice of the above example, service beans can be directly used as implementations of
the UsageTracked interface. If accessing a bean programmatically you would write the
following:
UsageTracked usageTracked = (UsageTracked) context.getBean("myService");
The effect of the 'perthis' clause is that one aspect instance will be created for each
unique service object executing a business service (each unique object bound to 'this' at
join points matched by the pointcut expression). The aspect instance is created the first
time that a method is invoked on the service object. The aspect goes out of scope when
the service object goes out of scope. Before the aspect instance is created, none of the
advice within it executes. As soon as the aspect instance has been created, the advice
declared within it will execute at matched join points, but only when the service object is
the one this aspect is associated with. See the AspectJ programming guide for more
information on per-clauses.
The 'pertarget' instantiation model works in exactly the same way as perthis, but
creates one aspect instance for each unique target object at matched join points.
9.2.7 Example
Now that you have seen how all the constituent parts work, let's put them together to do
something useful!
The execution of business services can sometimes fail due to concurrency issues (for
example, deadlock loser). If the operation is retried, it is quite likely to succeed next time
round. For business services where it is appropriate to retry in such conditions (idempotent
operations that don't need to go back to the user for conflict resolution), we'd like to
transparently retry the operation to avoid the client seeing a
PessimisticLockingFailureException. This is a requirement that clearly cuts
across multiple services in the service layer, and hence is ideal for implementing via an
aspect.
Because we want to retry the operation, we will need to use around advice so that we can
call proceed multiple times. Here's how the basic aspect implementation looks:
@Aspect
public class ConcurrentOperationExecutor implements Ordered {
private static final int DEFAULT_MAX_RETRIES = 2;
private int maxRetries = DEFAULT_MAX_RETRIES;
private int order = 1;
public void setMaxRetries(int maxRetries) {
this.maxRetries = maxRetries;
}
public int getOrder() {
return this.order;
}
public void setOrder(int order) {
this.order = order;
}
@Around("com.xyz.myapp.SystemArchitecture.businessService()")
public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
int numAttempts = 0;
PessimisticLockingFailureException lockFailureException;
do {
numAttempts++;
try {
return pjp.proceed();
}
catch(PessimisticLockingFailureException ex) {
lockFailureException = ex;
}
}
while(numAttempts <= this.maxRetries);
throw lockFailureException;
}
}
Note that the aspect implements the Ordered interface so we can set the precedence of
the aspect higher than the transaction advice (we want a fresh transaction each time we
retry). The maxRetries and order properties will both be configured by Spring. The
main action happens in the doConcurrentOperation around advice. Notice that for
the moment we're applying the retry logic to all businessService()s. We try to
proceed, and if we fail with an PessimisticLockingFailureException we simply
try again unless we have exhausted all of our retry attempts.
The corresponding Spring configuration is:
<aop:aspectj-autoproxy/>
<bean id="concurrentOperationExecutor"
class="com.xyz.myapp.service.impl.ConcurrentOperationExecutor">
<property name="maxRetries" value="3"/>
<property name="order" value="100"/>
</bean>
To refine the aspect so that it only retries idempotent operations, we might define an
Idempotent annotation:
@Retention(RetentionPolicy.RUNTIME)
public @interface Idempotent {
// marker annotation
}
and use the annotation to annotate the implementation of service operations. The change
to the aspect to only retry idempotent operations simply involves refining the pointcut
expression so that only @Idempotent operations match:
@Around("com.xyz.myapp.SystemArchitecture.businessService() && " +
"@annotation(com.xyz.myapp.service.Idempotent)")
public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
...
}
</bean>
The bean backing the aspect ("aBean" in this case) can of course be configured and
dependency injected just like any other Spring bean.
Note that the pointcut expression itself is using the same AspectJ pointcut expression
language as described in Section 9.2, @AspectJ support. If you are using the schema
based declaration style with Java 5, you can refer to named pointcuts defined in types
(@Aspects) within the pointcut expression, but this feature is not available on JDK 1.4 and
below (it relies on the Java 5 specific AspectJ reflection APIs). On JDK 1.5 therefore,
another way of defining the above pointcut would be:
<aop:config>
<aop:pointcut id="businessService"
expression="com.xyz.myapp.SystemArchitecture.businessService()"/>
</aop:config>
Much the same way in an @AspectJ aspect, pointcuts declared using the schema based
definition style may collect join point context. For example, the following pointcut collects
the 'this' object as the join point context and passes it to advice:
<aop:config>
<aop:aspect id="myAspect" ref="aBean">
<aop:pointcut id="businessService"
expression="execution(* com.xyz.myapp.service.*.*(..)) && this(service)"/>
<aop:before pointcut-ref="businessService" method="monitor"/>
...
</aop:aspect>
</aop:config>
The advice must be declared to receive the collected join point context by including
parameters of the matching names:
public void monitor(Object service) {
...
}
When combining pointcut sub-expressions, '&&' is awkward within an XML document, and
so the keywords 'and', 'or' and 'not' can be used in place of '&&', '||' and '!' respectively. For
example, the previous pointcut may be better written as:
<aop:config>
<aop:aspect id="myAspect" ref="aBean">
<aop:pointcut id="businessService"
expression="execution(* com.xyz.myapp.service.*.*(..)) and this(service)"/>
<aop:before pointcut-ref="businessService" method="monitor"/>
...
</aop:aspect>
</aop:config>
Note that pointcuts defined in this way are referred to by their XML id and cannot be used
as named pointcuts to form composite pointcuts. The named pointcut support in the
schema based definition style is thus more limited than that offered by the @AspectJ style.
Before advice
Before advice runs before a matched method execution. It is declared inside an
<aop:aspect> using the <aop:before> element.
<aop:aspect id="beforeExample" ref="aBean">
<aop:before
pointcut-ref="dataAccessOperation"
method="doAccessCheck"/>
...
</aop:aspect>
As we noted in the discussion of the @AspectJ style, using named pointcuts can
significantly improve the readability of your code.
The method attribute identifies a method (doAccessCheck) that provides the body of the
advice. This method must be defined for the bean referenced by the aspect element
containing the advice. Before a data access operation is executed (a method execution
join point matched by the pointcut expression), the "doAccessCheck" method on the
aspect bean will be invoked.
pointcut-ref="dataAccessOperation"
method="doAccessCheck"/>
...
</aop:aspect>
Just as in the @AspectJ style, it is possible to get hold of the return value within the advice
body. Use the returning attribute to specify the name of the parameter to which the return
value should be passed:
<aop:aspect id="afterReturningExample" ref="aBean">
<aop:after-returning
pointcut-ref="dataAccessOperation"
returning="retVal"
method="doAccessCheck"/>
...
</aop:aspect>
The doAccessCheck method must declare a parameter named retVal. The type of this
parameter constrains matching in the same way as described for @AfterReturning. For
example, the method signature may be declared as:
public void doAccessCheck(Object retVal) {...
Just as in the @AspectJ style, it is possible to get hold of the thrown exception within the
advice body. Use the throwing attribute to specify the name of the parameter to which the
exception should be passed:
<aop:aspect id="afterThrowingExample" ref="aBean">
<aop:after-throwing
pointcut-ref="dataAccessOperation"
throwing="dataAccessEx"
method="doRecoveryActions"/>
...
</aop:aspect>
</aop:aspect>
Around advice
The final kind of advice is around advice. Around advice runs "around" a matched method
execution. It has the opportunity to do work both before and after the method executes, and
to determine when, how, and even if, the method actually gets to execute at all. Around
advice is often used if you need to share state before and after a method execution in a
thread-safe manner (starting and stopping a timer for example). Always use the least
powerful form of advice that meets your requirements; don't use around advice if simple
before advice would do.
Around advice is declared using the aop:around element. The first parameter of the
advice method must be of type ProceedingJoinPoint. Within the body of the advice,
calling proceed() on the ProceedingJoinPoint causes the underlying method to
execute. The proceed method may also be calling passing in an Object[] - the values
in the array will be used as the arguments to the method execution when it proceeds. See
the section called Around advice for notes on calling proceed with an Object[].
<aop:aspect id="aroundExample" ref="aBean">
<aop:around
pointcut-ref="businessService"
method="doBasicProfiling"/>
...
</aop:aspect>
Advice parameters
The schema based declaration style supports fully typed advice in the same way as
described for the @AspectJ support - by matching pointcut parameters by name against
advice method parameters. See the section called Advice parameters for details. If you
wish to explicitly specify argument names for the advice methods (not relying on the
detection strategies previously described) then this is done using the arg-names attribute
of the advice element, which is treated in the same manner to the "argNames" attribute in
an advice annotation as described in the section called Determining argument names.
For example:
<aop:before
pointcut="com.xyz.lib.Pointcuts.anyPublicMethod() and @annotation(auditable)"
method="audit"
arg-names="auditable"/>
Next up is the aspect. Notice the fact that the profile(..) method accepts a number of
strongly-typed parameters, the first of which happens to be the join point used to proceed
with the method call: the presence of this parameter is an indication that the
profile(..) is to be used as around advice:
package x.y;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.util.StopWatch;
public class SimpleProfiler {
public Object profile(ProceedingJoinPoint call, String name, int age) throws Throwable {
StopWatch clock = new StopWatch(
"Profiling for '" + name + "' and '" + age + "'");
try {
clock.start(call.toShortString());
return call.proceed();
} finally {
clock.stop();
System.out.println(clock.prettyPrint());
}
}
}
Finally, here is the XML configuration that is required to effect the execution of the above
advice for a particular join point:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- this is the object that will be proxied by Spring's AOP infrastructure -->
<bean id="fooService" class="x.y.service.DefaultFooService"/>
<!-- this is the actual advice itself -->
<bean id="profiler" class="x.y.SimpleProfiler"/>
<aop:config>
<aop:aspect ref="profiler">
<aop:pointcut id="theExecutionOfSomeFooServiceMethod"
expression="execution(* x.y.service.FooService.getFoo(String,int))
and args(name, age)"/>
<aop:around pointcut-ref="theExecutionOfSomeFooServiceMethod"
method="profile"/>
</aop:aspect>
</aop:config>
</beans>
If we had the following driver script, we would get output something like this on standard
output:
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import x.y.service.FooService;
public final class Boot {
public static void main(final String[] args) throws Exception {
BeanFactory ctx = new ClassPathXmlApplicationContext("x/y/plain.xml");
FooService foo = (FooService) ctx.getBean("fooService");
foo.getFoo("Pengo", 12);
}
}
StopWatch 'Profiling for 'Pengo' and '12'': running time (millis) = 0
----------------------------------------ms
%
Task name
----------------------------------------00000 ? execution(getFoo)
Advice ordering
When multiple advice needs to execute at the same join point (executing method) the
ordering rules are as described in the section called Advice ordering. The precedence
between aspects is determined by either adding the Order annotation to the bean backing
the aspect or by having the bean implement the Ordered interface.
9.3.4 Introductions
Introductions (known as inter-type declarations in AspectJ) enable an aspect to declare
that advised objects implement a given interface, and to provide an implementation of that
interface on behalf of those objects.
An introduction is made using the aop:declare-parents element inside an
aop:aspect This element is used to declare that matching types have a new parent
(hence the name). For example, given an interface UsageTracked, and an
implementation of that interface DefaultUsageTracked, the following aspect declares
that all implementors of service interfaces also implement the UsageTracked interface.
(In order to expose statistics via JMX for example.)
<aop:aspect id="usageTrackerAspect" ref="usageTracking">
<aop:declare-parents
types-matching="com.xzy.myapp.service.*+"
implement-interface="com.xyz.myapp.service.tracking.UsageTracked"
default-impl="com.xyz.myapp.service.tracking.DefaultUsageTracked"/>
<aop:before
pointcut="com.xyz.myapp.SystemArchitecture.businessService()
and this(usageTracked)"
method="recordUsage"/>
</aop:aspect>
The class backing the usageTracking bean would contain the method:
public void recordUsage(UsageTracked usageTracked) {
usageTracked.incrementUseCount();
}
9.3.6 Advisors
The concept of "advisors" is brought forward from the AOP support defined in Spring 1.2
and does not have a direct equivalent in AspectJ. An advisor is like a small self-contained
aspect that has a single piece of advice. The advice itself is represented by a bean, and
must implement one of the advice interfaces described in Section 10.3.2, Advice types in
Spring. Advisors can take advantage of AspectJ pointcut expressions though.
Spring 2.0 supports the advisor concept with the <aop:advisor> element. You will most
commonly see it used in conjunction with transactional advice, which also has its own
namespace support in Spring 2.0. Here's how it looks:
<aop:config>
<aop:pointcut id="businessService"
expression="execution(* com.xyz.myapp.service.*.*(..))"/>
<aop:advisor
pointcut-ref="businessService"
advice-ref="tx-advice"/>
</aop:config>
<tx:advice id="tx-advice">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
As well as the pointcut-ref attribute used in the above example, you can also use the
pointcut attribute to define a pointcut expression inline.
To define the precedence of an advisor so that the advice can participate in ordering, use
the order attribute to define the Ordered value of the advisor.
9.3.7 Example
Let's see how the concurrent locking failure retry example from Section 9.2.7, Example
looks when rewritten using the schema support.
The execution of business services can sometimes fail due to concurrency issues (for
example, deadlock loser). If the operation is retried, it is quite likely it will succeed next time
round. For business services where it is appropriate to retry in such conditions (idempotent
operations that don't need to go back to the user for conflict resolution), we'd like to
transparently retry the operation to avoid the client seeing a
PessimisticLockingFailureException. This is a requirement that clearly cuts
across multiple services in the service layer, and hence is ideal for implementing via an
aspect.
Because we want to retry the operation, we'll need to use around advice so that we can
call proceed multiple times. Here's how the basic aspect implementation looks (it's just a
regular Java class using the schema support):
public class ConcurrentOperationExecutor implements Ordered {
private static final int DEFAULT_MAX_RETRIES = 2;
private int maxRetries = DEFAULT_MAX_RETRIES;
private int order = 1;
public void setMaxRetries(int maxRetries) {
this.maxRetries = maxRetries;
}
public int getOrder() {
return this.order;
}
public void setOrder(int order) {
this.order = order;
}
public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
int numAttempts = 0;
PessimisticLockingFailureException lockFailureException;
do {
numAttempts++;
try {
return pjp.proceed();
}
catch(PessimisticLockingFailureException ex) {
lockFailureException = ex;
}
}
while(numAttempts <= this.maxRetries);
throw lockFailureException;
}
}
Note that the aspect implements the Ordered interface so we can set the precedence of
the aspect higher than the transaction advice (we want a fresh transaction each time we
retry). The maxRetries and order properties will both be configured by Spring. The
main action happens in the doConcurrentOperation around advice method. We try to
proceed, and if we fail with a PessimisticLockingFailureException we simply
try again unless we have exhausted all of our retry attempts.
This class is identical to the one used in the @AspectJ example, but with the annotations
removed.
The corresponding Spring configuration is:
<aop:config>
<aop:aspect id="concurrentOperationRetry" ref="concurrentOperationExecutor">
<aop:pointcut id="idempotentOperation"
expression="execution(* com.xyz.myapp.service.*.*(..))"/>
<aop:around
pointcut-ref="idempotentOperation"
method="doConcurrentOperation"/>
</aop:aspect>
</aop:config>
<bean id="concurrentOperationExecutor"
class="com.xyz.myapp.service.impl.ConcurrentOperationExecutor">
<property name="maxRetries" value="3"/>
<property name="order" value="100"/>
</bean>
Notice that for the time being we assume that all business services are idempotent. If this is
not the case we can refine the aspect so that it only retries genuinely idempotent
operations, by introducing an Idempotent annotation:
@Retention(RetentionPolicy.RUNTIME)
public @interface Idempotent {
// marker annotation
}
and using the annotation to annotate the implementation of service operations. The
change to the aspect to retry only idempotent operations simply involves refining the
pointcut expression so that only @Idempotent operations match:
<aop:pointcut id="idempotentOperation"
expression="execution(* com.xyz.myapp.service.*.*(..)) and
@annotation(com.xyz.myapp.service.Idempotent)"/>
then the choice has been made for you... use the code style. If aspects play a large role in
your design, and you are able to use the AspectJ Development Tools (AJDT) plugin for
Eclipse, then the AspectJ language syntax is the preferred option: it is cleaner and simpler
because the language was purposefully designed for writing aspects. If you are not using
Eclipse, or have only a few aspects that do not play a major role in your application, then
you may want to consider using the @AspectJ style and sticking with a regular Java
compilation in your IDE, and adding an aspect weaving phase to your build script.
The downside of the XML approach is that you cannot define the
'accountPropertyAccess' pointcut by combining these definitions.
The @AspectJ style supports additional instantiation models, and richer pointcut
composition. It has the advantage of keeping the aspect as a modular unit. It also has the
advantage the @AspectJ aspects can be understood (and thus consumed) both by Spring
AOP and by AspectJ - so if you later decide you need the capabilities of AspectJ to
implement additional requirements then it is very easy to migrate to an AspectJ-based
approach. On balance the Spring team prefer the @AspectJ style whenever you have
aspects that do more than simple "configuration" of enterprise services.
proxies and interceptors defined using the Spring 1.2 style in the same configuration. All of
these are implemented using the same underlying support mechanism and will co-exist
without any difficulty.
To force CGLIB proxying when using the @AspectJ autoproxy support, set the 'proxytarget-class' attribute of the <aop:aspectj-autoproxy> element to true:
<aop:aspectj-autoproxy proxy-target-class="true"/>
Note
Multiple <aop:config/> sections are collapsed into a single unified
auto-proxy creator at runtime, which applies the strongest proxy
settings that any of the <aop:config/> sections (typically from
different XML bean definition files) specified. This also applies to the
<tx:annotation-driven/> and <aop:aspectjautoproxy/> elements.
To be clear: using 'proxy-target-class="true"' on
<tx:annotation-driven/>, <aop:aspectj-autoproxy/> or
<aop:config/> elements will force the use of CGLIB proxies for all
three of them.
If you invoke a method on an object reference, the method is invoked directly on that object
reference, as can be seen below.
Things change slightly when the reference that client code has is a proxy. Consider the
following diagram and code snippet.
The key thing to understand here is that the client code inside the main(..) of the Main
class has a reference to the proxy. This means that method calls on that object reference
will be calls on the proxy, and as such the proxy will be able to delegate to all of the
interceptors (advice) that are relevant to that particular method call. However, once the call
has finally reached the target object, the SimplePojo reference in this case, any method
calls that it may make on itself, such as this.bar() or this.foo(), are going to be
invoked against the this reference, and not the proxy. This has important implications. It
means that self-invocation is not going to result in the advice associated with a method
This totally couples your code to Spring AOP, and it makes the class itself aware of the fact
that it is being used in an AOP context, which flies in the face of AOP. It also requires some
additional configuration when the proxy is being created:
public class Main {
public static void main(String[] args) {
ProxyFactory factory = new ProxyFactory(new SimplePojo());
factory.adddInterface(Pojo.class);
factory.addAdvice(new RetryAdvice());
factory.setExposeProxy(true);
Pojo pojo = (Pojo) factory.getProxy();
// this is a method call on the proxy!
pojo.foo();
}
}
Finally, it must be noted that AspectJ does not have this self-invocation issue because it is
not a proxy-based AOP framework.
going to look at how you can use the AspectJ compiler/weaver instead of, or in addition to,
Spring AOP if your needs go beyond the facilities offered by Spring AOP alone.
Spring ships with a small AspectJ aspect library, which is available standalone in your
distribution as spring-aspects.jar; you'll need to add this to your classpath in order
to use the aspects in it. Section 9.8.1, Using AspectJ to dependency inject domain objects
with Spring and Section 9.8.2, Other Spring aspects for AspectJ discuss the content of
this library and how you can use it. Section 9.8.3, Configuring AspectJ aspects using
Spring IoC discusses how to dependency inject AspectJ aspects that are woven using the
AspectJ compiler. Finally, Section 9.8.4, Load-time weaving with AspectJ in the Spring
Framework provides an introduction to load-time weaving for Spring applications using
AspectJ.
When used as a marker interface in this way, Spring will configure new instances of the
annotated type (Account in this case) using a bean definition (typically prototype-scoped)
with the same name as the fully-qualified type name
(com.xyz.myapp.domain.Account). Since the default name for a bean is the fullyqualified name of its type, a convenient way to declare the prototype definition is simply to
omit the id attribute:
<bean class="com.xyz.myapp.domain.Account" scope="prototype">
<property name="fundsTransferService" ref="fundsTransferService"/>
</bean>
If you want to explicitly specify the name of the prototype bean definition to use, you can do
so directly in the annotation:
package com.xyz.myapp.domain;
import org.springframework.beans.factory.annotation.Configurable;
@Configurable("account")
public class Account {
// ...
}
Spring will now look for a bean definition named "account" and use that as the definition
to configure new Account instances.
You can also use autowiring to avoid having to specify a dedicated bean definition at all.
To have Spring apply autowiring use the 'autowire' property of the @Configurable
annotation: specify either @Configurable(autowire=Autowire.BY_TYPE) or
You can find out more information about the language semantics of the
various pointcut types in AspectJ in this appendix of the AspectJ
Programming Guide.
For this to work the annotated types must be woven with the AspectJ weaver - you can
either use a build-time Ant or Maven task to do this (see for example the AspectJ
Development Environment Guide) or load-time weaving (see Section 9.8.4, Load-time
weaving with AspectJ in the Spring Framework). The
AnnotationBeanConfigurerAspect itself needs configuring by Spring (in order to
obtain a reference to the bean factory that is to be used to configure new objects). If you are
using Java based configuration simply add @EnableSpringConfigured to any
@Configuration class.
@Configuration
@EnableSpringConfigured
public class AppConfig {
}
If you prefer XML based configuration, the Spring context namespace defines a
convenient context:spring-configured element:
<context:spring-configured/>
If you are using the DTD instead of schema, the equivalent definition is:
<bean
class="org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect"
factory-method="aspectOf"/>
Instances of @Configurable objects created before the aspect has been configured will
result in a message being issued to the debug log and no configuration of the object taking
place. An example might be a bean in the Spring configuration that creates domain objects
when it is initialized by Spring. In this case you can use the "depends-on" bean attribute to
manually specify that the bean depends on the configuration aspect.
<bean id="myService"
class="com.xzy.myapp.service.MyService"
depends-on="org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect">
<!-- ... -->
</bean>
Note
Do not activate @Configurable processing through the bean
configurer aspect unless you really mean to rely on its semantics at
runtime. In particular, make sure that you do not use @Configurable
on bean classes which are registered as regular Spring beans with the
container: You would get double initialization otherwise, once through
the container and once through the aspect.
prototype bean definitions and using the @Configurable support from springaspects.jar to configure the aspect instances once they have bean created by the
AspectJ runtime.
If you have some @AspectJ aspects that you want to weave with AspectJ (for example,
using load-time weaving for domain model types) and other @AspectJ aspects that you
want to use with Spring AOP, and these aspects are all configured using Spring, then you
will need to tell the Spring AOP @AspectJ autoproxying support which exact subset of the
@AspectJ aspects defined in the configuration should be used for autoproxying. You can
do this by using one or more <include/> elements inside the <aop:aspectjautoproxy/> declaration. Each <include/> element specifies a name pattern, and
only beans with names matched by at least one of the patterns will be used for Spring AOP
autoproxy configuration:
<aop:aspectj-autoproxy>
<aop:include name="thisBean"/>
<aop:include name="thatBean"/>
</aop:aspectj-autoproxy>
Note
Do not be misled by the name of the <aop:aspectj-autoproxy/>
element: using it will result in the creation of Spring AOP proxies. The
@AspectJ style of aspect declaration is just being used here, but the
AspectJ runtime is not involved.
A first example
Let us assume that you are an application developer who has been tasked with diagnosing
the cause of some performance problems in a system. Rather than break out a profiling
tool, what we are going to do is switch on a simple profiling aspect that will enable us to
very quickly get some performance metrics, so that we can then apply a finer-grained
profiling tool to that specific area immediately afterwards.
Note
The example presented here uses XML style configuration, it is also
possible to configure and use @AspectJ with Java Configuration.
Specifically the @EnableLoadTimeWeaving annotation can be used
as an alternative to <context:load-time-weaver/> (see below
for details).
Here is the profiling aspect. Nothing too fancy, just a quick-and-dirty time-based profiler,
using the @AspectJ-style of aspect declaration.
package foo;
import
import
import
import
import
import
org.aspectj.lang.ProceedingJoinPoint;
org.aspectj.lang.annotation.Aspect;
org.aspectj.lang.annotation.Around;
org.aspectj.lang.annotation.Pointcut;
org.springframework.util.StopWatch;
org.springframework.core.annotation.Order;
@Aspect
public class ProfilingAspect {
@Around("methodsToBeProfiled()")
public Object profile(ProceedingJoinPoint pjp) throws Throwable {
StopWatch sw = new StopWatch(getClass().getSimpleName());
try {
sw.start(pjp.getSignature().getName());
return pjp.proceed();
} finally {
sw.stop();
System.out.println(sw.prettyPrint());
}
}
@Pointcut("execution(public * foo..*.*(..))")
public void methodsToBeProfiled(){}
}
We will also need to create an 'META-INF/aop.xml' file, to inform the AspectJ weaver
that we want to weave our ProfilingAspect into our classes. This file convention,
namely the presence of a file (or files) on the Java classpath called ' METAINF/aop.xml' is standard AspectJ.
<!DOCTYPE aspectj PUBLIC
"-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<weaver>
<!-- only weave classes in our application-specific packages -->
<include within="foo.*"/>
</weaver>
<aspects>
<!-- weave in just this aspect -->
<aspect name="foo.ProfilingAspect"/>
</aspects>
</aspectj>
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- a service object; we will be profiling its methods -->
<bean id="entitlementCalculationService"
class="foo.StubEntitlementCalculationService"/>
<!-- this switches on the load-time weaving -->
<context:load-time-weaver/>
</beans>
Now that all the required artifacts are in place - the aspect, the 'META-INF/aop.xml' file,
and the Spring configuration -, let us create a simple driver class with a main(..) method
to demonstrate the LTW in action.
package foo;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public final class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml", Main.class);
EntitlementCalculationService entitlementCalculationService
= (EntitlementCalculationService) ctx.getBean("entitlementCalculationService");
// the profiling aspect is 'woven' around this method execution
entitlementCalculationService.calculateEntitlement();
}
}
There is one last thing to do. The introduction to this section did say that one could switch
on LTW selectively on a per-ClassLoader basis with Spring, and this is true. However,
just for this example, we are going to use a Java agent (supplied with Spring) to switch on
the LTW. This is the command line we will use to run the above Main class:
java -javaagent:C:/projects/foo/lib/global/spring-instrument.jar foo.Main
The '-javaagent' is a Java 5+ flag for specifying and enabling agents to instrument
programs running on the JVM. The Spring Framework ships with such an agent, the
InstrumentationSavingAgent, which is packaged in the springinstrument.jar that was supplied as the value of the -javaagent argument in the
above example.
The output from the execution of the Main program will look something like that below. (I
have introduced a Thread.sleep(..) statement into the
calculateEntitlement() implementation so that the profiler actually captures
something other than 0 milliseconds - the 01234 milliseconds is not an overhead
introduced by the AOP :) )
Calculating entitlement
StopWatch 'ProfilingAspect': running time (millis) = 1234
------ ----- ---------------------------ms
%
Task name
------ ----- ---------------------------01234 100% calculateEntitlement
Since this LTW is effected using full-blown AspectJ, we are not just limited to advising
Spring beans; the following slight variation on the Main program will yield the same result.
package foo;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public final class Main {
public static void main(String[] args) {
new ClassPathXmlApplicationContext("beans.xml", Main.class);
EntitlementCalculationService entitlementCalculationService =
new StubEntitlementCalculationService();
// the profiling aspect will be 'woven' around this method execution
entitlementCalculationService.calculateEntitlement();
}
}
Notice how in the above program we are simply bootstrapping the Spring container, and
then creating a new instance of the StubEntitlementCalculationService totally
outside the context of Spring... the profiling advice still gets woven in.
The example admittedly is simplistic... however the basics of the LTW support in Spring
have all been introduced in the above example, and the rest of this section will explain the
'why' behind each bit of configuration and usage in detail.
Note
The ProfilingAspect used in this example may be basic, but it is
quite useful. It is a nice example of a development-time aspect that
developers can use during development (of course), and then quite
easily exclude from builds of the application being deployed into UAT
or production.
Aspects
The aspects that you use in LTW have to be AspectJ aspects. They can be written in either
the AspectJ language itself or you can write your aspects in the @AspectJ-style. The latter
option is of course only an option if you are using Java 5+, but it does mean that your
aspects are then both valid AspectJ and Spring AOP aspects. Furthermore, the compiled
aspect classes need to be available on the classpath.
'META-INF/aop.xml'
The AspectJ LTW infrastructure is configured using one or more 'META-INF/aop.xml'
files, that are on the Java classpath (either directly, or more typically in jar files).
The structure and contents of this file is detailed in the main AspectJ reference
documentation, and the interested reader is referred to that resource. (I appreciate that this
section is brief, but the 'aop.xml' file is 100% AspectJ - there is no Spring-specific
information or semantics that apply to it, and so there is no extra value that I can contribute
either as a result), so rather than rehash the quite satisfactory section that the AspectJ
developers wrote, I am just directing you there.)
Spring configuration
The key component in Spring's LTW support is the LoadTimeWeaver interface (in the
org.springframework.instrument.classloading package), and the numerous
implementations of it that ship with the Spring distribution. A LoadTimeWeaver is
responsible for adding one or more
java.lang.instrument.ClassFileTransformers to a ClassLoader at
runtime, which opens the door to all manner of interesting applications, one of which
happens to be the LTW of aspects.
Alternatively, if you prefer XML based configuration, use the <context:load-timeweaver/> element. Note that the element is defined in the 'context' namespace.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:load-time-weaver/>
</beans>
The above configuration will define and register a number of LTW-specific infrastructure
beans for you automatically, such as a LoadTimeWeaver and an
AspectJWeavingEnabler. The default LoadTimeWeaver is the
DefaultContextLoadTimeWeaver class, which attempts to decorate an automatically
detected LoadTimeWeaver: the exact type of LoadTimeWeaver that will be
'automatically detected' is dependent upon your runtime environment (summarized in the
following table).
LoadTimeWeaver implementation
WebLogicLoadTimeWeaver
WebSphereLoadTimeWeaver
OC4JLoadTimeWeaver
Running in GlassFish
GlassFishLoadTimeWeaver
Running in JBoss AS
JBossLoadTimeWeaver
InstrumentationLoadTimeWeaver
Note that these are just the LoadTimeWeavers that are autodetected when using the
DefaultContextLoadTimeWeaver: it is of course possible to specify exactly which
LoadTimeWeaver implementation that you wish to use.
To specify a specific LoadTimeWeaver with Java configuration implement the
LoadTimeWeavingConfigurer interface and override the getLoadTimeWeaver()
method:
@Configuration
@EnableLoadTimeWeaving
public class AppConfig implements LoadTimeWeavingConfigurer {
@Override
public LoadTimeWeaver getLoadTimeWeaver() {
return new ReflectiveLoadTimeWeaver();
}
}
If you are using XML based configuration you can specify the fully-qualified classname as
the value of the 'weaver-class' attribute on the <context:load-time-weaver/>
element:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:load-time-weaver
weaver-class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver"/>
</beans>
The LoadTimeWeaver that is defined and registered by the configuration can be later
retrieved from the Spring container using the well-known name 'loadTimeWeaver'.
Remember that the LoadTimeWeaver exists just as a mechanism for Spring's LTW
infrastructure to add one or more ClassFileTransformers. The actual
ClassFileTransformer that does the LTW is the
ClassPreProcessorAgentAdapter (from the org.aspectj.weaver.loadtime
package) class. See the class-level Javadoc for the
ClassPreProcessorAgentAdapter class for further details, because the specifics of
how the weaving is actually effected is beyond the scope of this section.
There is one final attribute of the configuration left to discuss: the 'aspectjWeaving'
attribute (or 'aspectj-weaving' if you are using XML). This is a simple attribute that
controls whether LTW is enabled or not, it is as simple as that. It accepts one of three
possible values, summarized below, with the default value if the attribute is not present
being 'autodetect'
XML Value
ENABLED
on
DISABLED
off
Explanation
AspectJ weaving is on, and aspects will be
woven at load-time as appropriate.
LTW is off... no aspect will be woven at load-
DISABLED
off
time.
Environment-specific configuration
This last section contains any additional settings and configuration that you will need when
using Spring's LTW support in environments such as application servers and web
containers.
Tomcat
Apache Tomcat's default class loader does not support class transformation which is why
Spring provides an enhanced implementation that addresses this need. Named
TomcatInstrumentableClassLoader, the loader works on Tomcat 5.0 and above
and can be registered individually for each web application as follows:
Tomcat 6.0.x or higher
1. Copy org.springframework.instrument.tomcat.jar into
$CATALINA_HOME/lib, where $CATALINA_HOME represents the root of the
Tomcat installation)
2. Instruct Tomcat to use the custom class loader (instead of the default) by editing
the web application context file:
<Context path="/myWebApp" docBase="/my/webApp/location">
<Loader
loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/>
</Context>
per-web application configuration which can be deployed either on the serverside at $CATALINA_HOME/conf/[enginename]/[hostname]/[webapp]context.xml or embedded inside the web-app archive at METAINF/context.xml
For efficiency, the embedded web-app configuration style is recommended
recommended because it will impact only applications that use the class loader.
See the Tomcat 5.x documentation for more details about available context
locations.
Tomcat versions prior to 5.5.20 contained a bug in the XML configuration parsing
that prevented usage of the Loader tag inside server.xml configuration,
regardless of whether a class loader is specified or whether it is the official or a
custom one. See Tomcat's bugzilla for more details.
In Tomcat 5.5.x, versions 5.5.20 or later, you should set
useSystemClassLoaderAsParent to false to fix this problem:
<Context path="/myWebApp" docBase="/my/webApp/location">
<Loader
loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"
useSystemClassLoaderAsParent="false"/>
</Context>
Note that this requires modification of the VM launch script which may prevent you from
10.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 matches(Class clazz);
}
The matches(Method, Class) method is used to test whether this pointcut will ever
match a given method on a target class. This evaluation can be performed when an AOP
proxy is created, to avoid the need for a test on every method invocation. If the 2-argument
matches method returns true for a given method, and the isRuntime() method for the
MethodMatcher returns true, the 3-argument matches method will be invoked on every
method invocation. This enables a pointcut to look at the arguments passed to the method
invocation immediately before the target advice is to execute.
Most MethodMatchers are static, meaning that their isRuntime() method returns false.
In this case, the 3-argument matches method will never be invoked.
Tip
If possible, try to make pointcuts static, allowing the AOP framework to
cache the results of pointcut evaluation when an AOP proxy is created.
Static pointcuts
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.
regular expression pointcut, using the regular expression support in JDK 1.4+.
Using the JdkRegexpMethodPointcut 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.JdkRegexpMethodPointcut">
<property name="patterns">
<list>
<value>.*set.*</value>
<value>.*absquatulate</value>
</list>
</property>
</bean>
Attribute-driven pointcuts
An important type of static pointcut is a metadata-driven pointcut. This uses the values of
metadata attributes: typically, source-level metadata.
Dynamic pointcuts
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 provides useful pointcut superclasses to help you to implement your own pointcuts.
Because static pointcuts are most useful, you'll probably subclass
StaticMethodMatcherPointcut, as shown below. This requires implementing just one
abstract method (although it's possible to override other methods to customize behavior):
class TestStaticPointcut extends StaticMethodMatcherPointcut {
public boolean matches(Method m, Class targetClass) {
// return true if custom criteria match
}
}
The MethodInvocation argument to the invoke() method exposes the method being
invoked; the target join point; the AOP proxy; and the arguments to the method. The
invoke() method should return the invocation's result: the return value of the join point.
A simple MethodInterceptor implementation looks as follows:
public class DebugInterceptor implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("Before: invocation=[" + invocation + "]");
Object rval = invocation.proceed();
System.out.println("Invocation returned");
return rval;
}
}
Note the call to the MethodInvocation's proceed() method. This proceeds down the
interceptor chain towards the join point. Most interceptors will invoke this method, and
return its return value. However, a MethodInterceptor, like any around advice, can return a
different value or throw an exception rather than invoke the proceed method. However, you
don't want to do this without good reason!
Note
MethodInterceptors offer interoperability with other AOP Alliancecompliant AOP implementations. The other advice types discussed in
the remainder of this section implement common AOP concepts, but in
a Spring-specific way. While there is an advantage in using the most
specific advice type, stick with MethodInterceptor around advice if you
are likely to want to run the aspect in another AOP framework. Note that
pointcuts are not currently interoperable between frameworks, and the
AOP Alliance does not currently define pointcut interfaces.
Before advice
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 {
void before(Method m, Object[] args, Object target) throws Throwable;
}
Note the return type is void. Before advice can insert custom behavior before the join
point executes, but cannot change the return value. If a before advice throws an exception,
this will abort further execution of the interceptor chain. The exception will propagate back
up the interceptor chain. If it is unchecked, or on the signature of the invoked method, it will
be passed directly to the client; otherwise it will be wrapped in an unchecked exception by
the AOP proxy.
An example of a before advice in Spring, which counts all method invocations:
public class CountingBeforeAdvice implements MethodBeforeAdvice {
private int count;
public void before(Method m, Object[] args, Object target) throws Throwable {
++count;
}
public int getCount() {
return count;
}
}
Tip
Before advice can be used with any pointcut.
Throws advice
Throws advice is invoked after the return of the join point if the join point 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 in the form of:
afterThrowing([Method, args, target], subclassOfThrowable)
Only the last argument is required. The method signatures may have either one or four
arguments, depending on whether the advice method is interested in the method and
arguments. The following classes are examples of throws advice.
The advice below is invoked if a RemoteException is thrown (including subclasses):
public class RemoteThrowsAdvice implements ThrowsAdvice {
public void afterThrowing(RemoteException ex) throws Throwable {
// Do something with remote exception
}
}
The final example illustrates how these two methods could be used in a single class,
which handles both RemoteException and ServletException. Any number of
throws advice methods can be combined in a single class.
public static class CombinedThrowsAdvice implements ThrowsAdvice {
public void afterThrowing(RemoteException ex) throws Throwable {
// Do something with remote exception
}
public void afterThrowing(Method m, Object[] args, Object target, ServletException ex) {
// Do something with all arguments
}
}
Note: If a throws-advice method throws an exception itself, it will override the original
exception (i.e. change the exception thrown to the user). The overriding exception will
typically be a RuntimeException; this is compatible with any method signature. However, if
a throws-advice method throws a checked exception, it will have to match the declared
exceptions of the target method and is hence to some degree coupled to specific target
method signatures. Do not throw an undeclared checked exception that is incompatible
with the target method's signature!
Tip
Throws advice can be used with any pointcut.
An after returning advice has access to the return value (which it cannot modify), invoked
method, methods arguments and target.
The following after returning advice counts all successful method invocations that have not
thrown exceptions:
public class CountingAfterReturningAdvice implements AfterReturningAdvice {
private int count;
public void afterReturning(Object returnValue, Method m, Object[] args, Object target)
throws Throwable {
++count;
}
public int getCount() {
return count;
}
}
This advice doesn't change the execution path. If it throws an exception, this will be thrown
up the interceptor chain instead of the return value.
Tip
After returning advice can be used with any pointcut.
Introduction advice
Spring treats introduction advice as a special kind of interception advice.
Introduction requires an IntroductionAdvisor, and an
IntroductionInterceptor, implementing the following interface:
public interface IntroductionInterceptor extends MethodInterceptor {
boolean implementsInterface(Class intf);
}
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 suppressInterface(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
implements Lockable {
private boolean locked;
public void lock() {
this.locked = true;
}
public void unlock() {
this.locked = false;
}
public boolean locked() {
return this.locked;
}
public Object invoke(MethodInvocation invocation) throws Throwable {
if (locked() && invocation.getMethod().getName().indexOf("set") == 0)
throw new LockedException();
return super.invoke(invocation);
}
}
10.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 another 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.
Note that the interceptorNames property takes a list of String: the bean names of the
interceptor or advisors in the current factory. Advisors, interceptors, before, after returning
and throws advice objects can be used. The ordering of advisors is significant.
Note
You might be wondering why the list doesn't hold bean references. The
reason for this is that if the ProxyFactoryBean's singleton property is set
to false, it must be able to return independent proxy instances. If any of
the advisors is itself a prototype, an independent instance would need
to be returned, so it's necessary to be able to obtain an instance of the
prototype from the factory; holding a reference isn't sufficient.
The "person" bean definition above can be used in place of a Person implementation, as
follows:
Person person = (Person) factory.getBean("person");
Other beans in the same IoC context can express a strongly typed dependency on it, as
with an ordinary Java object:
<bean id="personUser" class="com.mycompany.PersonUser">
<property name="person"><ref local="person"/></property>
</bean>
The PersonUser class in this example would expose a property of type Person. As far as
it's concerned, the AOP proxy can be used transparently in place of a "real" person
implementation. However, its class would be a dynamic proxy class. It would be possible
to cast it to the Advised interface (discussed below).
It's possible to conceal the distinction between target and proxy using an anonymous inner
bean, as follows. Only the ProxyFactoryBean definition is different; the advice is
included only for completeness:
<bean id="myAdvisor" class="com.mycompany.MyAdvisor">
<property name="someProperty" value="Custom string property value"/>
</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 from 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.
</bean>
<bean id="global_debug" class="org.springframework.aop.interceptor.DebugInterceptor"/>
<bean id="global_performance" class="org.springframework.aop.interceptor.PerformanceMonitorInterceptor"/>
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 wraps the target of the
proxy as an inner bean definition, since the target will never be used on its own anyway.
<bean id="myService" parent="txProxyTemplate">
<property name="target">
<bean class="org.springframework.samples.MyServiceImpl">
</bean>
</property>
</bean>
It is of course possible to override properties from the parent template, such as in this case,
the transaction propagation settings:
<bean id="mySpecialService" parent="txProxyTemplate">
<property name="target">
<bean class="org.springframework.samples.MySpecialServiceImpl">
</bean>
</property>
<property name="transactionAttributes">
<props>
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="load*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="store*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
Note that in the example above, we have explicitly marked the parent bean definition as
abstract by using the abstract attribute, as described previously, so that it may not actually
ever be instantiated. Application contexts (but not simple bean factories) will by default preinstantiate all singletons. It is therefore important (at least for singleton beans) that if you
have a (parent) bean definition which you intend to use only as a template, and this
definition specifies a class, you must make sure to set the abstract attribute to true,
otherwise the application context will actually try to pre-instantiate it.
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 introductions).
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
Note
It's questionable whether it's advisable (no pun intended) to modify
advice on a business object in production, although there are no doubt
legitimate usage cases. However, it can be very useful in development:
for example, in tests. I have sometimes found it very useful to be able to
add test code in the form of an interceptor or other advice, getting inside
a method invocation I want to test. (For example, the advice can get
inside a transaction created for that method: for example, to run SQL to
check that a database was correctly updated, before marking the
transaction for roll back.)
Depending on how you created the proxy, you can usually set a frozen flag, in which
case the Advised isFrozen() method will return true, and any attempts to modify
advice through addition or removal will result in an AopConfigException. The ability to
freeze the state of an advised object is useful in some cases, for example, to prevent
calling code removing a security interceptor. It may also be used in Spring 1.1 to allow
aggressive optimization if runtime advice modification is known not to be required.
BeanNameAutoProxyCreator
The BeanNameAutoProxyCreator class is a BeanPostProcessor that
automatically creates AOP proxies for beans with names matching literal values or
wildcards.
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames" value="jdk*,onlyJdk"/>
<property name="interceptorNames">
<list>
<value>myInterceptor</value>
</list>
</property>
</bean>
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 auto-proxy
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 any) advice it should apply to each business
object (such as "businessObject1" and "businessObject2" in the example).
This means that any number of advisors can be applied automatically to each business
object. If no pointcut in any of the advisors matches any method in a business object, the
object will not be proxied. As bean definitions are added for new business objects, they
will automatically be proxied if necessary.
Autoproxying in general has the advantage of making it impossible for callers or
dependencies to obtain an un-advised object. Calling getBean("businessObject1") on this
ApplicationContext will return an AOP proxy, not the target business object. (The "inner
bean" idiom shown earlier also offers this benefit.)
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
<bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">
<property name="transactionInterceptor" ref="transactionInterceptor"/>
</bean>
<bean id="customAdvisor" class="com.mycompany.MyAdvisor"/>
<bean id="businessObject1" class="com.mycompany.BusinessObject1">
<!-- Properties omitted -->
</bean>
<bean id="businessObject2" class="com.mycompany.BusinessObject2"/>
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; the default setting is unordered.
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 behavior of the framework
DefaultAdvisorAutoProxyCreator.
Tip
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 auto-proxying 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"
scope="prototype"/>
<bean id="lockableAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"
scope="prototype">
<property name="pointcut" ref="myAttributeAwarePointcut"/>
<property name="advice" ref="lockMixin"/>
</bean>
<bean id="anyBean" class="anyclass" ...
If the attribute aware pointcut matches any methods in the anyBean or other bean
definitions, the mixin will be applied. Note that both lockMixin and lockableAdvisor
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.
EJBs, in which a pool of identical instances is maintained, with method invocations going
to free objects in the pool.
A crucial difference between Spring pooling and SLSB pooling is that Spring pooling can
be applied to any POJO. As with Spring in general, this service can be applied in a noninvasive way.
Spring provides out-of-the-box support for Jakarta Commons Pool 1.3, which provides a
fairly efficient pooling implementation. You'll need the commons-pool Jar on your
application's classpath to use this feature. It's also possible to subclass
org.springframework.aop.target.AbstractPoolingTargetSource to
support any other pooling API.
Sample configuration is shown below:
<bean id="businessObjectTarget" class="com.mycompany.MyBusinessObject"
scope="prototype">
... properties omitted
</bean>
<bean id="poolTargetSource" class="org.springframework.aop.target.CommonsPoolTargetSource">
<property name="targetBeanName" value="businessObjectTarget"/>
<property name="maxSize" value="25"/>
</bean>
<bean id="businessObject" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource" ref="poolTargetSource"/>
<property name="interceptorNames" value="myInterceptor"/>
</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 its 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 necessary to specify interceptors to use pooling. If
you want only pooling, and no other advice, don't set the interceptorNames property at all.
It's possible to configure Spring so as to be able to cast any pooled object to the
org.springframework.aop.target.PoolingConfig interface, which exposes
information about the configuration and current size of the pool through an introduction.
You'll need to define an advisor like this:
<bean id="poolConfigAdvisor" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="poolTargetSource"/>
<property name="targetMethod" value="getPoolingConfigMixin"/>
</bean>
Note
Pooling stateless service objects is not usually necessary. We don't
believe it should be the default choice, as most stateless objects are
naturally thread safe, and instance pooling is problematic if resources
are cached.
Simpler pooling is available using auto-proxying. It's possible to set the TargetSources
used by any auto-proxy creator.
There's only one property: the name of the target bean. Inheritance is used in the
TargetSource implementations to ensure consistent naming. As with the pooling target
source, the target bean must be a prototype bean definition.
Note
ThreadLocals come with serious issues (potentially resulting in
memory leaks) when incorrectly using them in a multi-threaded and
multi-classloader environments. One should always consider wrapping
a threadlocal in some other class and never directly use the
ThreadLocal itself (except of course in the wrapper class). Also, one
should always remember to correctly set and unset (where the latter
simply involved a call to ThreadLocal.set(null)) the resource
local to the thread. Unsetting should be done in any case since not
unsetting it might result in problematic behavior. Spring's ThreadLocal
support does this for you and should always be considered in favor of
using ThreadLocals without other proper handling code.
11. Testing
11.1 Introduction to Spring Testing
Testing is an integral part of enterprise software development. This chapter focuses on the
value-add of the IoC principle to unit testing and on the benefits of the Spring Framework's
support for integration testing. (A thorough treatment of testing in the enterprise is beyond
the scope of this reference manual.)
JNDI
The org.springframework.mock.jndi package contains an implementation of the
JNDI SPI, which you can use to set up a simple JNDI environment for test suites or standalone applications. If, for example, JDBC DataSources get bound to the same JNDI
names in test code as within a Java EE container, you can reuse both application code
and configuration in testing scenarios without modification.
Servlet API
The org.springframework.mock.web package contains a comprehensive set of
Servlet API mock objects, targeted at usage with Spring's Web MVC framework, which are
useful for testing web contexts and controllers. These mock objects are generally more
convenient to use than dynamic mock objects such as EasyMock or existing Servlet API
Portlet API
The org.springframework.mock.web.portlet package contains a set of Portlet
API mock objects, targeted at usage with Spring's Portlet MVC framework.
Spring MVC
The org.springframework.test.web package contains ModelAndViewAssert,
which you can use in combination with JUnit, TestNG, or any other testing framework for
unit tests dealing with Spring MVC ModelAndView objects.
Unit testing Spring MVC Controllers
To test your Spring MVC Controllers, use
ModelAndViewAssert combined with
MockHttpServletRequest, MockHttpSession, and so on from
the org.springframework.mock.web package.
When the TestContext framework loads your application context, it can optionally configure
instances of your test classes via Dependency Injection. This provides a convenient
mechanism for setting up test fixtures using preconfigured beans from your application
context. A strong benefit here is that you can reuse application contexts across various
testing scenarios (e.g., for configuring Spring-managed object graphs, transactional
proxies, DataSources, etc.), thus avoiding the need to duplicate complex test fixture
setup for individual test cases.
As an example, consider the scenario where we have a class,
HibernateTitleRepository, that implements data access logic for a Title domain
entity. We want to write integration tests that test the following areas:
The Spring configuration: basically, is everything related to the configuration of the
HibernateTitleRepository bean correct and present?
The Hibernate mapping file configuration: is everything mapped correctly, and are the
correct lazy-loading settings in place?
The logic of the HibernateTitleRepository: does the configured instance of
this class perform as anticipated?
See dependency injection of test fixtures with the TestContext framework.
Transaction management
One common issue in tests that access a real database is their effect on the state of the
persistence store. Even when you're using a development database, changes to the state
may affect future tests. Also, many operations such as inserting or modifying persistent
data cannot be performed (or verified) outside a transaction.
The TestContext framework addresses this issue. By default, the framework will create and
roll back a transaction for each test. You simply write code that can assume the existence
of a transaction. If you call transactionally proxied objects in your tests, they will behave
correctly, according to their configured transactional semantics. In addition, if a test method
deletes the contents of selected tables while running within the transaction managed for
the test, the transaction will roll back by default, and the database will return to its state
prior to execution of the test. Transactional support is provided to a test via a
PlatformTransactionManager bean defined in the test's application context.
If you want a transaction to commit unusual, but occasionally useful when you want a
particular test to populate or modify the database the TestContext framework can be
instructed to cause the transaction to commit instead of roll back via the
@TransactionConfiguration and @Rollback annotations.
See transaction management with the TestContext framework.
11.3.4 Annotations
Spring Testing Annotations
The Spring Framework provides the following set of Spring-specific annotations that you
can use in your unit and integration tests in conjunction with the TestContext framework.
Refer to the respective Javadoc for further information, including default attribute values,
attribute aliases, and so on.
@ContextConfiguration
Defines class-level metadata that is used to determine how to load and configure an
ApplicationContext for integration tests. Specifically,
@ContextConfiguration declares either the application context resource
locations or the annotated classes that will be used to load the context.
Resource locations are typically XML configuration files located in the classpath;
whereas, annotated classes are typically @Configuration classes. However,
resource locations can also refer to files in the file system, and annotated classes can
be component classes, etc.
@ContextConfiguration("/test-config.xml")
public class XmlApplicationContextTests {
// class body...
}
@ContextConfiguration(classes = TestConfig.class)
public class ConfigClassApplicationContextTests {
// class body...
}
Note
To override the default, specify a different base resource path via the implicit value
attribute. Both classpath: and file: resource prefixes are supported. If no
resource prefix is supplied the path is assumed to be a file system resource.
@ContextConfiguration
@WebAppConfiguration("classpath:test-web-resources")
public class WebAppTests {
// class body...
}
If you need to merge or override the configuration for a given level of the context
hierarchy within a test class hierarchy, you must explicitly name that level by supplying
the same value to the name attribute in @ContextConfiguration at each
corresponding level in the class hierarchy. See the section called Context
hierarchies and the Javadoc for @ContextHierarchy for further examples.
@ActiveProfiles
A class-level annotation that is used to declare which bean definition profiles should
Note
@ActiveProfiles provides support for inheriting active bean
definition profiles declared by superclasses by default.
See the section called Context configuration with environment profiles and the
Javadoc for @ActiveProfiles for examples and further details.
@DirtiesContext
Indicates that the underlying Spring ApplicationContext has been dirtied during
the execution of a test (i.e., modified or corrupted in some manner for example, by
changing the state of a singleton bean) and should be closed, regardless of whether
the test passed. When an application context is marked dirty, it is removed from the
testing framework's cache and closed. As a consequence, the underlying Spring
container will be rebuilt for any subsequent test that requires a context with the same
configuration metadata.
@DirtiesContext can be used as both a class-level and method-level annotation
within the same test class. In such scenarios, the ApplicationContext is marked
as dirty after any such annotated method as well as after the entire class. If the
ClassMode is set to AFTER_EACH_TEST_METHOD, the context is marked dirty after
each test method in the class.
The following examples explain when the context would be dirtied for various
configuration scenarios:
After the current test class, when declared on a class with class mode set to
AFTER_CLASS (i.e., the default class mode).
@DirtiesContext
public class ContextDirtyingTests {
// some tests that result in the Spring container being dirtied
}
After each test method in the current test class, when declared on a class with
class mode set to AFTER_EACH_TEST_METHOD.
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
public class ContextDirtyingTests {
// some tests that result in the Spring container being dirtied
}
For further details regarding the EXHAUSTIVE and CURRENT_LEVEL algorithms see
the Javadoc for DirtiesContext.HierarchyMode.
@TestExecutionListeners
Defines class-level metadata for configuring which TestExecutionListeners
should be registered with the TestContextManager. Typically,
@TestExecutionListeners is used in conjunction with
@ContextConfiguration.
@ContextConfiguration
@TestExecutionListeners({CustomTestExecutionListener.class, AnotherTestExecutionListener.class})
public class CustomTestExecutionListenerTests {
// class body...
}
Note
If the default conventions are sufficient for your test configuration,
you can avoid using @TransactionConfiguration
altogether. In other words, if you have only one transaction manger
or if you have multiple transaction mangers but the transaction
manager for tests is named "transactionManager" or specified via a
TransactionManagementConfigurer and if you want
transactions to roll back automatically, then there is no need to
annotate your test class with @TransactionConfiguration.
@Rollback
Indicates whether the transaction for the annotated test method should be rolled back
after the test method has completed. If true, the transaction is rolled back; otherwise,
the transaction is committed. Use @Rollback to override the default rollback flag
configured at the class level.
@Rollback(false)
@Test
public void testProcessWithoutRollback() {
// ...
}
@BeforeTransaction
Indicates that the annotated public void method should be executed before a
transaction is started for test methods configured to run within a transaction via the
@Transactional annotation.
@BeforeTransaction
public void beforeTransaction() {
// logic to be executed before a transaction is started
}
@AfterTransaction
Indicates that the annotated public void method should be executed after a
transaction has ended for test methods configured to run within a transaction via the
@Transactional annotation.
@AfterTransaction
public void afterTransaction() {
// logic to be executed after a transaction has ended
}
@NotTransactional
The presence of this annotation indicates that the annotated test method must not
execute in a transactional context.
@NotTransactional
@Test
public void testProcessWithoutTransaction() {
// ...
}
@NotTransactional is deprecated
As of Spring 3.0, @NotTransactional is deprecated in favor of
moving the non-transactional test method to a separate (nontransactional) test class or to a @BeforeTransaction or
@AfterTransaction method. As an alternative to annotating an
entire class with @Transactional, consider annotating
individual methods with @Transactional; doing so allows a mix
of transactional and non-transactional methods in the same test
class without the need for using @NotTransactional.
@ProfileValueSourceConfiguration
Class-level annotation that specifies what type of ProfileValueSource to use
when retrieving profile values configured through the @IfProfileValue annotation.
If @ProfileValueSourceConfiguration is not declared for a test,
SystemProfileValueSource is used by default.
@ProfileValueSourceConfiguration(CustomProfileValueSource.class)
public class CustomProfileValueSourceTests {
// class body...
}
@Timed
Indicates that the annotated test method must finish execution in a specified time
period (in milliseconds). If the text execution time exceeds the specified time period,
the test fails.
The time period includes execution of the test method itself, any repetitions of the test
(see @Repeat), as well as any set up or tear down of the test fixture.
@Timed(millis=1000)
public void testProcessWithOneSecondTimeout() {
// some logic that should not take longer than 1 second to execute
}
and preemptively fails the test if the test takes too long. Spring's @Timed, on the other
hand, times the total test execution time (including all repetitions) and does not
preemptively fail the test but rather waits for the test to complete before failing.
@Repeat
Indicates that the annotated test method must be executed repeatedly. The number of
times that the test method is to be executed is specified in the annotation.
The scope of execution to be repeated includes execution of the test method itself as
well as any set up or tear down of the test fixture.
@Repeat(10)
@Test
public void testProcessRepeatedly() {
// ...
}
Key abstractions
The core of the framework consists of the TestContext and TestContextManager
classes and the TestExecutionListener, ContextLoader, and
SmartContextLoader interfaces. A TestContextManager is created on a per-test
basis (e.g., for the execution of a single test method in JUnit). The
TestContextManager in turn manages a TestContext that holds the context of the
current test. The TestContextManager also updates the state of the TestContext as
the test progresses and delegates to TestExecutionListeners, which instrument the
actual test execution by providing dependency injection, managing transactions, and so
on. A ContextLoader (or SmartContextLoader) is responsible for loading an
ApplicationContext for a given test class. Consult the Javadoc and the Spring test
suite for further information and examples of various implementations.
TestContext: Encapsulates the context in which a test is executed, agnostic of the
actual testing framework in use, and provides context management and caching
support for the test instance for which it is responsible. The TestContext also
delegates to a ContextLoader (or SmartContextLoader) to load an
ApplicationContext if requested.
TestContextManager: The main entry point into the Spring TestContext
Framework, which manages a single TestContext and signals events to all
registered TestExecutionListeners at well-defined test execution points:
prior to any before class methods of a particular testing framework
test instance preparation
prior to any before methods of a particular testing framework
after any after methods of a particular testing framework
Context management
Each TestContext provides context management and caching support for the test
instance it is responsible for. Test instances do not automatically receive access to the
configured ApplicationContext. However, if a test class implements the
ApplicationContextAware interface, a reference to the ApplicationContext is
If you omit both the locations and value attributes from the
@ContextConfiguration annotation, the TestContext framework will attempt to detect
a default XML resource location. Specifically, GenericXmlContextLoader detects a
default location based on the name of the test class. If your class is named
com.example.MyTest, GenericXmlContextLoader loads your application context
from "classpath:/com/example/MyTest-context.xml".
package com.example;
@RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from
// "classpath:/com/example/MyTest-context.xml"
@ContextConfiguration
public class MyTest {
// class body...
}
If you omit the classes attribute from the @ContextConfiguration annotation, the
TestContext framework will attempt to detect the presence of default configuration classes.
Specifically, AnnotationConfigContextLoader will detect all static inner classes of
the test class that meet the requirements for configuration class implementations as
specified in the Javadoc for @Configuration. In the following example, the
OrderServiceTest class declares a static inner configuration class named Config
that will be automatically used to load the ApplicationContext for the test class. Note
that the name of the configuration class is arbitrary. In addition, a test class can contain
more than one static inner configuration class if desired.
@RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from the
// static inner Config class
@ContextConfiguration
public class OrderServiceTest {
@Configuration
static class Config {
// this bean will be injected into the OrderServiceTest class
@Bean
public OrderService orderService() {
OrderService orderService = new OrderServiceImpl();
// set properties, etc.
return orderService;
}
}
@Autowired
private OrderService orderService;
@Test
public void testOrderService() {
// test the orderService
}
}
It is also possible to omit the declaration of XML configuration files or annotated classes in
@ContextConfiguration entirely and instead declare only
ApplicationContextInitializer classes which are then responsible for
registering beans in the context for example, by programmatically loading bean
definitions from XML files or configuration classes.
@RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be initialized by EntireAppInitializer
// which presumably registers beans in the context
@ContextConfiguration(initializers = EntireAppInitializer.class)
public class MyTest {
// class body...
}
In the following example that uses context initializers, the ApplicationContext for
ExtendedTest will be initialized using BaseInitializer and
ExtendedInitializer. Note, however, that the order in which the initializers are
invoked depends on whether they implement Spring's Ordered interface or are annotated
with Spring's @Order annotation.
@RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be initialized by BaseInitializer
@ContextConfiguration(initializers=BaseInitializer.class)
public class BaseTest {
// class body...
}
// ApplicationContext will be initialized by BaseInitializer
// and ExtendedInitializer
@ContextConfiguration(initializers=ExtendedInitializer.class)
public class ExtendedTest extends BaseTest {
// class body...
}
In this variation, we have split the XML configuration into three independent
@Configuration classes:
TransferServiceConfig: acquires a dataSource via dependency injection
using @Autowired
StandaloneDataConfig: defines a dataSource for an embedded database
suitable for developer tests
JndiDataConfig: defines a dataSource that is retrieved from JNDI in a
production environment
As with the XML-based configuration example, we still annotate
TransferServiceTest with @ActiveProfiles("dev"), but this time we specify all
three configuration classes via the @ContextConfiguration annotation. The body of
the test class itself remains completely unchanged.
Loading a WebApplicationContext
Spring 3.2 introduces support for loading a WebApplicationContext in integration
tests. To instruct the TestContext framework to load a WebApplicationContext
instead of a standard ApplicationContext, simply annotate the respective test class
with @WebAppConfiguration.
The presence of @WebAppConfiguration on your test class instructs the TestContext
framework (TCF) that a WebApplicationContext (WAC) should be loaded for your
integration tests. In the background the TCF makes sure that a MockServletContext is
created and supplied to your test's WAC. By default the base resource path for your
MockServletContext will be set to "src/main/webapp". This is interpreted as a path
relative to the root of your JVM (i.e., normally the path to your project). If you're familiar with
the directory structure of a web application in a Maven project, you'll know that
"src/main/webapp" is the default location for the root of your WAR. If you need to override
this default, simply provide an alternate path to the @WebAppConfiguration annotation
(e.g., @WebAppConfiguration("src/test/webapp")). If you wish to reference a
base resource path from the classpath instead of the file system, just use Spring's
classpath: prefix.
Please note that Spring's testing support for WebApplicationContexts is on par with
its support for standard ApplicationContexts. When testing with a
WebApplicationContext you are free to declare either XML configuration files or
@Configuration classes via @ContextConfiguration. You are of course also free
to use any other test annotations such as @TestExecutionListeners,
@TransactionConfiguration, @ActiveProfiles, etc.
The following examples demonstrate some of the various configuration options for loading
a WebApplicationContext.
Example 11.1. Conventions
@RunWith(SpringJUnit4ClassRunner.class)
// defaults to "file:src/main/webapp"
@WebAppConfiguration
// detects "WacTests-context.xml" in same package
// or static nested @Configuration class
@ContextConfiguration
public class WacTests {
//...
}
The above example demonstrates the TestContext framework's support for convention
over configuration. If you annotate a test class with @WebAppConfiguration without
specifying a resource base path, the resource path will effectively default to
"file:src/main/webapp". Similarly, if you declare @ContextConfiguration without
This example demonstrates how to explicitly declare a resource base path with
@WebAppConfiguration and an XML resource location with
@ContextConfiguration. The important thing to note here is the different semantics
for paths with these two annotations. By default, @WebAppConfiguration resource
paths are file system based; whereas, @ContextConfiguration resource locations
are classpath based.
Example 11.3. Explicit resource semantics
@RunWith(SpringJUnit4ClassRunner.class)
// classpath resource
@WebAppConfiguration("classpath:test-web-resources")
// file system resource
@ContextConfiguration("file:src/main/webapp/WEB-INF/servlet-config.xml")
public class WacTests {
//...
}
In this third example, we see that we can override the default resource semantics for both
annotations by specifying a Spring resource prefix. Contrast the comments in this example
with the previous example.
@WebAppConfiguration
@ContextConfiguration
public class WacTests {
@Autowired WebApplicationContext wac; // cached
@Autowired MockServletContext servletContext; // cached
@Autowired MockHttpSession session;
@Autowired MockHttpServletRequest request;
@Autowired MockHttpServletResponse response;
@Autowired ServletWebRequest webRequest;
//...
}
Context caching
Once the TestContext framework loads an ApplicationContext (or
WebApplicationContext) for a test, that context will be cached and reused for all
subsequent tests that declare the same unique context configuration within the same test
suite. To understand how caching works, it is important to understand what is meant by
unique and test suite.
An ApplicationContext can be uniquely identified by the combination of
configuration parameters that are used to load it. Consequently, the unique combination of
configuration parameters are used to generate a key under which the context is cached.
The TestContext framework uses the following configuration parameters to build the
context cache key:
locations (from @ContextConfiguration)
classes (from @ContextConfiguration)
contextInitializerClasses (from @ContextConfiguration)
contextLoader (from @ContextConfiguration)
activeProfiles (from @ActiveProfiles)
resourceBasePath (from @WebAppConfiguration)
For example, if TestClassA specifies {"app-config.xml", "testconfig.xml"} for the locations (or value) attribute of @ContextConfiguration,
the TestContext framework will load the corresponding ApplicationContext and store
it in a static context cache under a key that is based solely on those locations. So if
TestClassB also defines {"app-config.xml", "test-config.xml"} for its
locations (either explicitly or implicitly through inheritance) but does not define
@WebAppConfiguration, a different ContextLoader, different active profiles, or
different context initializers, then the same ApplicationContext will be shared by both
test classes. This means that the setup cost for loading an application context is incurred
only once (per test suite), and subsequent test execution is much faster.
Test suites and forked processes
The Spring TestContext framework stores application contexts in a
static cache. This means that the context is literally stored in a static
variable. In other words, if tests execute in separate processes the
static cache will be cleared between each test execution, and this will
effectively disable the caching mechanism.
To benefit from the caching mechanism, all tests must run within the
same process or test suite. This can be achieved by executing all tests
as a group within an IDE. Similarly, when executing tests with a build
framework such as Ant, Maven, or Gradle it is important to make sure
that the build framework does not fork between tests. For example, if
the forkMode for the Maven Surefire plug-in is set to always or
pertest, the TestContext framework will not be able to cache
application contexts between test classes and the build process will
run significantly slower as a result.
In the unlikely case that a test corrupts the application context and requires reloading for
example, by modifying a bean definition or the state of an application object you can
annotate your test class or test method with @DirtiesContext (see the discussion of
@DirtiesContext in the section called Spring Testing Annotations). This instructs
Spring to remove the context from the cache and rebuild the application context before
executing the next test. Note that support for the @DirtiesContext annotation is
provided by the DirtiesContextTestExecutionListener which is enabled by
default.
Context hierarchies
When writing integration tests that rely on a loaded Spring ApplicationContext, it is
often sufficient to test against a single context; however, there are times when it is
beneficial or even necessary to test against a hierarchy of ApplicationContexts. For
example, if you are developing a Spring MVC web application you will typically have a root
WebApplicationContext loaded via Spring's ContextLoaderListener and a
child WebApplicationContext loaded via Spring's DispatcherServlet. This
results in a parent-child context hierarchy where shared components and infrastructure
configuration are declared in the root context and consumed in the child context by webspecific components. Another use case can be found in Spring Batch applications where
you often have a parent context that provides configuration for shared batch infrastructure
and a child context for the configuration of a specific batch job.
As of Spring Framework 3.2.2, it is possible to write integration tests that use context
hierarchies by declaring context configuration via the @ContextHierarchy annotation,
either on an individual test class or within a test class hierarchy. If a context hierarchy is
declared on multiple classes within a test class hierarchy it is also possible to merge or
override the context configuration for a specific, named level in the context hierarchy.
When merging configuration for a given level in the hierarchy the configuration resource
type (i.e., XML configuration files or annotated classes) must be consistent; otherwise, it is
perfectly acceptable to have different levels in a context hierarchy configured using
different resource types.
The following JUnit-based examples demonstrate common configuration scenarios for
integration tests that require the use of context hierarchies.
Example 11.5. Single test class with context hierarchy
ControllerIntegrationTests represents a typical integration testing scenario for a
Spring MVC web application by declaring a context hierarchy consisting of two levels, one
for the root WebApplicationContext (loaded using the TestAppConfig
@Configuration class) and one for the dispatcher servlet WebApplicationContext
(loaded using the WebConfig @Configuration class). The
WebApplicationContext that is autowired into the test instance is the one for the child
context (i.e., the lowest context in the hierarchy).
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextHierarchy({
@ContextConfiguration(classes = TestAppConfig.class),
@ContextConfiguration(classes = WebConfig.class)
})
public class ControllerIntegrationTests {
@Autowired
private WebApplicationContext wac;
// ...
}
The first code listing shows a JUnit-based implementation of the test class that uses
@Autowired for field injection.
@RunWith(SpringJUnit4ClassRunner.class)
// specifies the Spring configuration to load for this test fixture
@ContextConfiguration("repository-config.xml")
public class HibernateTitleRepositoryTests {
// this instance will be dependency injected by type
@Autowired
private HibernateTitleRepository titleRepository;
@Test
public void findById() {
Title title = titleRepository.findById(new Long(10));
assertNotNull(title);
}
}
Alternatively, you can configure the class to use @Autowired for setter injection as seen
below.
@RunWith(SpringJUnit4ClassRunner.class)
// specifies the Spring configuration to load for this test fixture
@ContextConfiguration("repository-config.xml")
public class HibernateTitleRepositoryTests {
// this instance will be dependency injected by type
private HibernateTitleRepository titleRepository;
@Autowired
public void setTitleRepository(HibernateTitleRepository titleRepository) {
this.titleRepository = titleRepository;
}
@Test
public void findById() {
Title title = titleRepository.findById(new Long(10));
assertNotNull(title);
}
}
The preceding code listings use the same XML context file referenced by the
@ContextConfiguration annotation (that is, repository-config.xml), which
looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- this bean will be injected into the HibernateTitleRepositoryTests class -->
<bean id="titleRepository" class="com.foo.repository.hibernate.HibernateTitleRepository">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<!-- configuration elided for brevity -->
</bean>
</beans>
Note
If you are extending from a Spring-provided test base class that happens to use @Autowired
on one of its setter methods, you might have multiple beans of the affected type defined in your
application context: for example, multiple DataSource beans. In such a case, you can
override the setter method and use the @Qualifier annotation to indicate a specific target
bean as follows, but make sure to delegate to the overridden method in the superclass as well.
// ...
@Autowired
@Override
public void setDataSource(@Qualifier("myDataSource") DataSource dataSource) {
super.setDataSource(dataSource);
}
// ...
The specified qualifier value indicates the specific DataSource bean to inject, narrowing the
set of type matches to a specific bean. Its value is matched against <qualifier>
declarations within the corresponding <bean> definitions. The bean name is used as a
fallback qualifier value, so you may effectively also point to a specific bean by name there (as
shown above, assuming that "myDataSource" is the bean id).
// assert results
}
}
The following code snippet is similar to the one we saw above for a request-scoped bean;
however, this time the userService bean has a dependency on a session-scoped
userPreferences bean. Note that the UserPreferences bean is instantiated using a
SpEL expression that retrieves the theme from the current HTTP session. In our test, we
will need to configure a theme in the mock session managed by the TestContext
framework.
Example 11.11. Session-scoped bean configuration
<beans>
<bean id="userService"
class="com.example.SimpleUserService"
c:userPreferences-ref="userPreferences" />
<bean id="userPreferences"
class="com.example.UserPreferences"
c:theme="#{session.getAttribute('theme')}"
scope="session">
<aop:scoped-proxy />
</bean>
</beans>
Transaction management
In the TestContext framework, transactions are managed by the
TransactionalTestExecutionListener. Note that
TransactionalTestExecutionListener is configured by default, even if you do
not explicitly declare @TestExecutionListeners on your test class. To enable
support for transactions, however, you must provide a PlatformTransactionManager
bean in the application context loaded by @ContextConfiguration semantics. In
addition, you must declare @Transactional either at the class or method level for your
tests.
For class-level transaction configuration (i.e., setting an explicit bean name for the
transaction manager and the default rollback flag), see the
@TransactionConfiguration entry in the annotation support section.
If transactions are not enabled for the entire test class, you can annotate methods explicitly
with @Transactional. To control whether a transaction should commit for a particular
test method, you can use the @Rollback annotation to override the class-level default
rollback setting.
AbstractTransactionalJUnit4SpringContextTests and
AbstractTransactionalTestNGSpringContextTests are preconfigured for
transactional support at the class level.
Occasionally you need to execute certain code before or after a transactional test method
but outside the transactional context, for example, to verify the initial database state prior to
execution of your test or to verify expected transactional commit behavior after test
execution (if the test was configured not to roll back the transaction).
TransactionalTestExecutionListener supports the @BeforeTransaction
and @AfterTransaction annotations exactly for such scenarios. Simply annotate any
public void method in your test class with one of these annotations, and the
TransactionalTestExecutionListener ensures that your before transaction
method or after transaction method is executed at the appropriate time.
Tip
Any before methods (such as methods annotated with JUnit's
@Before) and any after methods (such as methods annotated with
JUnit's @After) are executed within a transaction. In addition,
methods annotated with @BeforeTransaction or
@AfterTransaction are naturally not executed for tests annotated
with @NotTransactional. However, @NotTransactional is
deprecated as of Spring 3.0.
The following JUnit-based example displays a fictitious integration testing scenario
highlighting several transaction-related annotations. Consult the annotation support
section for further information and configuration examples.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@TransactionConfiguration(transactionManager="txMgr", defaultRollback=false)
@Transactional
public class FictitiousTransactionalTest {
@BeforeTransaction
public void verifyInitialDatabaseState() {
// logic to verify the initial state before a transaction is started
}
@Before
public void setUpTestDataWithinTransaction() {
// set up test data within the transaction
}
@Test
// overrides the class-level defaultRollback setting
@Rollback(true)
public void modifyDatabaseWithinTransaction() {
// logic which uses the test data and modifies database state
}
@After
public void tearDownWithinTransaction() {
// execute "tear down" logic within the transaction
}
@AfterTransaction
public void verifyFinalDatabaseState() {
// logic to verify the final state after transaction has rolled back
}
}
When you test application code that manipulates the state of the Hibernate
session, make sure to flush the underlying session within test methods that
execute that code. Failing to flush the underlying session can produce false
positives: your test may pass, but the same code throws an exception in a live,
production environment. In the following Hibernate-based example test case, one
method demonstrates a false positive, and the other method correctly exposes the
results of flushing the session. Note that this applies to JPA and any other ORM
frameworks that maintain an in-memory unit of work.
// ...
@Autowired
private SessionFactory sessionFactory;
@Test // no expected exception!
public void falsePositive() {
updateEntityInHibernateSession();
// False positive: an exception will be thrown once the session is
// finally flushed (i.e., in production code)
}
@Test(expected = GenericJDBCException.class)
public void updateWithSessionFlush() {
updateEntityInHibernateSession();
// Manual flush is required to avoid false positive in test
sessionFactory.getCurrentSession().flush();
}
// ...
Server-Side Tests
Before Spring Framework 3.2, the most likely way
to test a Spring MVC controller was to write a unit
Standalone project
Before inclusion in Spring
Framework 3.2, the Spring MVC
Test framework had already
existed as a separate project on
GitHub where it grew and
evolved through actual use,
feedback, and the contribution of
many.
The standalone spring-test-mvc
project is still available on GitHub
and can be used in conjunction
with Spring Framework 3.1.x.
Applications upgrading to 3.2
should replace the spring-
org.springframework.test.web
but otherwise is nearly identical
with two exceptions. One is
support for features new in 3.2
(e.g. asynchronous web
requests). The other relates to
the options for creating a
MockMvc instance. In Spring
Framework 3.2, this can only be
done through the TestContext
framework, which provides
caching benefits for the loaded
configuration.
Static Imports
The fluent API in the example above requires a few static imports such as
MockMvcRequestBuilders.*, MockMvcResultMatchers.*, and
MockMvcBuilders.*. An easy way to find these classes is to search for types matching
"MockMvc*". If using Eclipse, be sure to add them as "favorite static members" in the
Eclipse preferences under Java -> Editor -> Content Assist -> Favorites. That will allow
use of content assist after typing the first character of the static method name. Other IDEs
(e.g. IntelliJ) may not require any additional configuration. Just check the support for code
completion on static members.
Setup Options
The goal of server-side test setup is to create an instance of MockMvc that can be used to
perform requests. There are two main options.
The first option is to point to Spring MVC configuration through the TestContext framework,
which loads the Spring configuration and injects a WebApplicationContext into the
test to use to create a MockMvc:
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration("my-servlet-context.xml")
public class MyWebTests {
@Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
@Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
// ...
The second option is to simply register a controller instance without loading any Spring
configuration. Instead basic Spring MVC configuration suitable for testing annotated
controllers is automatically created. The created configuration is comparable to that of the
MVC JavaConfig (and the MVC namespace) and can be customized to a degree through
builder-style methods:
public class MyWebTests {
private MockMvc mockMvc;
@Before
public void setup() {
this.mockMvc = MockMvcBuilders.standaloneSetup(new AccountController()).build();
}
// ...
}
Then you can inject the mock service into the test in order set up and verify expectations:
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration("test-servlet-context.xml")
public class AccountTests {
@Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
@Autowired
private AccountService accountService;
// ...
}
The "standaloneSetup" on the other hand is a little closer to a unit test. It tests one
controller at a time, the controller can be injected with mock dependencies manually, and it
doesn't involve loading Spring configuration. Such tests are more focused in style and
make it easier to see which controller is being tested, whether any specific Spring MVC
configuration is required to work, and so on. The "standaloneSetup" is also a very
convenient way to write ad-hoc tests to verify some behavior or to debug an issue.
Just like with integration vs unit testing, there is no right or wrong answer. Using the
"standaloneSetup" does imply the need for some additional "webAppContextSetup" tests
to verify the Spring MVC configuration. Alternatively, you can decide write all tests with
"webAppContextSetup" and always test against actual Spring MVC configuration.
Performing Requests
To perform requests, use the appropriate HTTP method and additional builder-style
methods corresponding to properties of MockHttpServletRequest. For example:
mockMvc.perform(post("/hotels/{id}", 42).accept(MediaType.APPLICATION_JSON));
In addition to all the HTTP methods, you can also perform file upload requests, which
internally creates an instance of MockMultipartHttpServletRequest:
mockMvc.perform(fileUpload("/doc").file("a1", "ABC".getBytes("UTF-8")));
If application code relies on Servlet request parameters, and doesn't check the query
string, as is most often the case, then it doesn't matter how parameters are added. Keep in
mind though that parameters provided in the URI template will be decoded while
parameters provided through the param(...) method are expected to be decoded.
In most cases it's preferable to leave out the context path and the Servlet path from the
request URI. If you must test with the full request URI, be sure to set the contextPath
and servletPath accordingly so that request mappings will work:
mockMvc.perform(get("/app/main/hotels/{id}").contextPath("/app").servletPath("/main"))
Looking at the above example, it would be cumbersome to set the contextPath and
servletPath with every performed request. That's why you can define default request
properties when building the MockMvc:
public class MyWebTests {
private MockMvc mockMvc;
@Before
public void setup() {
mockMvc = standaloneSetup(new AccountController())
.defaultRequest(get("/")
.contextPath("/app").servletPath("/main")
.accept(MediaType.APPLICATION_JSON).build();
}
}
The above properties will apply to every request performed through the MockMvc. If the
same property is also specified on a given request, it will override the default value. That is
why, the HTTP method and URI don't matter, when setting default request properties, since
they must be specified on every request.
Defining Expectations
Expectations can be defined by appending one or more .andExpect(..) after call to
perform the request:
mockMvc.perform(get("/accounts/1")).andExpect(status().isOk());
binding/validation failed:
mockMvc.perform(post("/persons"))
.andExpect(status().isOk())
.andExpect(model().attributeHasErrors("person"));
Many times when writing tests, it's useful to dump the result of the performed request. This
can be done as follows, where print() is a static import from
MockMvcResultHandlers:
mockMvc.perform(post("/persons"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(model().attributeHasErrors("person"));
As long as request processing causes an unhandled exception, the print() method will
print all the available result data to System.out.
In some cases, you may want to get direct access to the result and verify something that
cannot be verified otherwise. This can be done by appending .andReturn() at the end
after all expectations:
MvcResult mvcResult = mockMvc.perform(post("/persons")).andExpect(status().isOk()).andReturn();
// ...
When all tests repeat the same expectations, you can define the common expectations
once when building the MockMvc:
standaloneSetup(new SimpleController())
.alwaysExpect(status().isOk())
.alwaysExpect(content().contentType("application/json;charset=UTF-8"))
.build()
Note that the expectation is always applied and cannot be overridden without creating a
separate MockMvc instance.
When JSON response content contains hypermedia links created with Spring HATEOAS,
the resulting links can be verified:
mockMvc.perform(get("/people").accept(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$.links[?(@.rel == 'self')].href").value("http://localhost:8080/people"));
When XML response content contains hypermedia links created with Spring HATEOAS,
the resulting links can be verified:
Map<String, String> ns = Collections.singletonMap("ns", "http://www.w3.org/2005/Atom");
mockMvc.perform(get("/handle").accept(MediaType.APPLICATION_XML))
.andExpect(xpath("/person/ns:link[@rel='self']/@href", ns).string("http://localhost:8080/people"));
Filter Registrations
When setting up a MockMvc, you can register one or more Filter instances:
mockMvc = standaloneSetup(new PersonController()).addFilters(new CharacterEncodingFilter()).build();
Client-side tests are for code using the RestTemplate. The goal is to define expected
requests and provide "stub" responses:
RestTemplate restTemplate = new RestTemplate();
MockRestServiceServer mockServer = MockRestServiceServer.createServer(restTemplate);
mockServer.expect(requestTo("/greeting")).andRespond(withSuccess("Hello world", "text/plain"));
// use RestTemplate ...
mockServer.verify();
Static Imports
Just like with server-side tests, the fluent API for client-side tests requires a few static
imports. Those are easy to find by searching "MockRest*". Eclipse users should add
"MockRestRequestMatchers.*" and "MockRestResponseCreators.*" as
"favorite static members" in the Eclipse preferences under Java -> Editor -> Content Assist
-> Favorites. That allows using content assist after typing the first character of the static
method name. Other IDEs (e.g. IntelliJ) may not require any additional configuration. Just
check the support for code completion on static members.
Notes:
This test case extends the
In a large-scale application, the Spring configuration is often split across multiple files.
Consequently, configuration locations are typically specified in a common base class for
all application-specific integration tests. Such a base class may also add useful instance
variables populated by Dependency Injection, naturally such as a
SessionFactory in the case of an application using Hibernate.
As far as possible, you should have exactly the same Spring configuration files in your
integration tests as in the deployed environment. One likely point of difference concerns
database connection pooling and transaction infrastructure. If you are deploying to a fullblown application server, you will probably use its connection pool (available through
JNDI) and JTA implementation. Thus in production you will use a
JndiObjectFactoryBean or <jee:jndi-lookup> for the DataSource and
JtaTransactionManager. JNDI and JTA will not be available in out-of-container
integration tests, so you should use a combination like the Commons DBCP
BasicDataSource and DataSourceTransactionManager or
HibernateTransactionManager for them. You can factor out this variant behavior
into a single XML file, having the choice between application server and a 'local'
configuration separated from all other configuration, which will not vary between the test
and production environments. In addition, it is advisable to use properties files for
connection settings. See the PetClinic application for an example.
Advantages of the Spring Framework's transaction support model describes why you
would use the Spring Framework's transaction abstraction instead of EJB ContainerManaged Transactions (CMT) or choosing to drive local transactions through a
proprietary API such as Hibernate.
Understanding the Spring Framework transaction abstraction outlines the core classes
and describes how to configure and obtain DataSource instances from a variety of
sources.
Synchronizing resources with transactions describes how the application code
ensures that resources are created, reused, and cleaned up properly.
Declarative transaction management describes support for declarative transaction
management.
Programmatic transaction management covers support for programmatic (that is,
explicitly coded) transaction management.
code once, and it can benefit from different transaction management strategies in different
environments. The Spring Framework provides both declarative and programmatic
transaction management. Most users prefer declarative transaction management, which is
recommended in most cases.
With programmatic transaction management, developers work with the Spring Framework
transaction abstraction, which can run over any underlying transaction infrastructure. With
the preferred declarative model, developers typically write little or no code related to
transaction management, and hence do not depend on the Spring Framework transaction
API, or any other transaction API.
discuss transaction isolation levels and other core transaction concepts. Understanding
these concepts is essential to using the Spring Framework or any transaction management
solution.
The TransactionStatus interface provides a simple way for transactional code to
control transaction execution and query transaction status. The concepts should be
familiar, as they are common to all transaction APIs:
public interface TransactionStatus extends SavepointManager {
boolean isNewTransaction();
boolean hasSavepoint();
void setRollbackOnly();
boolean isRollbackOnly();
void flush();
boolean isCompleted();
}
If you use JTA in a Java EE container then you use a container DataSource, obtained
through JNDI, in conjunction with Spring's JtaTransactionManager. This is what the
JTA and JNDI lookup version would look like:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee.xsd">
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/jpetstore"/>
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager" />
<!-- other <bean/> definitions here -->
</beans>
The JtaTransactionManager does not need to know about the DataSource, or any
other specific resources, because it uses the container's global transaction management
infrastructure.
Note
The above definition of the dataSource bean uses the <jndilookup/> tag from the jee namespace. For more information on
schema-based configuration, see Appendix E, XML Schema-based
configuration, and for more information on the <jee/> tags see the
section entitled Section E.2.3, The jee schema.
You can also use Hibernate local transactions easily, as shown in the following examples.
In this case, you need to define a Hibernate LocalSessionFactoryBean, which your
application code will use to obtain Hibernate Session instances.
The DataSource bean definition will be similar to the local JDBC example shown
previously and thus is not shown in the following example.
Note
If the DataSource, used by any non-JTA transaction manager, is
looked up via JNDI and managed by a Java EE container, then it
should be non-transactional because the Spring Framework, rather
than the Java EE container, will manage the transactions.
The txManager bean in this case is of the HibernateTransactionManager type. In
the same way as the DataSourceTransactionManager needs a reference to the
DataSource, the HibernateTransactionManager needs a reference to the
SessionFactory.
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mappingResources">
<list>
<value>org/springframework/samples/petclinic/hibernate/petclinic.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=${hibernate.dialect}
</value>
</property>
</bean>
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
If you are using Hibernate and Java EE container-managed JTA transactions, then you
should simply use the same JtaTransactionManager as in the previous JTA example
for JDBC.
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
Note
If you use JTA , then your transaction manager definition will look the
same regardless of what data access technology you use, be it JDBC,
Hibernate JPA or any other supported technology. This is due to the
fact that JTA transactions are global transactions, which can enlist any
transactional resource.
In all these cases, application code does not need to change. You can change how
transactions are managed merely by changing configuration, even if that change means
moving from local to global transactions or vice versa.
It should now be clear how you create different transaction managers, and how they are
linked to related resources that need to be synchronized to transactions (for example
DataSourceTransactionManager to a JDBC DataSource,
HibernateTransactionManager to a Hibernate SessionFactory, and so forth).
This section describes how the application code, directly or indirectly using a persistence
API such as JDBC, Hibernate, or JDO, ensures that these resources are created, reused,
and cleaned up properly. The section also discusses how transaction synchronization is
triggered (optionally) through the relevant PlatformTransactionManager.
If an existing transaction already has a connection synchronized (linked) to it, that instance
is returned. Otherwise, the method call triggers the creation of a new connection, which is
(optionally) synchronized to any existing transaction, and made available for subsequent
reuse in that same transaction. As mentioned, any SQLException is wrapped in a Spring
Framework CannotGetJdbcConnectionException, one of the Spring Framework's
hierarchy of unchecked DataAccessExceptions. This approach gives you more information
than can be obtained easily from the SQLException, and ensures portability across
databases, even across different persistence technologies.
This approach also works without Spring transaction management (transaction
synchronization is optional), so you can use it whether or not you are using Spring for
transaction management.
Of course, once you have used Spring's JDBC support, JPA support or Hibernate support,
you will generally prefer not to use DataSourceUtils or the other helper classes,
because you will be much happier working through the Spring abstraction than directly
with the relevant APIs. For example, if you use the Spring JdbcTemplate or
jdbc.object package to simplify your use of JDBC, correct connection retrieval occurs
behind the scenes and you won't need to write any special code.
12.4.3 TransactionAwareDataSourceProxy
At the very lowest level exists the TransactionAwareDataSourceProxy class. This
is a proxy for a target DataSource, which wraps the target DataSource to add
awareness of Spring-managed transactions. In this respect, it is similar to a transactional
JNDI DataSource as provided by a Java EE server.
It should almost never be necessary or desirable to use this class, except when existing
code must be called and passed a standard JDBC DataSource interface
implementation. In that case, it is possible that this code is usable, but participating in
Spring managed transactions. It is preferable to write your new code by using the higher
level abstractions mentioned above.
Where is
TransactionProxyFactoryBean?
Declarative transaction
configuration in versions of
Spring 2.0 and above differs
considerably from previous
versions of Spring. The main
difference is that there is no
longer any need to configure
TransactionProxyFactoryBean
beans.
The pre-Spring 2.0 configuration
style is still 100% valid
TransactionProxyFactoryBean
beans on your behalf.
UnsupportedOperationException instance.
// the service interface that we want to make transactional
package x.y.service;
public interface FooService {
Foo getFoo(String fooName);
Foo getFoo(String fooName, String barName);
void insertFoo(Foo foo);
void updateFoo(Foo foo);
}
// an implementation of the above interface
package x.y.service;
public class DefaultFooService implements FooService {
public Foo getFoo(String fooName) {
throw new UnsupportedOperationException();
}
public Foo getFoo(String fooName, String barName) {
throw new UnsupportedOperationException();
}
public void insertFoo(Foo foo) {
throw new UnsupportedOperationException();
}
public void updateFoo(Foo foo) {
throw new UnsupportedOperationException();
}
}
Assume that the first two methods of the FooService interface, getFoo(String) and
getFoo(String, String), must execute in the context of a transaction with readonly semantics, and that the other methods,insertFoo(Foo) and updateFoo(Foo),
must execute in the context of a transaction with read-write semantics. The following
configuration is explained in detail in the next few paragraphs.
<!-- from the file 'context.xml' -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- this is the service object that we want to make transactional -->
<bean id="fooService" class="x.y.service.DefaultFooService"/>
<!-- the transactional advice (what 'happens'; see the <aop:advisor/> bean below) -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<!-- the transactional semantics... -->
<tx:attributes>
<!-- all methods starting with 'get' are read-only -->
<tx:method name="get*" read-only="true"/>
<!-- other methods use the default transaction settings (see below) -->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- ensure that the above transactional advice runs for any execution
of an operation defined by the FooService interface -->
<aop:config>
<aop:pointcut id="fooServiceOperation" expression="execution(* x.y.service.FooService.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/>
</aop:config>
<!-- don't forget the DataSource -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/>
<property name="username" value="scott"/>
Examine the preceding configuration. You want to make a service object, the
fooService bean, transactional. The transaction semantics to apply are encapsulated in
the <tx:advice/> definition. The <tx:advice/> definition reads as ... all methods on
starting with 'get' are to execute in the context of a read-only transaction, and all other
methods are to execute with the default transaction semantics. The transactionmanager attribute of the <tx:advice/> tag is set to the name of the
PlatformTransactionManager bean that is going to drive the transactions, in this
case, the txManager bean.
Tip
You can omit the transaction-manager attribute in the
transactional advice (<tx:advice/>) if the bean name of the
PlatformTransactionManager that you want to wire in has the
name transactionManager. If the
PlatformTransactionManager bean that you want to wire in has
any other name, then you must use the transaction-manager
attribute explicitly, as in the preceding example.
The <aop:config/> definition ensures that the transactional advice defined by the
txAdvice bean executes at the appropriate points in the program. First you define a
pointcut that matches the execution of any operation defined in the FooService interface
(fooServiceOperation). Then you associate the pointcut with the txAdvice using
an advisor. The result indicates that at the execution of a fooServiceOperation, the
advice defined by txAdvice will be run.
The expression defined within the <aop:pointcut/> element is an AspectJ pointcut
expression; see Chapter 9, Aspect Oriented Programming with Spring for more details on
pointcut expressions in Spring 2.0.
A common requirement is to make an entire service layer transactional. The best way to do
this is simply to change the pointcut expression to match any operation in your service
layer. For example:
<aop:config>
<aop:pointcut id="fooServiceMethods" expression="execution(* x.y.service.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceMethods"/>
</aop:config>
Note
In this example it is assumed that all your service interfaces are defined
in the x.y.service package; see Chapter 9, Aspect Oriented
Programming with Spring for more details.
Now that we've analyzed the configuration, you may be asking yourself, Okay... but what
does all this configuration actually do?.
The above configuration will be used to create a transactional proxy around the object that
is created from the fooService bean definition. The proxy will be configured with the
transactional advice, so that when an appropriate method is invoked on the proxy, a
transaction is started, suspended, marked as read-only, and so on, depending on the
transaction configuration associated with that method. Consider the following program that
The output from running the preceding program will resemble the following. (The Log4J
output and the stack trace from the UnsupportedOperationException thrown by the
insertFoo(..) method of the DefaultFooService class have been truncated for clarity.)
<!-- the Spring container is starting up... -->
[AspectJInvocationContextExposingAdvisorAutoProxyCreator] - Creating implicit proxy
for bean 'fooService' with 0 common interceptors and 1 specific interceptors
<!-- the DefaultFooService is actually proxied -->
[JdkDynamicAopProxy] - Creating JDK dynamic proxy for [x.y.service.DefaultFooService]
<!-- ... the insertFoo(..) method is now being invoked on the proxy -->
[TransactionInterceptor] - Getting transaction for x.y.service.FooService.insertFoo
<!-- the transactional advice kicks in here... -->
[DataSourceTransactionManager] - Creating new transaction with name [x.y.service.FooService.insertFoo]
[DataSourceTransactionManager] - Acquired Connection
[org.apache.commons.dbcp.PoolableConnection@a53de4] for JDBC transaction
<!-- the insertFoo(..) method from DefaultFooService throws an exception... -->
[RuleBasedTransactionAttribute] - Applying rules to determine whether transaction should
rollback on java.lang.UnsupportedOperationException
[TransactionInterceptor] - Invoking rollback for transaction on x.y.service.FooService.insertFoo
due to throwable [java.lang.UnsupportedOperationException]
<!-- and the transaction is rolled back (by default, RuntimeException instances cause rollback) -->
[DataSourceTransactionManager] - Rolling back JDBC transaction on Connection
[org.apache.commons.dbcp.PoolableConnection@a53de4]
[DataSourceTransactionManager] - Releasing JDBC Connection after transaction
[DataSourceUtils] - Returning JDBC Connection to DataSource
Exception in thread "main" java.lang.UnsupportedOperationException
at x.y.service.DefaultFooService.insertFoo(DefaultFooService.java:14)
<!-- AOP infrastructure stack trace elements removed for clarity -->
at $Proxy0.insertFoo(Unknown Source)
at Boot.main(Boot.java:11)
You can also specify 'no rollback rules', if you do not want a transaction rolled back when
an exception is thrown. The following example tells the Spring Framework's transaction
infrastructure to commit the attendant transaction even in the face of an unhandled
InstrumentNotFoundException.
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="updateStock" no-rollback-for="InstrumentNotFoundException"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
You can also indicate a required rollback programmatically. Although very simple, this
process is quite invasive, and tightly couples your code to the Spring Framework's
transaction infrastructure:
public void resolvePosition() {
try {
// some business logic...
} catch (NoProductInStockException ex) {
// trigger rollback programmatically
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
You are strongly encouraged to use the declarative approach to rollback if at all possible.
Programmatic rollback is available should you absolutely need it, but its usage flies in the
face of achieving a clean POJO-based architecture.
The following example shows how to configure two distinct beans with totally different
transactional settings.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<aop:config>
<aop:pointcut id="defaultServiceOperation"
expression="execution(* x.y.service.*Service.*(..))"/>
<aop:pointcut id="noTxServiceOperation"
expression="execution(* x.y.service.ddl.DefaultDdlManager.*(..))"/>
<aop:advisor pointcut-ref="defaultServiceOperation" advice-ref="defaultTxAdvice"/>
<aop:advisor pointcut-ref="noTxServiceOperation" advice-ref="noTxAdvice"/>
</aop:config>
<!-- this bean will be transactional (see the 'defaultServiceOperation' pointcut) -->
<bean id="fooService" class="x.y.service.DefaultFooService"/>
<!-- this bean will also be transactional, but with totally different transactional settings -->
<bean id="anotherFooService" class="x.y.service.ddl.DefaultDdlManager"/>
<tx:advice id="defaultTxAdvice">
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<tx:advice id="noTxAdvice">
<tx:attributes>
<tx:method name="*" propagation="NEVER"/>
</tx:attributes>
</tx:advice>
<!-- other transaction infrastructure beans such as a PlatformTransactionManager omitted... -->
</beans>
name
Required?
Default
Yes
propagation No
Description
isolation
No
DEFAULT
timeout
No
-1
read-only
No
false
rollbackfor
No
norollbackfor
No
When the above POJO is defined as a bean in a Spring IoC container, the bean instance
can be made transactional by adding merely one line of XML configuration:
<!-- from the file 'context.xml' -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- this is the service object that we want to make transactional -->
<bean id="fooService" class="x.y.service.DefaultFooService"/>
<!-- enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="txManager"/>
<!-- a PlatformTransactionManager is still required -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- (this dependency is defined somewhere else) -->
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- other <bean/> definitions here -->
</beans>
Tip
You can omit the transaction-manager attribute in the
<tx:annotation-driven/> tag if the bean name of the
PlatformTransactionManager that you want to wire in has the
name transactionManager. If the
PlatformTransactionManager bean that you want to
dependency-inject has any other name, then you have to use the
transaction-manager attribute explicitly, as in the preceding
example.
Note
The @EnableTransactionManagement annotation provides
equivalent support if you are using Java based configuration. Simply
add the annotation to a @Configuration class. See Javadoc for full
details.
You can place the @Transactional annotation
before an interface definition, a method on an
@Transactional
@Transactional
means that if you are using classbased proxies (proxy-targetclass="true") or the weavingbased aspect
(mode="aspectj"), then the
transaction settings are not
recognized by the proxying and
weaving infrastructure, and the
object will not be wrapped in a
transactional proxy, which would
be decidedly bad.
Note
In proxy mode (which is the default), only external method calls coming
in through the proxy are intercepted. This means that self-invocation, in
effect, a method within the target object calling another method of the
target object, will not lead to an actual transaction at runtime even if the
invoked method is marked with @Transactional.
Consider the use of AspectJ mode (see mode attribute in table below) if you expect selfinvocations to be wrapped with transactions as well. In this case, there will not be a proxy
in the first place; instead, the target class will be weaved (that is, its byte code will be
modified) in order to turn @Transactional into runtime behavior on any kind of method.
Annotation Attribute
Default
mode
mode
proxy
Description
Name of transaction
manager to use. Only
required if the name of the
transaction manager is
not
transactionManager,
as in the example above.
The default mode "proxy"
processes annotated
beans to be proxied using
Spring's AOP framework
(following proxy
semantics, as discussed
above, applying to
method calls coming in
through the proxy only).
The alternative mode
"aspectj" instead weaves
the affected classes with
Spring's AspectJ
transaction aspect,
modifying the target class
byte code to apply to any
kind of method call.
AspectJ weaving requires
spring-aspects.jar in the
classpath as well as loadtime weaving (or compiletime weaving) enabled.
(See the section called
Spring configuration for
details on how to set up
load-time weaving.)
Applies to proxy mode
only. Controls what type
of transactional proxies
are created for classes
proxyproxyTargetClass
target-class
false
order
order
Note
The proxy-target-class attribute controls what type of
transactional proxies are created for classes annotated with the
@Transactional annotation. If proxy-target-class is set to
true, class-based proxies are created. If proxy-target-class is
false or if the attribute is omitted, standard JDK interface-based
proxies are created. (See Section 9.6, Proxying mechanisms for a
discussion of the different proxy types.)
Note
@EnableTransactionManagement and <tx:annotationdriven/> only looks for @Transactional on beans in the same
application context they are defined in. This means that, if you put
annotation driven configuration in a WebApplicationContext for a
DispatcherServlet, it only checks for @Transactional beans
in your controllers, and not your services. See Section 17.2, The
DispatcherServlet for more information.
The most derived location takes precedence when evaluating the transactional settings for
a method. In the case of the following example, the DefaultFooService class is
annotated at the class level with the settings for a read-only transaction, but the
@Transactional annotation on the updateFoo(Foo) method in the same class takes
precedence over the transactional settings defined at the class level.
@Transactional(readOnly = true)
public class DefaultFooService implements FooService {
public Foo getFoo(String fooName) {
// do something
}
// these settings have precedence for this method
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void updateFoo(Foo foo) {
// do something
}
}
@Transactional settings
The @Transactional annotation is metadata that specifies that an interface, class, or
method must have transactional semantics; for example, start a brand new read-only
transaction when this method is invoked, suspending any existing transaction. The default
@Transactional settings are as follows:
Propagation setting is PROPAGATION_REQUIRED.
Isolation level is ISOLATION_DEFAULT.
Transaction is read/write.
Transaction timeout defaults to the default timeout of the underlying transaction
system, or to none if timeouts are not supported.
Any RuntimeException triggers rollback, and any checked Exception does not.
These default settings can be changed; the various properties of the @Transactional
annotation are summarized in the following table:
Type
Description
value
String
Optional qualifier
specifying the
transaction manager to
be used.
propagation
enum: Propagation
Optional propagation
setting.
isolation
enum: Isolation
Optional isolation
level.
readOnly
boolean
timeout
Transaction timeout.
rollbackFor
Array of Class
Optional array of
objects, which must be
exception classes that
derived from
must cause rollback.
Throwable.
rollbackForClassName
Optional array of
names of exception
classes that must
cause rollback.
noRollbackFor
Array of Class
objects, which must be
derived from
Throwable.
Optional array of
exception classes that
must not cause
rollback.
Optional array of
names of exception
classes that must not
cause rollback.
Currently you cannot have explicit control over the name of a transaction, where 'name'
means the transaction name that will be shown in a transaction monitor, if applicable (for
example, WebLogic's transaction monitor), and in logging output. For declarative
transactions, the transaction name is always the fully-qualified class name + "." + method
name of the transactionally-advised class. For example, if the handlePayment(..)
method of the BusinessService class started a transaction, the name of the transaction
would be: com.foo.BusinessService.handlePayment.
could be combined with the following transaction manager bean declarations in the
application context.
<tx:annotation-driven/>
<bean id="transactionManager1" class="org.springframework.jdbc.DataSourceTransactionManager">
...
<qualifier value="order"/>
</bean>
<bean id="transactionManager2" class="org.springframework.jdbc.DataSourceTransactionManager">
...
<qualifier value="account"/>
</bean>
In this case, the two methods on TransactionalService will run under separate
transaction managers, differentiated by the "order" and "account" qualifiers. The default
<tx:annotation-driven> target bean name transactionManager will still be
used if no specifically qualified PlatformTransactionManager bean is found.
Here we have used the syntax to define the transaction manager qualifier, but could also
have included propagation behavior, rollback rules, timeouts etc.
Required
PROPAGATION_REQUIRED
When the propagation setting is PROPAGATION_REQUIRED, a logical transaction scope
is created for each method upon which the setting is applied. Each such logical transaction
scope can determine rollback-only status individually, with an outer transaction scope
being logically independent from the inner transaction scope. Of course, in case of
standard PROPAGATION_REQUIRED behavior, all these scopes will be mapped to the
same physical transaction. So a rollback-only marker set in the inner transaction scope
does affect the outer transaction's chance to actually commit (as you would expect it to).
However, in the case where an inner transaction scope sets the rollback-only marker, the
outer transaction has not decided on the rollback itself, and so the rollback (silently
triggered by the inner transaction scope) is unexpected. A corresponding
UnexpectedRollbackException is thrown at that point. This is expected behavior so
that the caller of a transaction can never be misled to assume that a commit was performed
when it really was not. So if an inner transaction (of which the outer caller is not aware)
silently marks a transaction as rollback-only, the outer caller still calls commit. The outer
caller needs to receive an UnexpectedRollbackException to indicate clearly that a
rollback was performed instead.
RequiresNew
PROPAGATION_REQUIRES_NEW
Nested
PROPAGATION_NESTED uses a single physical transaction with multiple savepoints that it
can roll back to. Such partial rollbacks allow an inner transaction scope to trigger a rollback
for its scope, with the outer transaction being able to continue the physical transaction
despite some operations having been rolled back. This setting is typically mapped onto
JDBC savepoints, so will only work with JDBC resource transactions. See Spring's
DataSourceTransactionManager.
The result of the above configuration is a fooService bean that has profiling and
transactional aspects applied to it in the desired order. You configure any number of
additional aspects in similar fashion.
The following example effects the same setup as above, but uses the purely XML
declarative approach.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="fooService" class="x.y.service.DefaultFooService"/>
<!-- the profiling advice -->
<bean id="profiler" class="x.y.SimpleProfiler">
<!-- execute before the transactional advice (hence the lower order number) -->
<property name="order" value="1"/>
</bean>
<aop:config>
<aop:pointcut id="entryPointMethod" expression="execution(* x.y..*Service.*(..))"/>
<!-- will execute after the profiling advice (c.f. the order attribute) -->
<aop:advisor
advice-ref="txAdvice"
pointcut-ref="entryPointMethod"
order="2"/> <!-- order value is higher than the profiling aspect -->
<aop:aspect id="profilingAspect" ref="profiler">
<aop:pointcut id="serviceMethodWithReturnValue"
expression="execution(!void x.y..*Service.*(..))"/>
<aop:around method="profile" pointcut-ref="serviceMethodWithReturnValue"/>
</aop:aspect>
</aop:config>
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- other <bean/> definitions such as a DataSource and a PlatformTransactionManager here -->
</beans>
The result of the above configuration will be a fooService bean that has profiling and
transactional aspects applied to it in that order. If you want the profiling advice to execute
after the transactional advice on the way in, and before the transactional advice on the way
out, then you simply swap the value of the profiling aspect bean's order property so that it
is higher than the transactional advice's order value.
You configure additional aspects in similar fashion.
Note
When using this aspect, you must annotate the implementation class
(and/or methods within that class), not the interface (if any) that the
class implements. AspectJ follows Java's rule that annotations on
interfaces are not inherited.
The @Transactional annotation on a class specifies the default transaction semantics
for the execution of any method in the class.
The @Transactional annotation on a method within the class overrides the default
transaction semantics given by the class annotation (if present). Any method may be
annotated, regardless of visibility.
To weave your applications with the AnnotationTransactionAspect you must either
build your application with AspectJ (see the AspectJ Development Guide) or use load-time
weaving. See Section 9.8.4, Load-time weaving with AspectJ in the Spring Framework
for a discussion of load-time weaving with AspectJ.
Code within the callback can roll the transaction back by calling the
setRollbackOnly() method on the supplied TransactionStatus object:
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
try {
updateOperation1();
updateOperation2();
} catch (SomeBusinessExeption ex) {
status.setRollbackOnly();
}
}
});
txManager.rollback(status);
throw ex;
}
txManager.commit(status);
If you are using the classic Hibernate APIs than you can inject the SessionFactory:
@Repository
public class HibernateMovieFinder implements MovieFinder {
private SessionFactory sessionFactory;
@Autowired
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
// ...
}
Last example we will show here is for typical JDBC support. You would have the
DataSource injected into an initialization method where you would create a
JdbcTemplate and other data access support classes like SimpleJdbcCall etc using
this DataSource.
@Repository
public class JdbcMovieFinder implements MovieFinder {
private JdbcTemplate jdbcTemplate;
@Autowired
public void init(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
// ...
}
Note
Please see the specific coverage of each persistence technology for
details on how to configure the application context to take advantage of
these annotations.
Spring
You
X
X
Handle transactions.
The Spring Framework takes care of all the low-level details that can make JDBC such a
tedious API to develop with.
Note
The DataSource should always be configured as a bean in the
Spring IoC container. In the first case the bean is given to the service
directly; in the second case it is given to the prepared template.
All SQL issued by this class is logged at the DEBUG level under the category
corresponding to the fully qualified class name of the template instance (typically
JdbcTemplate, but it may be different if you are using a custom subclass of the
JdbcTemplate class).
Querying (SELECT)
Here is a simple query for getting the number of rows in a relation:
int rowCount = this.jdbcTemplate.queryForObject("select count(*) from t_actor", int.class);
If the last two snippets of code actually existed in the same application, it would make
sense to remove the duplication present in the two RowMapper anonymous inner classes,
and extract them out into a single class (typically a static inner class) that can then be
referenced by DAO methods as needed. For example, it may be better to write the last
code snippet as follows:
public List<Actor> findAllActors() {
return this.jdbcTemplate.query( "select first_name, last_name from t_actor", new ActorMapper());
}
private static final class ActorMapper implements RowMapper<Actor> {
public Actor mapRow(ResultSet rs, int rowNum) throws SQLException {
Actor actor = new Actor();
actor.setFirstName(rs.getString("first_name"));
actor.setLastName(rs.getString("last_name"));
return actor;
}
}
The following example invokes a simple stored procedure. More sophisticated stored
procedure support is covered later.
this.jdbcTemplate.update(
"call SUPPORT.REFRESH_ACTORS_SUMMARY(?)",
Long.valueOf(unionId));
The corresponding XML configuration file would look like the following:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- Scans within the base package of the application for @Components to configure as beans -->
<context:component-scan base-package="org.springframework.docs.test" />
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<context:property-placeholder location="jdbc.properties"/>
</beans>
If you are using Spring's JdbcDaoSupport class, and your various JDBC-backed DAO
classes extend from it, then your sub-class inherits a setDataSource(..) method from
the JdbcDaoSupport class. You can choose whether to inherit from this class. The
JdbcDaoSupport class is provided as a convenience only.
Regardless of which of the above template initialization styles you choose to use (or not), it
is seldom necessary to create a new instance of a JdbcTemplate class each time you
want to execute SQL. Once configured, a JdbcTemplate instance is threadsafe. You
may want multiple JdbcTemplate instances if your application accesses multiple
databases, which requires multiple DataSources, and subsequently multiple differently
configured JdbcTemplates.
14.2.2 NamedParameterJdbcTemplate
The NamedParameterJdbcTemplate class adds support for programming JDBC
statements using named parameters, as opposed to programming JDBC statements using
only classic placeholder ('?') arguments. The NamedParameterJdbcTemplate class
wraps a JdbcTemplate, and delegates to the wrapped JdbcTemplate to do much of
its work. This section describes only those areas of the
NamedParameterJdbcTemplate class that differ from the JdbcTemplate itself;
namely, programming JDBC statements using named parameters.
// some JDBC-backed DAO class...
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
}
public int countOfActorsByFirstName(String firstName) {
String sql = "select count(*) from T_ACTOR where first_name = :first_name";
SqlParameterSource namedParameters = new MapSqlParameterSource("first_name", firstName);
return this.namedParameterJdbcTemplate.queryForObject(sql, int.class, namedParameters);
}
Notice the use of the named parameter notation in the value assigned to the sql variable,
and the corresponding value that is plugged into the namedParameters variable (of type
MapSqlParameterSource).
Alternatively, you can pass along named parameters and their corresponding values to a
NamedParameterJdbcTemplate instance by using the Map-based style.The
remaining methods exposed by the NamedParameterJdbcOperations and
implemented by the NamedParameterJdbcTemplate class follow a similar pattern and
are not covered here.
The following example shows the use of the Map-based style.
// some JDBC-backed DAO class...
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
}
public int countOfActorsByFirstName(String firstName) {
String sql = "select count(*) from T_ACTOR where first_name = :first_name";
Map<String, String> namedParameters = Collections.singletonMap("first_name", firstName);
return this.namedParameterJdbcTemplate.queryForObject(sql, int.class, namedParameters);
}
14.2.3 SQLExceptionTranslator
SQLExceptionTranslator is an interface to be implemented by classes that can
translate between SQLExceptions and Spring's own
org.springframework.dao.DataAccessException, which is agnostic in regard
to data access strategy. 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. It is more precise than the SQLState implementation. The error code
translations are based on codes held in a JavaBean type class called 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 actual database you are using are used.
The SQLErrorCodeSQLExceptionTranslator applies matching rules in the
following sequence:
Note
The SQLErrorCodesFactory is used by default to define Error
codes and custom exception translations. They are looked up in a file
named sql-error-codes.xml from the classpath and the matching
SQLErrorCodes instance is located based on the database name
from the database metadata of the database in use.
1. Any custom translation implemented by a subclass. Normally the provided concrete
SQLErrorCodeSQLExceptionTranslator is used so this rule does not apply. It
only applies if you have actually provided a subclass implementation.
2. Any custom implementation of the SQLExceptionTranslator interface that is
provided as the customSqlExceptionTranslator property of the
SQLErrorCodes class.
3. The list of instances of the CustomSQLErrorCodesTranslation class, provided
for the customTranslations property of the SQLErrorCodes class, are searched
for a match.
4. Error code matching is applied.
5. Use the fallback translator. SQLExceptionSubclassTranslator is the default
fallback translator. If this translation is not available then the next fallback translator is
the SQLStateSQLExceptionTranslator.
You can extend SQLErrorCodeSQLExceptionTranslator:
public class CustomSQLErrorCodesTranslator 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 other errors are left to be
translated by the default translator implementation. To use this custom translator, it is
necessary to pass it to the JdbcTemplate through 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:
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
// create a JdbcTemplate and set data source
this.jdbcTemplate = new JdbcTemplate();
this.jdbcTemplate.setDataSource(dataSource);
// create a custom translator and set the DataSource for the default translation lookup
CustomSQLErrorCodesTranslator tr = new CustomSQLErrorCodesTranslator();
tr.setDataSource(dataSource);
this.jdbcTemplate.setExceptionTranslator(tr);
}
public void updateShippingCharge(long orderId, long pct) {
// use the prepared JdbcTemplate for this update
this.jdbcTemplate.update(
"update orders" +
" set shipping_charge = shipping_charge * ? / 100" +
" where id = ?"
pct, orderId);
}
The custom translator is passed a data source in order to look up the error codes in sqlerror-codes.xml.
JdbcTemplate. The following example shows what you need to include for a minimal
but fully functional class that creates a new table:
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;
public class ExecuteAStatement {
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
public void doExecute() {
this.jdbcTemplate.execute("create table mytable (id integer, name varchar(100))");
}
}
In addition to the single result query methods, several methods return a list with an entry for
each row that the query returned. The most generic method is queryForList(..)
which returns a List where each entry is a Map with each entry in the map representing
the column value for that row. If you add a method to the above example to retrieve a list of
all the rows, it would look like this:
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
public List<Map<String, Object>> getList() {
return this.jdbcTemplate.queryForList("select * from mytable");
}
The following examples show the basic connectivity and configuration for DBCP and
C3P0. To learn about more options that help control the pooling features, see the product
documentation for the respective connection pooling implementations.
DBCP configuration:
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<context:property-placeholder location="jdbc.properties"/>
C3P0 configuration:
<bean id="dataSource"
class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driverClassName}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<context:property-placeholder location="jdbc.properties"/>
14.3.2 DataSourceUtils
The DataSourceUtils class is a convenient and powerful helper class that provides
static methods to obtain connections from JNDI and close connections if necessary. It
supports thread-bound connections with, for example,
DataSourceTransactionManager.
14.3.3 SmartDataSource
The SmartDataSource interface should be implemented by classes that can provide a
connection to a relational database. It extends the DataSource interface to allow classes
using it to query whether the connection should be closed after a given operation. This
usage is efficient when you know that you will reuse a connection.
14.3.4 AbstractDataSource
AbstractDataSource is an abstract base class for Spring's DataSource
implementations that implements code that is common to all DataSource
implementations. You extend the AbstractDataSource class if you are writing your
own DataSource implementation.
14.3.5 SingleConnectionDataSource
The SingleConnectionDataSource class is an implementation of the
SmartDataSource interface that wraps a single Connection that is not closed after
each use. Obviously, this is not multi-threading capable.
If any client code calls close in the assumption of a pooled connection, as when using
persistence tools, set the suppressClose property to true. This setting returns a closesuppressing proxy wrapping 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.
14.3.6 DriverManagerDataSource
The DriverManagerDataSource class is an implementation of the standard
DataSource interface that configures a plain JDBC driver through bean properties, and
returns a new Connection every time.
This implementation is useful for test and stand-alone environments outside of a Java EE
container, either as a DataSource bean in a Spring IoC container, 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.
However, using JavaBean-style connection pools such as commons-dbcp is so easy,
even in a test environment, that it is almost always preferable to use such a connection
pool over DriverManagerDataSource.
14.3.7 TransactionAwareDataSourceProxy
TransactionAwareDataSourceProxy is a proxy for a target DataSource, which
wraps that target DataSource to add awareness of Spring-managed transactions. In this
respect, it is similar to a transactional JNDI DataSource as provided by a Java EE
server.
Note
It is rarely desirable to use this class, except when already existing
code that must be called and passed a standard JDBC DataSource
interface implementation. In this case, it's possible to still have this
code be usable, and at the same time have this code participating in
Spring managed transactions. It is generally preferable to write your
own new code using the higher level abstractions for resource
management, such as JdbcTemplate or DataSourceUtils.
(See the TransactionAwareDataSourceProxy Javadocs for more details.)
14.3.8 DataSourceTransactionManager
The DataSourceTransactionManager class is a
PlatformTransactionManager implementation for single JDBC datasources. It binds
a JDBC connection from the specified data source to the currently executing thread,
14.3.9 NativeJdbcExtractor
Sometimes you need to access vendor specific JDBC methods that differ from the standard
JDBC API. This can be problematic if you are running in an application server or with a
DataSource that wraps the Connection, Statement and ResultSet objects with its
own wrapper objects. To gain access to the native objects you can configure your
JdbcTemplate or OracleLobHandler with a NativeJdbcExtractor.
The NativeJdbcExtractor comes in a variety of flavors to match your execution
environment:
SimpleNativeJdbcExtractor
C3P0NativeJdbcExtractor
CommonsDbcpNativeJdbcExtractor
JBossNativeJdbcExtractor
WebLogicNativeJdbcExtractor
WebSphereNativeJdbcExtractor
XAPoolNativeJdbcExtractor
Usually the SimpleNativeJdbcExtractor is sufficient for unwrapping a
Connection object in most environments. See the Javadocs for more details.
If you are processing a stream of updates or reading from a file, then you might have a
preferred batch size, but the last batch might not have that number of entries. In this case
you can use the InterruptibleBatchPreparedStatementSetter interface,
which allows you to interrupt a batch once the input source is exhausted. The
isBatchExhausted method allows you to signal the end of the batch.
For an SQL statement using the classic "?" placeholders, you pass in a list containing an
object array with the update values. This object array must have one entry for each
placeholder in the SQL statement, and they must be in the same order as they are defined
in the SQL statement.
The same example using classic JDBC "?" placeholders:
public class JdbcActorDao implements ActorDao {
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
public int[] batchUpdate(final List<Actor> actors) {
List<Object[]> batch = new ArrayList<Object[]>();
All of the above batch update methods return an int array containing the number of affected
rows for each batch entry. This count is reported by the JDBC driver. If the count is not
available, the JDBC driver returns a -2 value.
The batch update methods for this call returns an array of int arrays containing an array
entry for each batch with an array of the number of affected rows for each update. The top
level array's length indicates the number of batches executed and the second level array's
length indicates the number of updates in that batch. The number of updates in each batch
should be the the batch size provided for all batches except for the last one that might be
less, depending on the total number of update objects provided. The update count for each
update statement is the one reported by the JDBC driver. If the count is not available, the
JDBC driver returns a -2 value.
configuration by taking advantage of database metadata that can be retrieved through the
JDBC driver. This means there is less to configure up front, although you can override or
turn off the metadata processing if you prefer to provide all the details in your code.
The execute method used here takes a plain java.utils.Map as its only parameter.
The important thing to note here is that the keys used for the Map must match the column
names of the table as defined in the database. This is because we read the metadata in
order to construct the actual insert statement.
The main difference when executing the insert by this second approach is that you do not
add the id to the Map and you call the executeReturningKey method. This returns a
java.lang.Number object with which you can create an instance of the numerical type
that is used in our domain class.You cannot rely on all databases to return a specific Java
class here; java.lang.Number is the base class that you can rely on. If you have
multiple auto-generated columns, or the generated values are non-numeric, then you can
use a KeyHolder that is returned from the executeReturningKeyHolder method.
The execution of the insert is the same as if you had relied on the metadata to determine
which columns to use.
new SimpleJdbcInsert(dataSource)
.withTableName("t_actor")
.usingGeneratedKeyColumns("id");
}
public void add(Actor actor) {
SqlParameterSource parameters = new MapSqlParameterSource()
.addValue("first_name", actor.getFirstName())
.addValue("last_name", actor.getLastName());
Number newId = insertActor.executeAndReturnKey(parameters);
actor.setId(newId.longValue());
}
//
As you can see, the configuration is the same; only the executing code has to change to
use these alternative input classes.
The in_id parameter contains the id of the actor you are looking up. The out
parameters return the data read from the table.
The SimpleJdbcCall is declared in a similar manner to the SimpleJdbcInsert. You
should instantiate and configure the class in the initialization method of your data access
layer. Compared to the StoredProcedure class, you don't have to create a subclass and
you don't have to declare parameters that can be looked up in the database metadata.
Following is an example of a SimpleJdbcCall configuration using the above stored
procedure. The only configuration option, in addition to the DataSource, is the name of
the stored procedure.
public class JdbcActorDao implements ActorDao {
private JdbcTemplate jdbcTemplate;
private SimpleJdbcCall procReadActor;
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.procReadActor =
new SimpleJdbcCall(dataSource)
.withProcedureName("read_actor");
}
public Actor readActor(Long id) {
SqlParameterSource in = new MapSqlParameterSource()
.addValue("in_id", id);
Map out = procReadActor.execute(in);
Actor actor = new Actor();
actor.setId(id);
actor.setFirstName((String) out.get("out_first_name"));
actor.setLastName((String) out.get("out_last_name"));
actor.setBirthDate((Date) out.get("out_birth_date"));
return actor;
}
//
The code you write for the execution of the call involves creating an
By taking this action, you avoid conflicts in the case used for the names of your returned
out parameters.
The following example shows a fully declared procedure call, using the information from
the preceding example.
public class JdbcActorDao implements ActorDao {
private SimpleJdbcCall procReadActor;
public void setDataSource(DataSource dataSource) {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.setResultsMapCaseInsensitive(true);
this.procReadActor =
new SimpleJdbcCall(jdbcTemplate)
.withProcedureName("read_actor")
.withoutProcedureColumnMetaDataAccess()
.useInParameterNames("in_id")
.declareParameters(
new SqlParameter("in_id", Types.NUMERIC),
new SqlOutParameter("out_first_name", Types.VARCHAR),
new SqlOutParameter("out_last_name", Types.VARCHAR),
new SqlOutParameter("out_birth_date", Types.DATE)
);
}
//
The execution and end results of the two examples are the same; this one specifies all
details explicitly rather than relying on metadata.
The first line with the SqlParameter declares an IN parameter. IN parameters can be
used for both stored procedure calls and for queries using the SqlQuery and its
subclasses covered in the following section.
The second line with the SqlOutParameter declares an out parameter to be used in a
stored procedure call. There is also an SqlInOutParameter for InOut parameters,
parameters that provide an IN value to the procedure and that also return a value.
Note
Only parameters declared as SqlParameter and
SqlInOutParameter will be used to provide input values. This is
different from the StoredProcedure class, which for backwards
compatibility reasons allows input values to be provided for parameters
declared as SqlOutParameter.
For IN parameters, in addition to the name and the SQL type, you can specify a scale for
numeric data or a type name for custom database types. For out parameters, you can
provide a RowMapper to handle mapping of rows returned from a REF cursor. Another
option is to specify an SqlReturnType that provides an opportunity to define customized
handling of the return values.
The execute method used returns a String containing the return value from the function
call.
To call this procedure you declare the RowMapper. Because the class you want to map to
follows the JavaBean rules, you can use a
ParameterizedBeanPropertyRowMapper that is created by passing in the required
class to map to in the newInstance method.
The execute call passes in an empty Map because this call does not take any parameters.
The list of Actors is then retrieved from the results map and returned to the caller.
14.6.1 SqlQuery
SqlQuery is a reusable, threadsafe class that encapsulates an SQL query. Subclasses
must implement the newRowMapper(..) method to provide a RowMapper instance that
can create one object per row obtained from iterating over the ResultSet that is created
during the execution of the query. The SqlQuery class is rarely used directly because the
MappingSqlQuery subclass provides a much more convenient implementation for
mapping rows to Java classes. Other implementations that extend SqlQuery are
MappingSqlQueryWithParameters and UpdatableSqlQuery.
14.6.2 MappingSqlQuery
MappingSqlQuery is a reusable query in which concrete subclasses must implement
the abstract mapRow(..) method to convert each row of the supplied ResultSet into an
object of the type specified. The following example shows a custom query that maps the
data from the t_actor relation to an instance of the Actor class.
public class ActorMappingQuery extends MappingSqlQuery<Actor> {
public ActorMappingQuery(DataSource ds) {
super(ds, "select id, first_name, last_name from t_actor where id = ?");
super.declareParameter(new SqlParameter("id", Types.INTEGER));
compile();
}
@Override
protected Actor mapRow(ResultSet rs, int rowNumber) throws SQLException {
The class extends MappingSqlQuery parameterized with the Actor type. The
constructor for this customer query takes the DataSource as the only parameter. In this
constructor you 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.You must declare each parameter using the declareParameter
method passing in an SqlParameter. The SqlParameter takes a name and the JDBC
type as defined in java.sql.Types. After you define all parameters, you call the
compile() method so the statement can be prepared and later executed. This class is
thread-safe after it is compiled, so as long as these instances are created when the DAO is
initialized they can be kept as instance variables and be reused.
private ActorMappingQuery actorMappingQuery;
@Autowired
public void setDataSource(DataSource dataSource) {
this.actorMappingQuery = new ActorMappingQuery(dataSource);
}
public Customer getCustomer(Long id) {
return actorMappingQuery.findObject(id);
}
The method in this example retrieves the customer with the id that is passed in as the only
parameter. Since we only want one object returned we simply call the convenience
method findObject with the id as parameter. If we had instead a query that returned a
list of objects and took additional parameters then we would use one of the execute
methods that takes an array of parameter values passed in as varargs.
public List<Actor> searchForActors(int age, String namePattern) {
List<Actor> actors = actorSearchMappingQuery.execute(age, namePattern);
return actors;
}
14.6.3 SqlUpdate
The SqlUpdate class encapsulates an SQL update. Like a query, an update object is
reusable, and like all RdbmsOperation classes, 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. The SQLUpdate class is concrete. It can be
subclassed, for example, to add a custom update method, as in the following snippet
where it's simply called execute. However, you don't have to subclass the SqlUpdate
class since 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;
public class UpdateCreditRating extends SqlUpdate {
public UpdateCreditRating(DataSource ds) {
setDataSource(ds);
setSql("update customer set credit_rating = ? where id = ?");
declareParameter(new SqlParameter("creditRating", Types.NUMERIC));
declareParameter(new SqlParameter("id", Types.NUMERIC));
compile();
}
/**
* @param id for the Customer to be updated
* @param rating the new value for credit rating
14.6.4 StoredProcedure
The StoredProcedure class is a superclass for object abstractions of RDBMS stored
procedures. This class is abstract, and its various execute(..) methods have
protected access, preventing use other than through a subclass that offers tighter
typing.
The inherited sql property will be the name of the stored procedure in the RDBMS.
To define a parameter for the StoredProcedure class, you use an SqlParameter or
one of its subclasses. You must specify the parameter name and SQL type in the
constructor like in the following code snippet. The SQL type is specified using the
java.sql.Types constants.
new SqlParameter("in_id", Types.NUMERIC),
new SqlOutParameter("out_first_name", Types.VARCHAR),
The first line with the SqlParameter declares an IN parameter. IN parameters can be
used for both stored procedure calls and for queries using the SqlQuery and its
subclasses covered in the following section.
The second line with the SqlOutParameter declares an out parameter to be used in
the stored procedure call. There is also an SqlInOutParameter for InOut parameters,
parameters that provide an in value to the procedure and that also return a value.
For in parameters, in addition to the name and the SQL type, you can specify a scale for
numeric data or a type name for custom database types. For out parameters you can
provide a RowMapper to handle mapping of rows returned from a REF cursor. Another
option is to specify an SqlReturnType that enables you to define customized handling
of the return values.
Here is an example of a simple DAO that uses a StoredProcedure to call a function,
sysdate(),which comes with any Oracle database. To use the stored procedure
functionality you have to create a class that extends StoredProcedure. In this example,
the StoredProcedure class is an inner class, but if you need to reuse the
StoredProcedure you declare it as a top-level class. This example has no input
parameters, but an output parameter is declared as a date type using the class
SqlOutParameter. The execute() method executes the procedure and extracts the
returned date from the results Map. The results Map has an entry for each declared output
parameter, in this case only one, using the parameter name as the key.
import
import
import
import
java.sql.Types;
java.util.Date;
java.util.HashMap;
java.util.Map;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.SqlOutParameter;
import org.springframework.jdbc.object.StoredProcedure;
public class StoredProcedureDao {
private GetSysdateProcedure getSysdate;
@Autowired
public void init(DataSource dataSource) {
this.getSysdate = new GetSysdateProcedure(dataSource);
}
public Date getSysdate() {
return getSysdate.execute();
}
private class GetSysdateProcedure extends StoredProcedure {
private static final String SQL = "sysdate";
public GetSysdateProcedure(DataSource dataSource) {
setDataSource(dataSource);
setFunction(true);
setSql(SQL);
declareParameter(new SqlOutParameter("date", Types.DATE));
compile();
}
public Date execute() {
// the 'sysdate' sproc has no input parameters, so an empty Map is supplied...
Map<String, Object> results = execute(new HashMap<String, Object>());
Date sysdate = (Date) results.get("date");
return sysdate;
}
}
}
The following example of a StoredProcedure has two output parameters (in this case,
Oracle REF cursors).
import oracle.jdbc.OracleTypes;
import org.springframework.jdbc.core.SqlOutParameter;
import org.springframework.jdbc.object.StoredProcedure;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
public class TitlesAndGenresStoredProcedure extends StoredProcedure {
private static final String SPROC_NAME = "AllTitlesAndGenres";
public TitlesAndGenresStoredProcedure(DataSource dataSource) {
super(dataSource, SPROC_NAME);
declareParameter(new SqlOutParameter("titles", OracleTypes.CURSOR, new TitleMapper()));
declareParameter(new SqlOutParameter("genres", OracleTypes.CURSOR, new GenreMapper()));
compile();
}
public Map<String, Object> execute() {
// again, this sproc has no input parameters, so an empty Map is supplied
return super.execute(new HashMap<String, Object>());
}
}
Notice how the overloaded variants of the declareParameter(..) method that have
been used in the TitlesAndGenresStoredProcedure constructor are passed
RowMapper implementation instances; this is a very convenient and powerful way to
reuse existing functionality. The code for the two RowMapper implementations is provided
below.
The TitleMapper class maps a ResultSet to a Title domain object for each row in
the supplied ResultSet:
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.foo.domain.Title;
public final class TitleMapper implements RowMapper<Title> {
public Title mapRow(ResultSet rs, int rowNum) throws SQLException {
Title title = new Title();
title.setId(rs.getLong("id"));
title.setName(rs.getString("name"));
return title;
}
}
The GenreMapper class maps a ResultSet to a Genre domain object for each row in
the supplied ResultSet.
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.foo.domain.Genre;
public final class GenreMapper implements RowMapper<Genre> {
public Genre mapRow(ResultSet rs, int rowNum) throws SQLException {
return new Genre(rs.getString("name"));
}
}
To pass parameters to a stored procedure that has one or more input parameters in its
definition in the RDBMS, you can code a strongly typed execute(..) method that would
delegate to the superclass' untyped execute(Map parameters) method (which has
protected access); for example:
import
import
import
import
oracle.jdbc.OracleTypes;
org.springframework.jdbc.core.SqlOutParameter;
org.springframework.jdbc.core.SqlParameter;
org.springframework.jdbc.object.StoredProcedure;
import javax.sql.DataSource;
import
import
import
import
java.sql.Types;
java.util.Date;
java.util.HashMap;
java.util.Map;
You use the SqlTypeValue to pass in the value of a Java object like TestItem into a
stored procedure. The SqlTypeValue interface has a single method named
createTypeValue that you must implement. The active connection is passed in, and
you can use it to create database-specific objects such as StructDescriptors, as
shown in the following example, or ArrayDescriptors.
final TestItem = new TestItem(123L, "A test item",
new SimpleDateFormat("yyyy-M-d").parse("2010-12-31"));
SqlTypeValue value = new AbstractSqlTypeValue() {
protected Object createTypeValue(Connection conn, int sqlType, String typeName) throws SQLException {
StructDescriptor itemDescriptor = new StructDescriptor(typeName, conn);
Struct item = new STRUCT(itemDescriptor, conn,
new Object[] {
testItem.getId(),
testItem.getDescription(),
new java.sql.Date(testItem.getExpirationDate().getTime())
});
return item;
}
};
This SqlTypeValue can now be added to the Map containing the input parameters for
the execute call of the stored procedure.
Another use for the SqlTypeValue is passing in an array of values to an Oracle stored
procedure. Oracle has its own internal ARRAY class that must be used in this case, and
you can use the SqlTypeValue to create an instance of the Oracle ARRAY and populate
it with values from the Java ARRAY.
final Long[] ids = new Long[] {1L, 2L};
SqlTypeValue value = new AbstractSqlTypeValue() {
protected Object createTypeValue(Connection conn, int sqlType, String typeName) throws SQLException {
ArrayDescriptor arrayDescriptor = new ArrayDescriptor(typeName, conn);
ARRAY idArray = new ARRAY(arrayDescriptor, conn, ids);
return idArray;
}
};
The preceding configuration creates an embedded HSQL database populated with SQL
from schema.sql and testdata.sql resources in the classpath. The database instance is
made available to the Spring container as a bean of type javax.sql.DataSource.
This bean can then be injected into data access objects as needed.
14.8.6 Using H2
Spring supports the H2 database as well. To enable H2, set the type attribute of the
embedded-database tag to H2. If you are using the builder API, call the
setType(EmbeddedDatabaseType) method with EmbeddedDatabaseType.H2.
The example above runs the two scripts specified against the database: the first script is a
schema creation, and the second is a test data set insert. The script locations can also be
patterns with wildcards in the usual ant style used for resources in Spring (e.g.
classpath*:/com/foo/**/sql/*-data.sql). If a pattern is used the scripts are
executed in lexical order of their URL or filename.
The default behavior of the database initializer is to unconditionally execute the scripts
provided. This will not always be what you want, for instance if running against an existing
database that already has test data in it. The likelihood of accidentally deleting data is
reduced by the commonest pattern (as shown above) that creates the tables first and then
inserts the data - the first step will fail if the tables already exist.
However, to get more control over the creation and deletion of existing data, the XML
namespace provides a couple more options. The first is flag to switch the initialization on
and off. This can be set according to the environment (e.g. to pull a boolean value from
system properties or an environment bean), e.g.
<jdbc:initialize-database data-source="dataSource"
enabled="#{systemProperties.INITIALIZE_DATABASE}">
<jdbc:script location="..."/>
</jdbc:initialize-database>
The second option to control what happens with existing data is to be more tolerant of
failures. To this end you can control the ability of the initializer to ignore certain errors in the
SQL it executes from the scripts, e.g.
<jdbc:initialize-database data-source="dataSource" ignore-failures="DROPS">
<jdbc:script location="..."/>
</jdbc:initialize-database>
In this example we are saying we expect that sometimes the scripts will be run against an
empty database and there are some DROP statements in the scripts which would therefore
fail. So failed SQL DROP statements will be ignored, but other failures will cause an
exception. This is useful if your SQL dialect doesn't support DROP ... IF EXISTS (or
similar) but you want to unconditionally remove all test data before re-creating it. In that
case the first script is usually a set of drops, followed by a set of CREATE statements.
The ignore-failures option can be set to NONE (the default), DROPS (ignore failed
drops) or ALL (ignore all failures).
If you need more control than you get from the XML namespace, you can simply use the
DataSourceInitializer directly, and define it as a component in your application.
A large class of applications can just use the database initializer with no further
complications: those that do not use the database until after the Spring context has started.
If your application is not one of those then you might need to read the rest of this section.
The database initializer depends on a data source instance and runs the scripts provided
in its initialization callback (c.f. init-method in an XML bean definition or
InitializingBean). If other beans depend on the same data source and also use the
data source in an initialization callback then there might be a problem because the data
has not yet been initialized. A common example of this is a cache that initializes eagerly
and loads up data from the database on application startup.
To get round this issue you two options: change your cache initialization strategy to a later
phase, or ensure that the database initializer is initialized first.
The first option might be easy if the application is in your control, and not otherwise. Some
suggestions for how to implement this are
Make the cache initialize lazily on first usage, which improves application startup time
Have your cache or a separate component that initializes the cache implement
Lifecycle or SmartLifecycle. When the application context starts up a
SmartLifecycle can be automatically started if its autoStartup flag is set, and a
Lifecycle can be started manually by calling
ConfigurableApplicationContext.start() on the enclosing context.
Use a Spring ApplicationEvent or similar custom observer mechanism to trigger
the cache initialization. ContextRefreshedEvent is always published by the
context when it is ready for use (after all beans have been initialized), so that is often a
useful hook (this is how the SmartLifecycle works by default).
The second option can also be easy. Some suggestions on how to implement this are
Rely on Spring BeanFactory default behavior, which is that beans are initialized in
registration order. You can easily arrange that by adopting the common practice of a
set of <import/> elements that order your application modules, and ensure that the
database and database initialization are listed first
Separate the datasource and the business components that use it and control their
startup order by putting them in separate ApplicationContext instances (e.g. parent has
the datasource and child has the business components). This structure is common in
Spring web applications, but can be more generally applied.
Use a modular runtime like SpringSource dm Server and separate the data source and
the components that depend on it. E.g. specify the bundle start up order as datasource
-> initializer -> business components.
data access applications. You can leverage as much of the integration support as you
wish, and you should compare this integration effort with the cost and risk of building a
similar infrastructure in-house. You can use much of the ORM support as you would a
library, regardless of technology, because everything is designed as a set of reusable
JavaBeans. ORM in a Spring IoC container facilitates configuration and deployment. Thus
most examples in this section show configuration inside a Spring container.
Benefits of using the Spring Framework to create your ORM DAOs include:
Easier testing. Spring's IoC approach makes it easy to swap the implementations and
configuration locations of Hibernate SessionFactory instances, JDBC
DataSource instances, transaction managers, and mapped object implementations
(if needed). This in turn makes it much easier to test each piece of persistence-related
code in isolation.
Common data access exceptions. Spring can wrap exceptions from your ORM tool,
converting them from proprietary (potentially checked) exceptions to a common
runtime DataAccessException hierarchy. This feature allows you to handle most
persistence exceptions, which are non-recoverable, only in the appropriate layers,
without annoying boilerplate catches, throws, and exception declarations. You can still
trap and handle exceptions as necessary. Remember that JDBC exceptions (including
DB-specific dialects) are also converted to the same hierarchy, meaning that you can
perform some operations with JDBC within a consistent programming model.
General resource management. Spring application contexts can handle the location
and configuration of Hibernate SessionFactory instances, JPA
EntityManagerFactory instances, JDBC DataSource instances, iBATIS SQL
Maps configuration objects, and other related resources. This makes these values
easy to manage and change. Spring offers efficient, easy, and safe handling of
persistence resources. For example, related code that uses Hibernate generally needs
to use the same Hibernate Session to ensure efficiency and proper transaction
handling. Spring makes it easy to create and bind a Session to the current thread
transparently, by exposing a current Session through the Hibernate
SessionFactory. Thus Spring solves many chronic problems of typical Hibernate
usage, for any local or JTA transaction environment.
Integrated transaction management. You can wrap your ORM code with a declarative,
aspect-oriented programming (AOP) style method interceptor either through the
@Transactional annotation or by explicitly configuring the transaction AOP advice
in an XML configuration file. In both cases, transaction semantics and exception
handling (rollback, and so on) are handled for you. As discussed below, in Resource
and transaction management, you can also swap various transaction managers,
without affecting your ORM-related code. For example, you can swap between local
transactions and JTA, with the same full services (such as declarative transactions)
available in both scenarios. Additionally, JDBC-related code can fully integrate
transactionally with the code you use to do ORM. This is useful for data access that is
not suitable for ORM, such as batch processing and BLOB streaming, which still need
to share common transactions with ORM operations.
TODO: provide links to current samples
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 need not be Spring-aware. In a typical Spring application, many
important objects are JavaBeans: data access templates, data access objects, transaction
managers, business services that use the data access objects and transaction managers,
web view resolvers, web controllers that use the business services,and so on.
The postprocessor automatically looks for all exception translators (implementations of the
15.3 Hibernate
We will start with a coverage of Hibernate 3 in a Spring environment, using it to
demonstrate the approach that Spring takes towards integrating O/R mappers. This section
will cover many issues in detail and show different variations of DAO implementations and
transaction demarcation. Most of these patterns can be directly translated to all other
supported ORM tools. The following sections in this chapter will then cover the other ORM
technologies, showing briefer examples there.
Note
As of Spring 3.0, Spring requires Hibernate 3.2 or later.
This style is similar to that of the Hibernate reference documentation and examples, except
for holding the SessionFactory in an instance variable. We strongly recommend such
an instance-based setup over the old-school static HibernateUtil class from
Hibernate's CaveatEmptor sample application. (In general, do not keep any resources in
static variables unless absolutely necessary.)
The above DAO follows the dependency injection pattern: it fits nicely into a Spring IoC
container, just as it would if coded against Spring's HibernateTemplate. Of course,
such a DAO can also be set up in plain Java (for example, in unit tests). Simply instantiate
it and call setSessionFactory(..) with the desired factory reference. As a Spring
bean definition, the DAO would resemble the following:
<beans>
<bean id="myProductDao" class="product.ProductDaoImpl">
<property name="sessionFactory" ref="mySessionFactory"/>
</bean>
</beans>
The main advantage of this DAO style is that it depends on Hibernate API only; no import
of any Spring class is required. This is of course appealing from a non-invasiveness
perspective, and will no doubt feel more natural to Hibernate developers.
However, the DAO throws plain HibernateException (which is unchecked, so does
not have to be declared or caught), which means that callers can only treat exceptions as
generally fatal - unless they want to depend on Hibernate's own exception hierarchy.
Catching specific causes such as an optimistic locking failure is not possible without tying
the caller to the implementation strategy. This trade off might be acceptable to applications
that are strongly Hibernate-based and/or do not need any special exception treatment.
Fortunately, Spring's LocalSessionFactoryBean supports Hibernate's
SessionFactory.getCurrentSession() method for any Spring transaction
strategy, returning the current Spring-managed transactional Session even with
HibernateTransactionManager. Of course, the standard behavior of that method
remains the return of the current Session associated with the ongoing JTA transaction, if
any. This behavior applies regardless of whether you are using Spring's
JtaTransactionManager, EJB container managed transactions (CMTs), or JTA.
In summary: you can implement DAOs based on the plain Hibernate 3 API, while still
being able to participate in Spring-managed transactions.
We recommend that you use Spring's declarative transaction support, which enables you
to replace explicit transaction demarcation API calls in your Java code with an AOP
transaction interceptor. This transaction interceptor can be configured in a Spring container
using either Java annotations or XML.This declarative transaction capability allows you to
keep business services free of repetitive transaction demarcation code and to focus on
adding business logic, which is the real value of your application.
Note
Prior to continuing, you are strongly encouraged to read Section 12.5,
Declarative transaction management if you have not done so.
Furthermore, transaction semantics like propagation behavior and isolation level can be
changed in a configuration file and do not affect the business service implementations.
The following example shows how you can configure an AOP transaction interceptor,
using XML, for a simple service class:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- SessionFactory, DataSource, etc. omitted -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<aop:config>
<aop:pointcut id="productServiceMethods"
expression="execution(* product.ProductService.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="productServiceMethods"/>
</aop:config>
<tx:advice id="txAdvice" transaction-manager="myTxManager">
<tx:attributes>
<tx:method name="increasePrice*" propagation="REQUIRED"/>
<tx:method name="someOtherBusinessMethod" propagation="REQUIRES_NEW"/>
<tx:method name="*" propagation="SUPPORTS" read-only="true"/>
</tx:attributes>
</tx:advice>
<bean id="myProductService" class="product.SimpleProductService">
<property name="productDao" ref="myProductDao"/>
</bean>
</beans>
container to find these annotations and provide transactional semantics for these
annotated methods.
public class ProductServiceImpl implements ProductService {
private ProductDao productDao;
public void setProductDao(ProductDao productDao) {
this.productDao = productDao;
}
@Transactional
public void increasePriceOfAllProductsInCategory(final String category) {
List productsToChange = this.productDao.loadProductsByCategory(category);
// ...
}
@Transactional(readOnly = true)
public List<Product> findAllProducts() {
return this.productDao.findAllProducts();
}
}
As you can see from the following configuration example, the configuration is much
simplified, compared to the XML example above, while still providing the same
functionality driven by the annotations in the service layer code. All you need to provide is
the TransactionManager implementation and a "<tx:annotation-driven/>" entry.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- SessionFactory, DataSource, etc. omitted -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<tx:annotation-driven/>
<bean id="myProductService" class="product.SimpleProductService">
<property name="productDao" ref="myProductDao"/>
</bean>
</beans>
</value>
</property>
</bean>
<bean id="mySessionFactory2"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="myDataSource2"/>
<property name="mappingResources">
<list>
<value>inventory.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.OracleDialect
</value>
</property>
</bean>
<bean id="myTxManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
<bean id="myProductDao" class="product.ProductDaoImpl">
<property name="sessionFactory" ref="mySessionFactory1"/>
</bean>
<bean id="myInventoryDao" class="product.InventoryDaoImpl">
<property name="sessionFactory" ref="mySessionFactory2"/>
</bean>
<bean id="myProductService" class="product.ProductServiceImpl">
<property name="productDao" ref="myProductDao"/>
<property name="inventoryDao" ref="myInventoryDao"/>
</bean>
<aop:config>
<aop:pointcut id="productServiceMethods"
expression="execution(* product.ProductService.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="productServiceMethods"/>
</aop:config>
<tx:advice id="txAdvice" transaction-manager="myTxManager">
<tx:attributes>
<tx:method name="increasePrice*" propagation="REQUIRED"/>
<tx:method name="someOtherBusinessMethod" propagation="REQUIRES_NEW"/>
<tx:method name="*" propagation="SUPPORTS" read-only="true"/>
</tx:attributes>
</tx:advice>
</beans>
than JTA, transaction support also works in a stand-alone or test environment. Especially
in the typical case of single-database transactions, Spring's single-resource local
transaction support is a lightweight and powerful alternative to JTA. When you use local
EJB stateless session beans to drive transactions, you depend both on an EJB container
and JTA, even if you access only a single database, and only use stateless session beans
to provide declarative transactions through container-managed transactions. Also, direct
use of JTA programmatically requires a Java EE environment as well. JTA does not
involve only container dependencies in terms of JTA itself and of JNDI DataSource
instances. For non-Spring, JTA-driven Hibernate transactions, you have to use the
Hibernate JCA connector, or extra Hibernate transaction code with the
TransactionManagerLookup configured for proper JVM-level caching.
Spring-driven transactions can work as well with a locally defined Hibernate
SessionFactory as they do with a local JDBC DataSource if they are accessing a
single database. Thus you only have to use Spring's JTA transaction strategy when you
have distributed transaction requirements. A JCA connector requires container-specific
deployment steps, and obviously JCA support in the first place. This configuration requires
more work than deploying a simple web application with local resource definitions and
Spring-driven transactions. Also, you often need the Enterprise Edition of your container if
you are using, for example, WebLogic Express, which does not provide JCA. A Spring
application with local resources and transactions spanning one single database works in
any Java EE web container (without JTA, JCA, or EJB) such as Tomcat, Resin, or even
plain Jetty. Additionally, you can easily reuse such a middle tier in desktop applications or
test suites.
All things considered, if you do not use EJBs, stick with local SessionFactory setup
and Spring's HibernateTransactionManager or JtaTransactionManager. You
get all of the benefits, including proper transactional JVM-level caching and distributed
transactions, without the inconvenience of container deployment. JNDI registration of a
Hibernate SessionFactory through the JCA connector only adds value when used in
conjunction with EJBs.
You resolve this warning by simply making Hibernate aware of the JTA
PlatformTransactionManager instance, to which it will synchronize (along with
Spring). You have two options for doing this:
If in your application context you are already directly obtaining the JTA
PlatformTransactionManager object (presumably from JNDI through
JndiObjectFactoryBean or <jee:jndi-lookup>) and feeding it, for example,
to Spring's JtaTransactionManager, then the easiest way is to specify a
reference to the bean defining this JTA PlatformTransactionManager instance
as the value of the jtaTransactionManager property for
LocalSessionFactoryBean. Spring then makes the object available to
Hibernate.
More likely you do not already have the JTA PlatformTransactionManager
instance, because Spring's JtaTransactionManager can find it itself. Thus you
15.4 JDO
Spring supports the standard JDO 2.0 and 2.1 APIs as data access strategy, following the
same style as the Hibernate support. The corresponding integration classes reside in the
org.springframework.orm.jdo package.
just like a JDBC DataSource implementation class, which is a natural fit for a
configuration that uses Spring. This setup style usually supports a Spring-defined JDBC
DataSource, passed into the connectionFactory property. For example, for the
open source JDO implementation DataNucleus (formerly JPOX)
(http://www.datanucleus.org/), this is the XML configuration of the
PersistenceManagerFactory implementation:
<beans>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<bean id="myPmf" class="org.datanucleus.jdo.JDOPersistenceManagerFactory" destroy-method="close">
<property name="connectionFactory" ref="dataSource"/>
<property name="nontransactionalRead" value="true"/>
</bean>
</beans>
Because the above DAO follows the dependency injection pattern, it fits nicely into a
Spring container, just as it would if coded against Spring's JdoTemplate:
<beans>
<bean id="myProductDao" class="product.ProductDaoImpl">
<property name="persistenceManagerFactory" ref="myPmf"/>
</bean>
</beans>
The main problem with such DAOs is that they always get a new PersistenceManager
from the factory. To access a Spring-managed transactional PersistenceManager,
define a TransactionAwarePersistenceManagerFactoryProxy (as included in
Your data access code will receive a transactional PersistenceManager (if any) from
the PersistenceManagerFactory.getPersistenceManager() method that it
calls. The latter method call goes through the proxy, which first checks for a current
transactional PersistenceManager before getting a new one from the factory. Any
close() calls on the PersistenceManager are ignored in case of a transactional
PersistenceManager.
If your data access code always runs within an active transaction (or at least within active
transaction synchronization), it is safe to omit the PersistenceManager.close() call
and thus the entire finally block, which you might do to keep your DAO
implementations concise:
public class ProductDaoImpl implements ProductDao {
private PersistenceManagerFactory persistenceManagerFactory;
public void setPersistenceManagerFactory(PersistenceManagerFactory pmf) {
this.persistenceManagerFactory = pmf;
}
public Collection loadProductsByCategory(String category) {
PersistenceManager pm = this.persistenceManagerFactory.getPersistenceManager();
Query query = pm.newQuery(Product.class, "category = pCategory");
query.declareParameters("String pCategory");
return query.execute(category);
}
}
With such DAOs that rely on active transactions, it is recommended that you enforce active
transactions through turning off
TransactionAwarePersistenceManagerFactoryProxy's allowCreate flag:
<beans>
<bean id="myPmfProxy"
class="org.springframework.orm.jdo.TransactionAwarePersistenceManagerFactoryProxy">
<property name="targetPersistenceManagerFactory" ref="myPmf"/>
<property name="allowCreate" value="false"/>
</bean>
<bean id="myProductDao" class="product.ProductDaoImpl">
<property name="persistenceManagerFactory" ref="myPmfProxy"/>
</bean>
</beans>
The main advantage of this DAO style is that it depends on JDO API only; no import of any
Spring class is required. This is of course appealing from a non-invasiveness perspective,
and might feel more natural to JDO developers.
However, the DAO throws plain JDOException (which is unchecked, so does not have
to be declared or caught), which means that callers can only treat exceptions as fatal,
unless you want to depend on JDO's own exception structure. Catching specific causes
such as an optimistic locking failure is not possible without tying the caller to the
implementation strategy. This trade off might be acceptable to applications that are strongly
JDO-based and/or do not need any special exception treatment.
In summary, you can DAOs based on the plain JDO API, and they can still participate in
Spring-managed transactions. This strategy might appeal to you if you are already familiar
with JDO. However, such DAOs throw plain JDOException, and you would have to
convert explicitly to Spring's DataAccessException (if desired).
15.4.4 JdoDialect
As an advanced feature, both JdoTemplate and JdoTransactionManager support a
custom JdoDialect that can be passed into the jdoDialect bean property. In this
scenario, the DAOs will not receive a PersistenceManagerFactory reference but
rather a full JdoTemplate instance (for example, passed into the jdoTemplate
15.5 JPA
The Spring JPA, available under the org.springframework.orm.jpa package,
offers comprehensive support for the Java Persistence API in a similar manner to the
integration with Hibernate or JDO, while being aware of the underlying implementation in
order to provide additional features.
This form of JPA deployment is the simplest and the most limited. You cannot refer to an
existing JDBC DataSource bean definition and no support for global transactions exists.
Furthermore, weaving (byte-code transformation) of persistent classes is provider-specific,
often requiring a specific JVM agent to specified on startup. This option is sufficient only for
stand-alone applications and test environments, for which the JPA specification is
designed.
This action assumes standard Java EE 5 bootstrapping: the Java EE server autodetects
persistence units (in effect, META-INF/persistence.xml files in application jars) and
persistence-unit-ref entries in the Java EE deployment descriptor (for example,
web.xml) and defines environment naming context locations for those persistence units.
In such a scenario, the entire persistence unit deployment, including the weaving (bytecode transformation) of persistent classes, is up to the Java EE server. The JDBC
DataSource is defined through a JNDI location in the META-INF/persistence.xml
file; EntityManager transactions are integrated with the server's JTA subsystem. Spring
merely uses the obtained EntityManagerFactory, passing it on to application objects
through dependency injection, and managing transactions for the persistence unit, typically
through JtaTransactionManager.
If multiple persistence units are used in the same application, the bean names of such
JNDI-retrieved persistence units should match the persistence unit names that the
application uses to refer to them, for example, in @PersistenceUnit and
@PersistenceContext annotations.
LocalContainerEntityManagerFactoryBean
Note
Use this option for full JPA capabilities in a Spring-based application
environment. This includes web containers such as Tomcat as well as
stand-alone applications and integration tests with sophisticated
persistence requirements.
The LocalContainerEntityManagerFactoryBean gives full control over
EntityManagerFactory configuration and is appropriate for environments where finegrained customization is required. The
LocalContainerEntityManagerFactoryBean creates a
PersistenceUnitInfo instance based on the persistence.xml file, the supplied
dataSourceLookup strategy, and the specified loadTimeWeaver. It is thus possible to
work with custom data sources outside of JNDI and to control the weaving process. The
following example shows a typical bean definition for a
LocalContainerEntityManagerFactoryBean:
<beans>
<bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="someDataSource"/>
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
</property>
</bean>
</beans>
Note
The exclude-unlisted-classes element always indicates that
no scanning for annotated entity classes is supposed to occur, in order
to support the <exclude-unlisted-classes/> shortcut. This is in
line with the JPA specification, which suggests that shortcut, but
unfortunately is in conflict with the JPA XSD, which implies false for
that shortcut. Consequently, <exclude-unlisted-classes>
false </exclude-unlisted-classes/> is not supported.
Simply omit the exclude-unlisted-classes element if you want
entity class scanning to occur.
Using the LocalContainerEntityManagerFactoryBean is the most powerful JPA
setup option, allowing for flexible local configuration within the application. It supports links
to an existing JDBC DataSource, supports both local and global transactions, and so on.
However, it also imposes requirements on the runtime environment, such as the
availability of a weaving-capable class loader if the persistence provider demands bytecode transformation.
This option may conflict with the built-in JPA capabilities of a Java EE 5 server. In a full
Java EE 5 environment, consider obtaining your EntityManagerFactory from JNDI.
Alternatively, specify a custom persistenceXmlLocation on your
LocalContainerEntityManagerFactoryBean definition, for example, METAINF/my-persistence.xml, and only include a descriptor with that name in your application
jar files. Because the Java EE 5 server only looks for default METAINF/persistence.xml files, it ignores such custom persistence units and hence avoid
conflicts with a Spring-driven JPA setup upfront. (This applies to Resin 3.1, for example.)
The LoadTimeWeaver interface is a Springprovided class that allows JPA
ClassTransformer instances to be plugged in
a specific manner, depending whether the
environment is a web container or application
server. Hooking ClassTransformers through a
Java 5 agent typically is not efficient. The agents
work against the entire virtual machine and
inspect every class that is loaded, which is usually
undesirable in a production server environment.
Spring provides a number of LoadTimeWeaver
However, if needed, one can manually specify a dedicated weaver through the
loadTimeWeaver property:
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver"/>
</property>
</bean>
No matter how the LTW is configured, using this technique, JPA applications relying on
instrumentation can run in the target platform (ex: Tomcat) without needing an agent. This
is important especially when the hosting applications rely on different JPA
implementations because the JPA transformers are applied only at class loader level and
thus are isolated from each other.
The DAO above has no dependency on Spring and still fits nicely into a Spring application
context. Moreover, the DAO takes advantage of annotations to require the injection of the
default EntityManagerFactory:
<beans>
<!-- bean post-processor for JPA annotations -->
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
<bean id="myProductDao" class="product.ProductDaoImpl"/>
</beans>
The main problem with such a DAO is that it always creates a new EntityManager
through the factory. You can avoid this by requesting a transactional EntityManager
(also called "shared EntityManager" because it is a shared, thread-safe proxy for the actual
transactional EntityManager) to be injected instead of the factory:
public class ProductDaoImpl implements ProductDao {
@PersistenceContext
private EntityManager em;
public Collection loadProductsByCategory(String category) {
Query query = em.createQuery("from Product as p where p.category = :category");
query.setParameter("category", category);
return query.getResultList();
}
}
@PersistenceContext)
can be applied on field or
methods inside a class, hence
the expressions method-level
injection and field-level injection.
Field-level annotations are
concise and easier to use while
method-level allows for further
processing of the injected
dependency. In both cases the
member visibility (public,
protected, private) does not
matter.
What about class-level
annotations?
On the Java EE 5 platform, they
are used for dependency
declaration and not for resource
injection.
To execute service operations within transactions, you can use Spring's common
declarative transaction facilities. For example:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="myTxManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="myEmf"/>
</bean>
<bean id="myProductService" class="product.ProductServiceImpl">
<property name="productDao" ref="myProductDao"/>
</bean>
<aop:config>
<aop:pointcut id="productServiceMethods" expression="execution(* product.ProductService.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="productServiceMethods"/>
</aop:config>
<tx:advice id="txAdvice" transaction-manager="myTxManager">
<tx:attributes>
<tx:method name="increasePrice*" propagation="REQUIRED"/>
<tx:method name="someOtherBusinessMethod" propagation="REQUIRES_NEW"/>
<tx:method name="*" propagation="SUPPORTS" read-only="true"/>
</tx:attributes>
</tx:advice>
</beans>
15.5.4 JpaDialect
As an advanced feature JpaTemplate, JpaTransactionManager and subclasses of
AbstractEntityManagerFactoryBean support a custom JpaDialect, to be
passed into the jpaDialect bean property. In such a scenario, the DAOs do not receive an
EntityManagerFactory reference but rather a full JpaTemplate instance (for
example, passed into the jpaTemplate property of JpaDaoSupport). A JpaDialect
implementation can enable some advanced features supported by Spring, usually in a
vendor-specific manner:
Applying specific transaction semantics such as custom isolation level or transaction
timeout)
Retrieving the transactional JDBC Connection for exposure to JDBC-based DAOs)
Advanced translation of PersistenceExceptions to Spring
DataAccessExceptions
This is particularly valuable for special transaction semantics and for advanced translation
of exception. The default implementation used (DefaultJpaDialect) does not provide
any special capabilities and if the above features are required, you have to specify the
appropriate dialect.
See the JpaDialect Javadoc for more details of its operations and how they are used
within Spring's JPA support.
To map this Account class with iBATIS 2.x we need to create the following SQL map
Account.xml:
<sqlMap namespace="Account">
<resultMap id="result" class="examples.Account">
<result property="name" column="NAME" columnIndex="1"/>
<result property="email" column="EMAIL" columnIndex="2"/>
</resultMap>
<select id="getAccountByEmail" resultMap="result">
select ACCOUNT.NAME, ACCOUNT.EMAIL
from ACCOUNT
where ACCOUNT.EMAIL = #value#
</select>
<insert id="insertAccount">
insert into ACCOUNT (NAME, EMAIL) values (#name#, #email#)
</insert>
</sqlMap>
Remember that iBATIS loads resources from the class path, so be sure to add
theAccount.xml file to the class path.
We can use the SqlMapClientFactoryBean in the Spring container. Note that with
iBATIS SQL Maps 2.x, the JDBC DataSource is usually specified on the
SqlMapClientFactoryBean, which enables lazy loading. This is the configuration
needed for these bean definitions:
<beans>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="configLocation" value="WEB-INF/sqlmap-config.xml"/>
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
}
}
In this scenario, you need to handle the SQLException thrown by the iBATIS API in a
custom fashion, usually by wrapping it in your own application-specific DAO exception.
Wiring in the application context would still look like it does in the example for the
SqlMapClientDaoSupport, due to the fact that the plain iBATIS-based DAO still
follows the dependency injection pattern:
<beans>
<bean id="accountDao" class="example.SqlMapAccountDao">
<property name="sqlMapClient" ref="sqlMapClient"/>
</bean>
</beans>
16.2.1 Marshaller
Spring abstracts all marshalling operations behind the
org.springframework.oxm.Marshaller interface, the main methods of which is
listed below.
The Marshaller interface has one main method, which marshals the given object to a
given javax.xml.transform.Result. Result is a tagging interface that basically
represents an XML output abstraction: concrete implementations wrap various XML
representations, as indicated in the table below.
Result
implementation
DOMResult
org.w3c.dom.Node
SAXResult
org.xml.sax.ContentHandler
StreamResult
java.io.File, java.io.OutputStream, or
java.io.Writer
Note
Although the marshal() method accepts a plain object as its first
parameter, most Marshaller implementations cannot handle
arbitrary objects. Instead, an object class must be mapped in a
mapping file, marked with an annotation, registered with the marshaller,
or have a common base class. Refer to the further sections in this
chapter to determine how your O/X technology of choice manages this.
16.2.2 Unmarshaller
Similar to the Marshaller, there is the
org.springframework.oxm.Unmarshaller interface.
public interface Unmarshaller {
/**
* Unmarshals the given provided Source into an object graph.
*/
Object unmarshal(Source source)
throws XmlMappingException, IOException;
}
This interface also has one method, which reads from the given
javax.xml.transform.Source (an XML input abstraction), and returns the object
read. As with Result, Source is a tagging interface that has three concrete
implementations. Each wraps a different XML representation, as indicated in the table
below.
Source
implementation
DOMSource
org.w3c.dom.Node
SAXSource
org.xml.sax.InputSource, and
org.xml.sax.XMLReader
StreamSource
java.io.File, java.io.InputStream, or
java.io.Reader
Even though there are two separate marshalling interfaces (Marshaller and
Unmarshaller), all implementations found in Spring-WS implement both in one class.
This means that you can wire up one marshaller class and refer to it both as a marshaller
and an unmarshaller in your applicationContext.xml.
16.2.3 XmlMappingException
Spring converts exceptions from the underlying O/X mapping tool to its own exception
hierarchy with the XmlMappingException as the root exception. As can be expected,
these runtime exceptions wrap the original exception so no information will be lost.
Additionally, the MarshallingFailureException and
UnmarshallingFailureException provide a distinction between marshalling and
unmarshalling operations, even though the underlying O/X mapping tool does not do so.
The O/X Mapping exception hierarchy is shown in the following figure:
The application class uses this bean to store its settings. Besides a main method, the class
has two methods: saveSettings() saves the settings bean to a file named
settings.xml, and loadSettings() loads these settings again. A main() method
constructs a Spring application context, and calls these two methods.
import
import
import
import
import
java.io.FileInputStream;
java.io.FileOutputStream;
java.io.IOException;
javax.xml.transform.stream.StreamResult;
javax.xml.transform.stream.StreamSource;
import
import
import
import
org.springframework.context.ApplicationContext;
org.springframework.context.support.ClassPathXmlApplicationContext;
org.springframework.oxm.Marshaller;
org.springframework.oxm.Unmarshaller;
This application context uses Castor, but we could have used any of the other marshaller
instances described later in this chapter. Note that Castor does not require any further
configuration by default, so the bean definition is rather simple. Also note that the
CastorMarshaller implements both Marshaller and Unmarshaller, so we can
refer to the castorMarshaller bean in both the marshaller and unmarshaller property
of the application.
This sample application produces the following settings.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<settings foo-enabled="false"/>
16.5 JAXB
The JAXB binding compiler translates a W3C XML Schema into one or more Java classes,
a jaxb.properties file, and possibly some resource files. JAXB also offers a way to
generate a schema from annotated Java classes.
Spring supports the JAXB 2.0 API as XML marshalling strategies, following the
Marshaller and Unmarshaller interfaces described in Section 16.2, Marshaller and
Unmarshaller. The corresponding integration classes reside in the
org.springframework.oxm.jaxb package.
16.5.1 Jaxb2Marshaller
The Jaxb2Marshaller class implements both the Spring Marshaller and
Unmarshallerinterface. It requires a context path to operate, which you can set using
the contextPath property. The context path is a list of colon (:) separated Java package
names that contain schema derived classes. It also offers a classesToBeBound property,
which allows you to set an array of classes to be supported by the marshaller. Schema
validation is performed by specifying one or more schema resource to the bean, like so:
<beans>
<bean id="jaxb2Marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>org.springframework.oxm.jaxb.Flight</value>
<value>org.springframework.oxm.jaxb.Flights</value>
</list>
</property>
<property name="schema" value="classpath:org/springframework/oxm/schema.xsd"/>
</bean>
...
</beans>
Alternatively, the list of classes to bind can be provided to the marshaller via the classto-be-bound child tag:
<oxm:jaxb2-marshaller id="marshaller">
<oxm:class-to-be-bound name="org.springframework.ws.samples.airline.schema.Airport"/>
<oxm:class-to-be-bound name="org.springframework.ws.samples.airline.schema.Flight"/>
...
</oxm:jaxb2-marshaller>
Description
Required
id
no
contextPath
no
16.6 Castor
Castor XML mapping is an open source XML binding framework. It allows you to transform
the data contained in a java object model into/from an XML document. By default, it does
not require any further configuration, though a mapping file can be used to have more
control over the behavior of Castor.
For more information on Castor, refer to the Castor web site. The Spring integration
classes reside in the org.springframework.oxm.castor package.
16.6.1 CastorMarshaller
As with JAXB, the CastorMarshaller implements both the Marshaller and
Unmarshaller interface. It can be wired up as follows:
<beans>
<bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller" />
...
</beans>
16.6.2 Mapping
Although it is possible to rely on Castor's default marshalling behavior, it might be
necessary to have more control over it. This can be accomplished using a Castor mapping
file. For more information, refer to Castor XML Mapping.
The mapping can be set using the mappingLocation resource property, indicated below
with a classpath resource.
<beans>
<bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller" >
<property name="mappingLocation" value="classpath:mapping.xml" />
</bean>
</beans>
The marshaller instance can be configured in two ways, by specifying either the location of
a mapping file (through the mapping-location property), or by identifying Java POJOs
(through the target-class or target-package properties) for which there exist corresponding
XML descriptor classes. The latter way is usually used in conjunction with XML code
generation from XML schemas.
Available attributes are:
Attribute
Description
Required
id
no
encoding
no
targetclass
no
targetpackage
no
mappinglocation
no
16.7 XMLBeans
XMLBeans is an XML binding tool that has full XML Schema support, and offers full XML
Infoset fidelity. It takes a different approach to that of most other O/X mapping frameworks,
in that all classes that are generated from an XML Schema are all derived from
XmlObject, and contain XML binding information in them.
For more information on XMLBeans, refer to the XMLBeans web site . The Spring-WS
integration classes reside in the org.springframework.oxm.xmlbeans package.
16.7.1 XmlBeansMarshaller
The XmlBeansMarshaller implements both the Marshaller and Unmarshaller
interfaces. It can be configured as follows:
<beans>
<bean id="xmlBeansMarshaller" class="org.springframework.oxm.xmlbeans.XmlBeansMarshaller" />
...
</beans>
Note
Note that the XmlBeansMarshaller can only marshal objects of
type XmlObject, and not every java.lang.Object.
Description
Required
id
no
options
no
16.8 JiBX
The JiBX framework offers a solution similar to that which JDO provides for ORM: a
binding definition defines the rules for how your Java objects are converted to or from XML.
After preparing the binding and compiling the classes, a JiBX binding compiler enhances
the class files, and adds code to handle converting instances of the classes from or to
XML.
For more information on JiBX, refer to the JiBX web site. The Spring integration classes
reside in the org.springframework.oxm.jibx package.
16.8.1 JibxMarshaller
The JibxMarshaller class implements both the Marshaller and Unmarshaller
interface. To operate, it requires the name of the class to marshal in, which you can set
using the targetClass property. Optionally, you can set the binding name using the
bindingName property. In the next sample, we bind the Flights class:
<beans>
Description
Required
id
no
target-class
yes
bindingName
no
16.9 XStream
XStream is a simple library to serialize objects to XML and back again. It does not require
any mapping, and generates clean XML.
For more information on XStream, refer to the XStream web site. The Spring integration
classes reside in the org.springframework.oxm.xstream package.
16.9.1 XStreamMarshaller
The XStreamMarshaller does not require any configuration, and can be configured in
an application context directly. To further customize the XML, you can set an alias map,
which consists of string aliases mapped to classes:
<beans>
<bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
<property name="aliases">
<props>
<prop key="Flight">org.springframework.oxm.xstream.Flight</prop>
</props>
</property>
</bean>
...
</beans>
Warning
By default, XStream allows for arbitrary classes to be unmarshalled, which can result in security
vulnerabilities. As such, it is recommended to set the supportedClasses property on the
XStreamMarshaller, like so:
<bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
<property name="supportedClasses" value="org.springframework.oxm.xstream.Flight"/>
...
</bean>
This will make sure that only the registered classes are eligible for unmarshalling.
Additionally, you can register custom converters to make sure that only your supported classes can
be unmarshalled. You might want to add a CatchAllConverter as the last converter in the list, in
addition to converters that explicitly support the domain classes that should be supported. As a result,
default XStream converters with lower priorities and possible security vulnerabilities do not get
invoked.
Note
Note that XStream is an XML serialization library, not a data binding
library. Therefore, it has limited namespace support. As such, it is
rather unsuitable for usage within Web services.
AbstractController.setSynchronizeOnSession()
method. Refer to Section 9.6.1,
Understanding AOP proxies for
more information on AOP proxies
and why you cannot add advice
to final methods.
A JSP form tag library, introduced in Spring 2.0, that makes writing forms in JSP pages
much easier. For information on the tag library descriptor, see the appendix entitled
Appendix H, spring-form.tld
Beans whose lifecycle is scoped to the current HTTP request or HTTP Session. This
is not a specific feature of Spring MVC itself, but rather of the
WebApplicationContext container(s) that Spring MVC uses. These bean scopes
are described in Section 5.5.4, Request, session, and global session scopes
In the preceding example, all requests starting with /example will be handled by the
DispatcherServlet instance named example. In a Servlet 3.0+ environment, you
also have the option of configuring the Servlet container programmatically. Below is the
code based equivalent of the above web.xml example:
public class MyWebApplicationInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext container) {
ServletRegistration.Dynamic registration = container.addServlet("dispatcher", new DispatcherServlet());
registration.setLoadOnStartup(1);
registration.addMapping("/example/*");
}
}
The above is only the first step in setting up Spring Web MVC. You now need to configure
the various beans used by the Spring Web MVC framework (over and above the
DispatcherServlet itself).
As detailed in Section 5.14, Additional Capabilities of the ApplicationContext,
ApplicationContext instances in Spring can be scoped. In the Web MVC framework,
each DispatcherServlet has its own WebApplicationContext, which inherits all
the beans already defined in the root WebApplicationContext. These inherited beans
can be overridden in the servlet-specific scope, and you can define new scope-specific
beans local to a given Servlet instance.
With the above Servlet configuration in place, you will need to have a file called /WEBINF/golfing-servlet.xml in your application; this file will contain all of your Spring
Web MVC-specific components (beans). You can change the exact location of this
configuration file through a Servlet initialization parameter (see below for details).
The WebApplicationContext is an extension of the plain ApplicationContext
that has some extra features necessary for web applications. It differs from a normal
ApplicationContext in that it is capable of resolving themes (see Section 17.9,
Using themes), and that it knows which Servlet it is associated with (by having a link to
the ServletContext). The WebApplicationContext is bound in the
ServletContext, and by using static methods on the RequestContextUtils class
you can always look up the WebApplicationContext if you need access to it.
Explanation
HandlerMapping
HandlerAdapter
HandlerExceptionResolver
ViewResolver
LocaleResolver
ThemeResolver
MultipartResolver
FlashMapManager
that would have been used otherwise for that special bean type. For example if you
configure an InternalResourceViewResolver, the default list of ViewResolver
implementations is ignored.
In Section 17.15, Configuring Spring MVC you'll learn about other options for configuring
Spring MVC including MVC Java config and the MVC XML namespace both of which
provide a simple starting point and assume little knowledge of how Spring MVC works.
Regardless of how you choose to configure your application, the concepts explained in
this section are fundamental should be of help to you.
contextClass
Explanation
Class that implements
WebApplicationContext, which instantiates
the context used by this Servlet. By default, the
XmlWebApplicationContext is used.
@Controller
public class HelloWorldController {
@RequestMapping("/helloWorld")
public String helloWorld(Model model) {
model.addAttribute("message", "Hello World!");
return "helloWorld";
}
}
As you can see, the @Controller and @RequestMapping annotations allow flexible
method names and signatures. In this particular example the method accepts a Model and
returns a view name as a String, but various other method parameters and return values
can be used as explained later in this section. @Controller and @RequestMapping
and a number of other annotations form the basis for the Spring MVC implementation. This
section documents these annotations and how they are most commonly used in a Servlet
environment.
for autodetection, aligned with Spring general support for detecting component classes in
the classpath and auto-registering bean definitions for them.
To enable autodetection of such annotated controllers, you add component scanning to
your configuration. Use the spring-context schema as shown in the following XML snippet:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="org.springframework.samples.petclinic.web"/>
<!-- ... -->
</beans>
In the example, the @RequestMapping is used in a number of places. The first usage is
on the type (class) level, which indicates that all handling methods on this controller are
relative to the /appointments path. The get() method has a further
@RequestMapping refinement: it only accepts GET requests, meaning that an HTTP
GET for /appointments invokes this method. The post() has a similar refinement,
and the getNewForm() combines the definition of HTTP method and path into one, so
that GET requests for appointments/new are handled by that method.
The URI Template "/owners/{ownerId}" specifies the variable name ownerId. When
the controller handles this request, the value of ownerId is set to the value found in the
appropriate part of the URI. For example, when a request comes in for /owners/fred,
the value of ownerId is fred.
Tip
To process the @PathVariable annotation, Spring MVC needs to find the matching URI
template variable by name. You can specify it in the annotation:
@RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET)
public String findOwner(@PathVariable("ownerId") String theOwner, Model model) {
// implementation omitted
}
Or if the URI template variable name matches the method argument name you can omit that
detail. As long as your code is not compiled without debugging information, Spring MVC will
match the method argument name to the URI template variable name:
@RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET)
public String findOwner(@PathVariable String ownerId, Model model) {
// implementation omitted
}
A @PathVariable argument can be of any simple type such as int, long, Date, etc.
Spring automatically converts to the appropriate type or throws a
TypeMismatchException if it fails to do so. You can also register support for parsing
additional data types. See the section called Method Parameters And Type Conversion
and the section called Customizing WebDataBinder initialization.
Path Patterns
In addition to URI templates, the @RequestMapping annotation also supports Ant-style
path patterns (for example, /myPath/*.do). A combination of URI templates and Antstyle globs is also supported (for example, /owners/*/pets/{petId}).
Matrix Variables
The URI specification RFC 3986 defines the possibility of including name-value pairs
within path segments. There is no specific term used in the spec. The general "URI path
parameters" could be applied although the more unique "Matrix URIs", originating from an
old post by Tim Berners-Lee, is also frequently used and fairly well known. Within Spring
MVC these are referred to as matrix variables.
Matrix variables can appear in any path segment, each matrix variable separated with a ";"
(semicolon). For example: "/cars;color=red;year=2012". Multiple values may be
either "," (comma) separated "color=red,green,blue" or the variable name may be
repeated "color=red;color=green;color=blue".
If a URL is expected to contain matrix variables, the request mapping pattern must
represent them with a URI template. This ensures the request can be matched correctly
regardless of whether matrix variables are present or not and in what order they are
provided.
Below is an example of extracting the matrix variable "q":
// GET /pets/42;q=11;r=22
@RequestMapping(value = "/pets/{petId}", method = RequestMethod.GET)
public void findPet(@PathVariable String petId, @MatrixVariable int q) {
// petId == 42
// q == 11
}
Since all path segments may contain matrix variables, in some cases you need to be more
specific to identify where the variable is expected to be:
// GET /owners/42;q=11/pets/21;q=22
@RequestMapping(value = "/owners/{ownerId}/pets/{petId}", method = RequestMethod.GET)
public void findPet(
@MatrixVariable(value="q", pathVar="ownerId") int q1,
@MatrixVariable(value="q", pathVar="petId") int q2) {
// q1 == 11
// q2 == 22
}
Note that to enable the use of matrix variables, you must set the
removeSemicolonContent property of RequestMappingHandlerMapping to
false. By default it is set to false.
You can narrow the primary mapping by specifying a list of consumable media types. The
request will be matched only if the Content-Type request header matches the specified
media type. For example:
@Controller
@RequestMapping(value = "/pets", method = RequestMethod.POST, consumes="application/json")
public void addPet(@RequestBody Pet pet, Model model) {
// implementation omitted
}
Consumable media type expressions can also be negated as in !text/plain to match to all
requests other than those with Content-Type of text/plain.
Tip
The consumes condition is supported on the type and on the method
level. Unlike most other conditions, when used at the type level,
method-level consumable types override rather than extend type-level
consumable types.
Just like with consumes, producible media type expressions can be negated as in
!text/plain to match to all requests other than those with an Accept header value of
text/plain.
Tip
The produces condition is supported on the type and on the method
level. Unlike most other conditions, when used at the type level,
method-level producible types override rather than extend type-level
producible types.
The same can be done to test for request header presence/absence or to match based on
a specific request header value:
@Controller
@RequestMapping("/owners/{ownerId}")
Tip
Although you can match to Content-Type and Accept header values
using media type wild cards (for example "content-type=text/*" will
match to "text/plain" and "text/html"), it is recommended to use the
consumes and produces conditions respectively instead. They are
intended specifically for that purpose.
Note, that there is a Model parameter in between Pet and BindingResult. To get this
working you have to reorder the parameters as follows:
@RequestMapping(method = RequestMethod.POST)
public String processSubmit(@ModelAttribute("pet") Pet pet,
BindingResult result, Model model) { }
in your controller.
The following code snippet shows the usage:
@Controller
@RequestMapping("/pets")
@SessionAttributes("pet")
public class EditPetForm {
// ...
@RequestMapping(method = RequestMethod.GET)
public String setupForm(@RequestParam("petId") int petId, ModelMap model) {
Pet pet = this.clinic.loadPet(petId);
model.addAttribute("pet", pet);
return "petForm";
}
// ...
Parameters using this annotation are required by default, but you can specify that a
parameter is optional by setting @RequestParam's required attribute to false (e.g.,
@RequestParam(value="id", required=false)).
Type conversion is applied automatically if the target method parameter type is not
String. See the section called Method Parameters And Type Conversion.
class="org.springframework.http.converter.StringHttpMessageConverter"/>
<bean id="marshallingHttpMessageConverter"
class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<property name="marshaller" ref="castorMarshaller" />
<property name="unmarshaller" ref="castorMarshaller" />
</bean>
<bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller"/>
The above example will result in the text Hello World being written to the HTTP
response stream.
As with @RequestBody, Spring converts the returned object to a response body by using
an HttpMessageConverter. For more information on these converters, see the
previous section and Message Converters.
Using HttpEntity<?>
The HttpEntity is similar to @RequestBody and @ResponseBody. Besides getting
access to the request and response body, HttpEntity (and the response-specific
subclass ResponseEntity) also allows access to the request and response headers,
like so:
@RequestMapping("/something")
public ResponseEntity<String> handle(HttpEntity<byte[]> requestEntity) throws UnsupportedEncodingException {
String requestHeader = requestEntity.getHeaders().getFirst("MyRequestHeader"));
byte[] requestBody = requestEntity.getBody();
// do something with request header and body
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("MyResponseHeader", "MyValue");
return new ResponseEntity<String>("Hello World", responseHeaders, HttpStatus.CREATED);
}
The above example gets the value of the MyRequestHeader request header, and reads
the body as a byte array. It adds the MyResponseHeader to the response, writes Hello
World to the response stream, and sets the response status code to 201 (Created).
As with @RequestBody and @ResponseBody, Spring uses HttpMessageConverter
to convert from and to the request and response streams. For more information on these
converters, see the previous section and Message Converters.
@ModelAttribute methods are used to populate the model with commonly needed
attributes for example to fill a drop-down with states or with pet types, or to retrieve a
command object like Account in order to use it to represent the data on an HTML form. The
latter case is further discussed in the next section.
Note the two styles of @ModelAttribute methods. In the first, the method adds an
attribute implicitly by returning it. In the second, the method accepts a Model and adds any
number of model attributes to it. You can choose between the two styles depending on
your needs.
A controller can have any number of @ModelAttribute methods. All such methods are
invoked before @RequestMapping methods of the same controller.
@ModelAttribute methods can also be defined in an @ControllerAdviceannotated class and such methods apply to all controllers. The @ControllerAdvice
annotation is a component annotation allowing implementation classes to be autodetected
through classpath scanning.
Tip
What happens when a model attribute name is not explicitly specified?
In such cases a default name is assigned to the model attribute based
on its type. For example if the method returns an object of type
Account, the default name used is "account". You can change that
through the value of the @ModelAttribute annotation. If adding
attributes directly to the Model, use the appropriate overloaded
addAttribute(..) method - i.e., with or without an attribute name.
The @ModelAttribute annotation can be used on @RequestMapping methods as
well. In that case the return value of the @RequestMapping method is interpreted as a
model attribute rather than as a view name. The view name is derived from view name
conventions instead much like for methods returning void see Section 17.12.3, The
View - RequestToViewNameTranslator.
Using
on a method argument
Given the above example where can the Pet instance come from? There are several
options:
It may already be in the model due to use of @SessionAttributes see the
section called Using @SessionAttributes to store model attributes in the HTTP
session between requests.
It may already be in the model due to an @ModelAttribute method in the same
controller as explained in the previous section.
It may be retrieved based on a URI template variable and type converter (explained in
more detail below).
It may be instantiated using its default constructor.
An @ModelAttribute method is a common way to to retrieve an attribute from the
database, which may optionally be stored between requests through the use of
@SessionAttributes. In some cases it may be convenient to retrieve the attribute by
using an URI template variable and a type converter. Here is an example:
@RequestMapping(value="/accounts/{account}", method = RequestMethod.PUT)
public String save(@ModelAttribute("account") Account account) {
}
In this example the name of the model attribute (i.e. "account") matches the name of a URI
template variable. If you register Converter<String, Account> that can turn the
String account value into an Account instance, then the above example will work
without the need for an @ModelAttribute method.
The next step is data binding. The WebDataBinder class matches request parameter
names including query string parameters and form fields to model attribute fields by
name. Matching fields are populated after type conversion (from String to the target field
type) has been applied where necessary. Data binding and validation are covered in
Chapter 7, Validation, Data Binding, and Type Conversion. Customizing the data binding
process for a controller level is covered in the section called Customizing
WebDataBinder initialization.
As a result of data binding there may be errors such as missing required fields or type
conversion errors. To check for such errors add a BindingResult argument immediately
following the @ModelAttribute argument:
@RequestMapping(value="/owners/{ownerId}/pets/{petId}/edit", method = RequestMethod.POST)
public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) {
if (result.hasErrors()) {
return "petForm";
}
// ...
}
With a BindingResult you can check if errors were found in which case it's common to
render the same form where the errors can be shown with the help of Spring's <errors>
form tag.
In addition to data binding you can also invoke validation using your own custom validator
passing the same BindingResult that was used to record data binding errors. That
allows for data binding and validation errors to be accumulated in one place and
subsequently reported back to the user:
@RequestMapping(value="/owners/{ownerId}/pets/{petId}/edit", method = RequestMethod.POST)
public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) {
new PetValidator().validate(pet, result);
if (result.hasErrors()) {
return "petForm";
}
// ...
}
Or you can have validation invoked automatically by adding the JSR-303 @Valid
annotation:
@RequestMapping(value="/owners/{ownerId}/pets/{petId}/edit", method = RequestMethod.POST)
public String processSubmit(@Valid @ModelAttribute("pet") Pet pet, BindingResult result) {
if (result.hasErrors()) {
return "petForm";
}
// ...
}
See Section 7.8, Spring 3 Validation and Chapter 7, Validation, Data Binding, and Type
Conversion for details on how to configure and use validation.
Note
When using controller interfaces (e.g., for AOP proxying), make sure to
consistently put all your mapping annotations - such as
@RequestMapping and @SessionAttributes - on the controller
interface rather than on the implementation class.
The above filter intercepts HTTP PUT and PATCH requests with content type
application/x-www-form-urlencoded, reads the form data from the body of the
request, and wraps the ServletRequest in order to make the form data available
through the ServletRequest.getParameter*() family of methods.
Note
As HttpPutFormContentFilter consumes the body of the
request, it should not be configured for PUT or PATCH URLs that rely
on other converters for application/x-www-form-urlencoded.
This includes @RequestBody MultiValueMap<String,
String> and HttpEntity<MultiValueMap<String,
String>>.
The following code sample demonstrates how to get the value of the JSESSIONID cookie:
@RequestMapping("/displayHeaderInfo.do")
public void displayHeaderInfo(@CookieValue("JSESSIONID") String cookie)
//...
}
Type conversion is applied automatically if the target method parameter type is not
String. See the section called Method Parameters And Type Conversion.
This annotation is supported for annotated handler methods in Servlet and Portlet
environments.
localhost:8080
text/html,application/xhtml+xml,application/xml;q=0.9
fr,en-gb;q=0.7,en;q=0.3
gzip,deflate
ISO-8859-1,utf-8;q=0.7,*;q=0.7
300
The following code sample demonstrates how to get the value of the Accept-Encoding
and Keep-Alive headers:
@RequestMapping("/displayHeaderInfo.do")
public void displayHeaderInfo(@RequestHeader("Accept-Encoding") String encoding,
@RequestHeader("Keep-Alive") long keepAlive) {
//...
}
Type conversion is applied automatically if the method parameter is not String. See the
section called Method Parameters And Type Conversion.
Tip
Built-in support is available for converting a comma-separated string
into an array/collection of strings or other types known to the type
conversion system. For example a method parameter annotated with
@RequestHeader("Accept") may be of type String but also
String[] or List<String>.
This annotation is supported for annotated handler methods in Servlet and Portlet
environments.
This may be difficult to understand without any knowledge of the Servlet 3 async
processing feature. It would certainly help to read up on it. At a very minimum consider the
following basic facts:
A ServletRequest can be put in asynchronous mode by calling
request.startAsync(). The main effect of doing so is that the Servlet, as well as
any Filters, can exit but the response will remain open allowing some other thread to
complete processing.
The call to request.startAsync() returns an AsyncContext, which can be
used for further control over async processing. For example it provides the method
dispatch, which can be called from an application thread in order to "dispatch" the
request back to the Servlet container. An async dispatch is similar to a forward except
it is made from one (application) thread to another (Servlet container) thread whereas
a forward occurs synchronously in the same (Servlet container) thread.
ServletRequest provides access to the current DispatcherType, which can be
used to distinguish if a Servlet or a Filter is processing on the initial request
processing thread and when it is processing in an async dispatch.
With the above in mind, the following is the sequence of events for async request
processing with a Callable: (1) Controller returns a Callable, (2) Spring MVC starts
async processing and submits the Callable to a TaskExecutor for processing in a
separate thread, (3) the DispatcherServlet and all Filter's exit the request processing
thread but the response remains open, (4) the Callable produces a result and Spring
MVC dispatches the request back to the Servlet container, (5) the DispatcherServlet
is invoked again and processing resumes with the asynchronously produced result from
the Callable. The exact sequencing of (2), (3), and (4) may vary depending on the speed
of execution of the concurrent threads.
The sequence of events for async request processing with a DeferredResult is the
same in principal except it's up to the application to produce the asynchronous result from
some thread: (1) Controller returns a DeferredResult and saves it in some in-memory
queue or list where it can be accessed, (2) Spring MVC starts async processing, (3) the
DispatcherServlet and all configured Filter's exit the request processing thread but
the response remains open, (4) the application sets the DeferredResult from some
thread and Spring MVC dispatches the request back to the Servlet container, (5) the
DispatcherServlet is invoked again and processing resumes with the
asynchronously produced result.
Explaining the motivation for async request processing and when or why to use it are
beyond the scope of this document. For further information you may wish to read this blog
post series.
HandlerExceptionResolver instance.
The DispatcherServlet and any Filter configuration need to have the <asyncsupported>true</async-supported> sub-element. Additionally, any Filter that
also needs to get involved in async dispatches should also be configured to support the
ASYNC dispatcher type. Note that it is safe to enable the ASYNC dispatcher type for all
filters provided with the Spring Framework since they will not get involved in async
dispatches unless needed.
If using Servlet 3, Java based configuration, e.g. via WebApplicationInitializer,
you'll also need to set the "asyncSupported" flag as well as the ASYNC dispatcher type
just like with web.xml. To simplify all this configuration, consider extending
AbstractDispatcherServletInitializer or
AbstractAnnotationConfigDispatcherServletInitializer, which
automatically set those options and make it very easy to register Filter instances.
not set depends on the underlying Servlet container (e.g. 10 seconds on Tomcat). You can
also configure an AsyncTaskExecutor to use for executing Callable instances
returned from controller methods. It is highly recommended to configure this property since
by default Spring MVC uses SimpleAsyncTaskExecutor. The MVC Java config and
the MVC namespace also allow you to register CallableProcessingInterceptor
and DeferredResultProcessingInterceptor instances.
If you need to override the default timeout value for a specific DeferredResult, you can
do so by using the appropriate class constructor. Similarly, for a Callable, you can wrap
it in a WebAsyncTask and use the appropriate class constructor to customize the timeout
value. The class constructor of WebAsyncTask also allows providing an
AsyncTaskExecutor.
<property name="interceptors">
<bean class="example.MyInterceptor"/>
</property>
</bean>
<beans>
package samples;
public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter {
private int openingTime;
private int closingTime;
public void setOpeningTime(int openingTime) {
this.openingTime = openingTime;
}
public void setClosingTime(int closingTime) {
this.closingTime = closingTime;
}
public boolean preHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
Calendar cal = Calendar.getInstance();
int hour = cal.get(HOUR_OF_DAY);
if (openingTime <= hour && hour < closingTime) {
return true;
} else {
response.sendRedirect("http://host.com/outsideOfficeHours.html");
return false;
}
}
Description
AbstractCachingViewResolver
XmlViewResolver
ResourceBundleViewResolver
UrlBasedViewResolver
InternalResourceViewResolver
Convenient subclass of
UrlBasedViewResolver that supports
InternalResourceView (in effect,
Servlets and JSPs) and subclasses such as
JstlView and TilesView. You can
specify the view class for all views
generated by this resolver by using
setViewClass(..). See the Javadocs
for the UrlBasedViewResolver class for
details.
VelocityViewResolver /
FreeMarkerViewResolver
Convenient subclass of
UrlBasedViewResolver that supports
VelocityView (in effect, Velocity
templates) or FreeMarkerView
,respectively, and custom subclasses of
them.
When returning test as a logical view name, this view resolver forwards the request to
the RequestDispatcher that will send the request to /WEB-INF/jsp/test.jsp.
When you combine different view technologies in a web application, you can use the
ResourceBundleViewResolver:
<bean id="viewResolver"
class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
<property name="basename" value="views"/>
<property name="defaultParentView" value="parentView"/>
</bean>
views in the properties file extend. This way you can specify a default view class, for
example.
Note
Subclasses of AbstractCachingViewResolver cache view
instances that they resolve. Caching improves performance of certain
view technologies. It's possible to turn off the cache by setting the
cache property to false. Furthermore, if you must refresh a certain
view at runtime (for example when a Velocity template is modified), you
can use the removeFromCache(String viewName, Locale
loc) method.
If a specific view resolver does not result in a view, Spring examines the context for other
view resolvers. If additional view resolvers exist, Spring continues to inspect them until a
view is resolved. If no view resolver returns a view, Spring throws a ServletException.
The contract of a view resolver specifies that a view resolver can return null to indicate the
view could not be found. Not all view resolvers do this, however, because in some cases,
the resolver simply cannot detect whether or not the view exists. For example, the
InternalResourceViewResolver uses the RequestDispatcher internally, and
dispatching is the only way to figure out if a JSP exists, but this action can only execute
once. The same holds for the VelocityViewResolver and some others. Check the
Javadoc for the view resolver to see whether it reports non-existing views. Thus, putting an
InternalResourceViewResolver in the chain in a place other than the last, results
in the chain not being fully inspected, because the InternalResourceViewResolver
will always return a view!
If you use RedirectView and the view is created by the controller itself, it is
recommended that you configure the redirect URL to be injected into the controller so that it
is not baked into the controller but configured in the context along with the view names.
The next section discusses this process.
The special redirect: prefix allows you to accomplish this. If a view name is returned
that has the prefix redirect:, the UrlBasedViewResolver (and all subclasses) will
recognize this as a special indication that a redirect is needed. The rest of the view name
will be treated as the redirect URL.
The net effect is the same as if the controller had returned a RedirectView, but now the
controller itself can simply operate in terms of logical view names. A logical view name
such as redirect:/myapp/some/resource will redirect relative to the current Servlet
context, while a name such as
redirect:http://myhost.com/some/arbitrary/path will redirect to an
absolute URL.
17.5.4 ContentNegotiatingViewResolver
The ContentNegotiatingViewResolver does not resolve views itself but rather
delegates to other view resolvers, selecting the view that resembles the representation
requested by the client. Two strategies exist for a client to request a representation from the
server:
Use a distinct URI for each resource, typically by using a different file extension in the
URI. For example, the URI http://www.example.com/users/fred.pdf
requests a PDF representation of the user fred, and
http://www.example.com/users/fred.xml requests an XML representation.
Use the same URI for the client to locate the resource, but set the Accept HTTP
request header to list the media types that it understands. For example, an HTTP
request for http://www.example.com/users/fred with an Accept header set
to application/pdf requests a PDF representation of the user fred, while
http://www.example.com/users/fred with an Accept header set to
text/xml requests an XML representation. This strategy is known as content
negotiation.
Note
One issue with the Accept header is that it is impossible to set it in a web browser
within HTML. For example, in Firefox, it is fixed to:
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
For this reason it is common to see the use of a distinct URI for each representation
when developing browser based web applications.
To support multiple representations of a resource, Spring provides the
ContentNegotiatingViewResolver to resolve a view based on the file extension or
Note
If ContentNegotiatingViewResolver's list of ViewResolvers is
not configured explicitly, it automatically uses any ViewResolvers
defined in the application context.
The corresponding controller code that returns an Atom RSS feed for a URI of the form
http://localhost/content.atom or http://localhost/content with an
Accept header of application/atom+xml is shown below.
@Controller
public class ContentController {
private List<SampleContent> contentList = new ArrayList<SampleContent>();
@RequestMapping(value="/content", method=RequestMethod.GET)
public ModelAndView getContent() {
ModelAndView mav = new ModelAndView();
mav.setViewName("content");
mav.addObject("sampleContentList", contentList);
return mav;
}
}
Note that UriComponents is immutable and the expand() and encode() operations
return new instances if necessary.
You can also expand and encode using individual URI components:
UriComponents uriComponents =
UriComponentsBuilder.newInstance()
.scheme("http").host("example.com").path("/hotels/{hotel}/bookings/{booking}").build()
.expand("42", "21")
.encode();
Alternatively, you may choose to copy a subset of the available information up to and
including the context path:
// Re-use host, port and context path
// Append "/accounts" to the path
ServletUriComponentsBuilder ucb =
ServletUriComponentsBuilder.fromContextPath(request).path("/accounts").build()
can also have the literal part of the servlet mapping included:
// Re-use host, port, context path
// Append the literal part of the servlet mapping to the path
// Append "/accounts" to the path
ServletUriComponentsBuilder ucb =
ServletUriComponentsBuilder.fromServletMapping(request).path("/accounts").build()
17.8.1 AcceptHeaderLocaleResolver
This locale resolver inspects the accept-language header in the request that was sent
by the client (e.g., a web browser). Usually this header field contains the locale of the
client's operating system.
17.8.2 CookieLocaleResolver
This locale resolver inspects a Cookie that might exist on the client to see if a locale is
specified. If so, it uses the specified locale. Using the properties of this locale resolver, you
can specify the name of the cookie as well as the maximum age. Find below an example of
defining a CookieLocaleResolver.
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
<property name="cookieName" value="clientlanguage"/>
<!-- in seconds. If set to -1, the cookie is not persisted (deleted when browser shuts down) -->
<property name="cookieMaxAge" value="100000">
</bean>
Default
cookieName
classname +
LOCALE
Description
The name of the cookie
cookiePath
cookiePath
17.8.3 SessionLocaleResolver
The SessionLocaleResolver allows you to retrieve locales from the session that
might be associated with the user's request.
17.8.4 LocaleChangeInterceptor
You can enable changing of locales by adding the LocaleChangeInterceptor to one
of the handler mappings (see Section 17.4, Handler mappings). It will detect a parameter
in the request and change the locale. It calls setLocale() on the LocaleResolver
that also exists in the context. The following example shows that calls to all *.view
resources containing a parameter named siteLanguage will now change the locale. So,
for example, a request for the following URL, http://www.sf.net/home.view?
siteLanguage=nl will change the site language to Dutch.
<bean id="localeChangeInterceptor"
class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="siteLanguage"/>
</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 bean="localeChangeInterceptor"/>
</list>
</property>
<property name="mappings">
<value>/**/*.view=someController</value>
</property>
</bean>
background=/themes/cool/img/coolBg.jpg
The keys of the properties are the names that refer to the themed elements from view code.
For a JSP, you typically do this using the spring:theme custom tag, which is very
similar to the spring:message tag. The following JSP fragment uses the theme defined
in the previous example to customize the look and feel:
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<html>
<head>
<link rel="stylesheet" href="<spring:theme code='styleSheet'/>" type="text/css"/>
</head>
<body style="background=<spring:theme code='background'/>">
...
</body>
</html>
Description
Selects a fixed theme, set using the
defaultThemeName property.
to the web application's context. Each request is inspected to see if it contains a multipart.
If no multipart is found, the request continues as expected. If a multipart is found in the
request, the MultipartResolver that has been declared in your context is used. After
that, the multipart attribute in your request is treated like any other attribute.
Of course you also need to put the appropriate jars in your classpath for the multipart
resolver to work. In the case of the CommonsMultipartResolver, you need to use
commons-fileupload.jar.
When the Spring DispatcherServlet detects a multi-part request, it activates the
resolver that has been declared in your context and hands over the request. The resolver
then wraps the current HttpServletRequest into a
MultipartHttpServletRequest that supports multipart file uploads. Using the
MultipartHttpServletRequest, you can get information about the multiparts
contained by this request and actually get access to the multipart files themselves in your
controllers.
The next step is to create a controller that handles the file upload. This controller is very
similar to a normal annotated @Controller, except that we use
MultipartHttpServletRequest or MultipartFile in the method parameters:
@Controller
public class FileUploadController {
@RequestMapping(value = "/form", method = RequestMethod.POST)
public String handleFormUpload(@RequestParam("name") String name,
@RequestParam("file") MultipartFile file) {
if (!file.isEmpty()) {
byte[] bytes = file.getBytes();
// store the bytes somewhere
return "redirect:uploadSuccess";
} else {
return "redirect:uploadFailure";
}
}
}
Note how the @RequestParam method parameters map to the input elements declared in
the form. In this example, nothing is done with the byte[], but in practice you can save it
in a database, store it on the file system, and so on.
When using Servlet 3.0 multipart parsing you can also use
javax.servlet.http.Part for the method parameter:
@Controller
public class FileUploadController {
@RequestMapping(value = "/form", method = RequestMethod.POST)
public String handleFormUpload(@RequestParam("name") String name,
@RequestParam("file") Part file) {
InputStream inputStream = file.getInputStream();
// store bytes from uploaded file somewhere
return "redirect:uploadSuccess";
}
}
17.11.2 @ExceptionHandler
The HandlerExceptionResolver interface and the
SimpleMappingExceptionResolver implementations allow you to map Exceptions
to specific views declaratively along with some optional Java logic before forwarding to
those views. However, in some cases, especially when relying on @ResponseBody
methods rather than on view resolution, it may be more convenient to directly set the status
of the response and optionally write error content to the body of the response.
You can do that with @ExceptionHandler methods. When declared within a controller
such methods apply to exceptions raised by @RequestMapping methods of that
contoroller (or any of its sub-classes). You can also declare an @ExceptionHandler
method within an @ControllerAdvice class in which case it handles exceptions from
@RequestMapping methods from any controller. The @ControllerAdvice annotation
is a component annotation, which can be used with classpath scanning. It is automatically
enabled when using the MVC namespace and the MVC Java config, or otherwise
depending on whether the ExceptionHandlerExceptionResolver is configured or
not. Below is an example of a controller-local @ExceptionHandler method:
@Controller
public class SimpleController {
// @RequestMapping methods omitted ...
@ExceptionHandler(IOException.class)
public ResponseEntity<String> handleIOException(IOException ex) {
// prepare responseEntity
return responseEntity;
}
}
BindException
ConversionNotSupportedException
HttpMediaTypeNotAcceptableException
HttpMediaTypeNotSupportedException
HttpMessageNotReadableException
HttpMessageNotWritableException
HttpRequestMethodNotSupportedException
MethodArgumentNotValidException
MissingServletRequestParameterException
MissingServletRequestPartException
NoSuchRequestHandlingMethodException
TypeMismatchException
response while your application may need to add developer-friendly content to every error
response for example when providing a REST API. You can prepare a ModelAndView
and render error content through view resolution -- i.e. by configuring a
ContentNegotiatingViewResolver, MappingJacksonJsonView, and so on.
However, you may prefer to use @ExceptionHandler methods instead.
If you prefer to write error content via @ExceptionHandler methods you can extend
ResponseEntityExceptionHandler instead. This is a convenient base for
@ControllerAdvice classes providing an @ExceptionHandler method to handle
standard Spring MVC exceptions and return ResponseEntity. That allows you to
customize the response and write error content with message converters. See the Javadoc
of ResponseEntityExceptionHandler for more details.
Note that the actual location for the error page can be a JSP page or some other URL
within the container including one handled through an @Controller method:
When writing error information, the status code and the error message set on the
HttpServletResponse can be accessed through request attributes in a controller:
@Controller
public class ErrorController {
@RequestMapping(value="/error", produces="application/json")
@ResponseBody
public Map<String, Object> handle(HttpServletRequest request) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("status", request.getAttribute("javax.servlet.error.status_code"));
map.put("reason", request.getAttribute("javax.servlet.error.message"));
return map;
}
}
or in a JSP:
<%@ page contentType="application/json" pageEncoding="UTF-8"%>
{
status:<%=request.getAttribute("javax.servlet.error.status_code") %>,
reason:<%=request.getAttribute("javax.servlet.error.message") %>
}
just what they (the projects) need, and Spring Web MVC now has explicit support for
convention over configuration. What this means is that if you establish a set of naming
conventions and suchlike, you can substantially cut down on the amount of configuration
that is required to set up handler mappings, view resolvers, ModelAndView instances,
etc. This is a great boon with regards to rapid prototyping, and can also lend a degree of
(always good-to-have) consistency across a codebase should you choose to move forward
with it into production.
Convention-over-configuration support addresses the three core areas of MVC: models,
views, and controllers.
Here is a snippet from the corresponding Spring Web MVC configuration file:
<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/>
<bean id="viewShoppingCart" class="x.y.z.ViewShoppingCartController">
<!-- inject dependencies as required... -->
</bean>
implementations.
The ModelAndView class uses a ModelMap class that is a custom Map implementation
that automatically generates a key for an object when an object is added to it. The strategy
for determining the name for an added object is, in the case of a scalar object such as
User, to use the short class name of the object's class. The following examples are names
that are generated for scalar objects put into a ModelMap instance.
An x.y.User instance added will have the name user generated.
An x.y.Registration instance added will have the name registration
generated.
An x.y.Foo instance added will have the name foo generated.
A java.util.HashMap instance added will have the name hashMap generated.
You probably want to be explicit about the name in this case because hashMap is
less than intuitive.
Adding null will result in an IllegalArgumentException being thrown. If the
object (or objects) that you are adding could be null, then you will also want to be
explicit about the name.
The strategy for generating a name after adding a
Set or a List is to peek into the collection, take
the short class name of the first object in the
collection, and use that with List appended to
the name. The same applies to arrays although
with arrays it is not necessary to peek into the
array contents. A few examples will make the
semantics of name generation for collections
clearer:
An x.y.User[] array with zero or more
x.y.User elements added will have the
name userList generated.
An x.y.Foo[] array with zero or more
What, no automatic
pluralization?
Spring Web MVC's conventionover-configuration support does
not support automatic
pluralization. That is, you cannot
add a List of Person objects
to a ModelAndView and have
the generated name be
people .
This decision was made after
some debate, with the Principle
of Least Surprise winning out in
the end.
The above example is for an application that uses Java-based Spring configuration. If
using XML-based Spring configuration, extend directly from
AbstractDispatcherServletInitializer:
public class MyWebAppInitializer extends AbstractDispatcherServletInitializer {
@Override
protected WebApplicationContext createRootApplicationContext() {
return null;
}
@Override
protected WebApplicationContext createServletApplicationContext() {
XmlWebApplicationContext cxt = new XmlWebApplicationContext();
cxt.setConfigLocation("/WEB-INF/spring/dispatcher-config.xml");
return cxt;
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
Each filter is added with a default name based on its concrete type and automatically
mapped to the DispatcherServlet.
The isAsyncSupported protected method of
AbstractDispatcherServletInitializer provides a single place to enable
async support on the DispatcherServlet and all filters mapped to it. By default this
flag is set to true.
You can choose either the MVC Java config or the MVC namespace depending on your
preference. Also as you will see further below, with the MVC Java config it is easier to see
the underlying configuration as well as to make fine-grained customizations directly to the
created Spring MVC beans. But let's start from the beginning.
17.15.1 Enabling the MVC Java Config or the MVC XML Namespace
To enable MVC Java config add the annotation @EnableWebMvc to one of your
@Configuration classes:
@Configuration
@EnableWebMvc
public class WebConfig {
}
<mvc:interceptor>
<mapping path="/**"/>
<exclude-mapping path="/admin/**"/>
<bean class="org.springframework.web.servlet.theme.ThemeChangeInterceptor" />
</mvc:interceptor>
<mvc:interceptor>
<mapping path="/secure/*"/>
<bean class="org.example.SecurityInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
In the MVC namespace, the <mvc:annotation-driven> element has a contentnegotiation-manager attribute, which expects a ContentNegotiationManager
that in turn can be created with a ContentNegotiationManagerFactoryBean:
<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" />
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorPathExtension" value="false" />
<property name="favorParameter" value="true" />
<property name="mediaTypes" >
<value>
json=application/json
xml=application/xml
</value>
</property>
</bean>
If not using the MVC Java config or the MVC namespace, you'll need to create an instance
of ContentNegotiationManager and use it to configure
RequestMappingHandlerMapping for request mapping purposes, and
RequestMappingHandlerAdapter and
ExceptionHandlerExceptionResolver for content negotiation purposes.
Note that ContentNegotiatingViewResolver now can also be configured with a
ContentNegotiatingViewResolver, so you can use one instance throughout
Spring MVC.
In more advanced cases, it may be useful to configure multiple
ContentNegotiationManager instances that in turn may contain custom
ContentNegotiationStrategy implementations. For example you could configure
To serve these resources with a 1-year future expiration to ensure maximum use of the
browser cache and a reduction in HTTP requests made by the browser:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/public-resources/").setCachePeriod(31556926);
}
}
And in XML:
<mvc:resources mapping="/resources/**" location="/public-resources/" cache-period="31556926"/>
And in XML:
<mvc:resources mapping="/resources/**" location="/, classpath:/META-INF/public-web-resources/"/>
When serving resources that may change when a new version of the application is
deployed, it is recommended that you incorporate a version string into the mapping pattern
used to request the resources, so that you may force clients to request the newly deployed
version of your application's resources. Such a version string can be parameterized and
accessed using SpEL so that it may be easily managed in a single place when deploying
new versions.
As an example, let's consider an application that uses a performance-optimized custom
build (as recommended) of the Dojo JavaScript library in production, and that the build is
generally deployed within the web application at a path of /publicresources/dojo/dojo.js. Since different parts of Dojo may be incorporated into the
custom build for each new version of the application, the client web browsers need to be
forced to re-download that custom-built dojo.js resource any time a new version of the
application is deployed. A simple way to achieve this would be to manage the version of
the application in a properties file, such as:
application.version=1.0.0
and then to make the properties file's values accessible to SpEL as a bean using the
util:properties tag:
<util:properties id="applicationProps" location="/WEB-INF/spring/application.properties"/>
With the application version now accessible via SpEL, we can incorporate this into the use
of the resources tag:
<mvc:resources mapping="/resources-#{applicationProps['application.version']}/**" location="/public-resources/"/>
In Java, you can use the @PropertySouce annotation and then inject the
Environment abstraction for access to all defined properties:
@Configuration
@EnableWebMvc
@PropertySource("/WEB-INF/spring/application.properties")
public class WebConfig extends WebMvcConfigurerAdapter {
and finally, to request the resource with the proper URL, we can take advantage of the
Spring JSP tags:
<spring:eval expression="@applicationProps['application.version']" var="applicationVersion"/>
<spring:url value="/resources-{applicationVersion}" var="resourceUrl">
<spring:param name="applicationVersion" value="${applicationVersion}"/>
</spring:url>
<script src="${resourceUrl}/dojo/dojo.js" type="text/javascript"> </script>
17.15.7 mvc:default-servlet-handler
This tag allows for mapping the DispatcherServlet to "/" (thus overriding the mapping
of the container's default Servlet), while still allowing static resource requests to be
handled by the container's default Servlet. It configures a
DefaultServletHttpRequestHandler with a URL mapping of "/**" and the lowest
priority relative to other URL mappings.
This handler will forward all requests to the default Servlet. Therefore it is important that it
remains last in the order of all other URL HandlerMappings. That will be the case if you
use <mvc:annotation-driven> or alternatively if you are setting up your own
customized HandlerMapping instance be sure to set its order property to a value lower
than that of the DefaultServletHttpRequestHandler, which is
Integer.MAX_VALUE.
To enable the feature using the default setup use:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
Or in XML:
<mvc:default-servlet-handler/>
The caveat to overriding the "/" Servlet mapping is that the RequestDispatcher for the
default Servlet must be retrieved by name rather than by path. The
DefaultServletHttpRequestHandler will attempt to auto-detect the default Servlet
for the container at startup time, using a list of known names for most of the major Servlet
containers (including Tomcat, Jetty, GlassFish, JBoss, Resin, WebLogic, and
WebSphere). If the default Servlet has been custom configured with a different name, or if a
different Servlet container is being used where the default Servlet name is unknown, then
the default Servlet's name must be explicitly provided as in the following example:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable("myCustomDefaultServlet");
}
Or in XML:
<mvc:default-servlet-handler default-servlet-name="myCustomDefaultServlet"/>
Note that modifying beans in this way does not prevent you from using any of the higherlevel constructs shown earlier in this section.
Configuration
The form tag library comes bundled in spring-webmvc.jar. The library descriptor is
called spring-form.tld.
To use the tags from this library, add the following directive to the top of your JSP page:
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
... where form is the tag name prefix you want to use for the tags from this library.
<table>
<tr>
<td>First Name:</td>
<td><form:input path="firstName" /></td>
</tr>
<tr>
<td>Last Name:</td>
<td><form:input path="lastName" /></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="Save Changes" />
</td>
</tr>
</table>
</form:form>
The firstName and lastName values are retrieved from the command object placed in
the PageContext by the page controller. Keep reading to see more complex examples of
how inner tags are used with the form tag.
The generated HTML looks like a standard form:
<form method="POST">
<table>
<tr>
<td>First Name:</td>
<td><input name="firstName" type="text" value="Harry"/></td>
</tr>
<tr>
<td>Last Name:</td>
<td><input name="lastName" type="text" value="Potter"/></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="Save Changes" />
</td>
</tr>
</table>
</form>
The preceding JSP assumes that the variable name of the form backing object is
'command'. If you have put the form backing object into the model under another name
(definitely a best practice), then you can bind the form to the named variable like so:
<form:form commandName="user">
<table>
<tr>
<td>First Name:</td>
<td><form:input path="firstName" /></td>
</tr>
<tr>
<td>Last Name:</td>
<td><form:input path="lastName" /></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="Save Changes" />
</td>
</tr>
</table>
</form:form>
There are 3 approaches to the checkbox tag which should meet all your checkbox needs.
Approach One - When the bound value is of type java.lang.Boolean, the
input(checkbox) is marked as 'checked' if the bound value is true. The value
attribute corresponds to the resolved value of the setValue(Object) value
property.
Approach Two - When the bound value is of type array or
java.util.Collection, the input(checkbox) is marked as 'checked' if the
configured setValue(Object) value is present in the bound Collection.
Approach Three - For any other bound value type, the input(checkbox) is marked
as 'checked' if the configured setValue(Object) is equal to the bound value.
Note that regardless of the approach, the same HTML structure is generated. Below is an
HTML snippet of some checkboxes:
<tr>
<td>Interests:</td>
<td>
Quidditch: <input name="preferences.interests" type="checkbox" value="Quidditch"/>
<input type="hidden" value="1" name="_preferences.interests"/>
Herbology: <input name="preferences.interests" type="checkbox" value="Herbology"/>
<input type="hidden" value="1" name="_preferences.interests"/>
Defence Against the Dark Arts: <input name="preferences.interests" type="checkbox"
value="Defence Against the Dark Arts"/>
What you might not expect to see is the additional hidden field after each checkbox. When
a checkbox in an HTML page is not checked, its value will not be sent to the server as part
of the HTTP request parameters once the form is submitted, so we need a workaround for
this quirk in HTML in order for Spring form data binding to work. The checkbox tag
follows the existing Spring convention of including a hidden parameter prefixed by an
underscore ("_") for each checkbox. By doing this, you are effectively telling Spring that
the checkbox was visible in the form and I want my object to which the form data will be
bound to reflect the state of the checkbox no matter what .
This example assumes that the "interestList" is a List available as a model attribute
containing strings of the values to be selected from. In the case where you use a Map, the
map entry key will be used as the value and the map entry's value will be used as the label
to be displayed. You can also use a custom object where you can provide the property
names for the value using "itemValue" and the label using "itemLabel".
<tr>
<td>Sex:</td>
<td><form:radiobuttons path="sex" items="${sexOptions}"/></td>
</tr>
Please note that by default, the password value is not shown. If you do want the password
value to be shown, then set the value of the 'showPassword' attribute to true, like so.
<tr>
<td>Password:</td>
<td>
<form:password path="password" value="^76525bvHGq" showPassword="true" />
</td>
</tr>
If the User's skill were in Herbology, the HTML source of the 'Skills' row would look like:
<tr>
<td>Skills:</td>
<td><select name="skills" multiple="true">
<option value="Potions">Potions</option>
<option value="Herbology" selected="selected">Herbology</option>
<option value="Quidditch">Quidditch</option></select>
</td>
</tr>
If the User's house was in Gryffindor, the HTML source of the 'House' row would look
like:
<tr>
<td>House:</td>
<td>
<select name="house">
<option value="Gryffindor" selected="selected">Gryffindor</option>
<option value="Hufflepuff">Hufflepuff</option>
<option value="Ravenclaw">Ravenclaw</option>
<option value="Slytherin">Slytherin</option>
</select>
</td>
</tr>
If the User lived in the UK, the HTML source of the 'Country' row would look like:
<tr>
<td>Country:</td>
<td>
<select name="country">
<option value="-">--Please Select</option>
<option value="AT">Austria</option>
<option value="UK" selected="selected">United Kingdom</option>
<option value="US">United States</option>
</select>
</td>
</tr>
As the example shows, the combined usage of an option tag with the options tag
generates the same standard HTML, but allows you to explicitly specify a value in the JSP
that is for display only (where it belongs) such as the default string in the example: "-Please Select".
The items attribute is typically populated with a collection or array of item objects.
itemValue and itemLabel simply refer to bean properties of those item objects, if
specified; otherwise, the item objects themselves will be stringified. Alternatively, you may
specify a Map of items, in which case the map keys are interpreted as option values and
the map values correspond to option labels. If itemValue and/or itemLabel happen to
be specified as well, the item value property will apply to the map key and the item label
property will apply to the map value.
If we choose to submit the 'house' value as a hidden one, the HTML would look like:
<input name="house" type="hidden" value="Gryffindor"/>
in your controller or those that were created by any validators associated with your
controller.
Let's assume we want to display all error messages for the firstName and lastName
fields once we submit the form. We have a validator for instances of the User class called
UserValidator.
public class UserValidator implements Validator {
public boolean supports(Class candidate) {
return User.class.isAssignableFrom(candidate);
}
public void validate(Object obj, Errors errors) {
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "firstName", "required", "Field is required.");
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "lastName", "required", "Field is required.");
}
}
If we submit a form with empty values in the firstName and lastName fields, this is
what the HTML would look like:
<form method="POST">
<table>
<tr>
<td>First Name:</td>
<td><input name="firstName" type="text" value=""/></td>
<%-- Associated errors to firstName field displayed --%>
<td><span name="firstName.errors">Field is required.</span></td>
</tr>
<tr>
<td>Last Name:</td>
<td><input name="lastName" type="text" value=""/></td>
<%-- Associated errors to lastName field displayed --%>
<td><span name="lastName.errors">Field is required.</span></td>
</tr>
<tr>
<td colspan="3">
<input type="submit" value="Save Changes" />
</td>
</tr>
</table>
</form>
What if we want to display the entire list of errors for a given page? The example below
shows that the errors tag also supports some basic wildcarding functionality.
path="*" - displays all errors
path="lastName" - displays all errors associated with the lastName field
if path is omitted - object errors only are displayed
The example below will display a list of errors at the top of the page, followed by fieldspecific errors next to the fields:
<form:form>
<form:errors path="*" cssClass="errorBox" />
<table>
<tr>
<td>First Name:</td>
<td><form:input path="firstName" /></td>
<td><form:errors path="firstName" /></td>
</tr>
<tr>
<td>Last Name:</td>
<td><form:input path="lastName" /></td>
<td><form:errors path="lastName" /></td>
</tr>
<tr>
<td colspan="3">
<input type="submit" value="Save Changes" />
</td>
</tr>
</table>
</form:form>
This will actually perform an HTTP POST, with the 'real' DELETE method hidden behind a
request parameter, to be picked up by the HiddenHttpMethodFilter, as defined in
web.xml:
<filter>
<filter-name>httpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>httpMethodFilter</filter-name>
<servlet-name>petclinic</servlet-name>
</filter-mapping>
HTML5 Tags
Starting with Spring 3, the Spring form tag library allows entering dynamic attributes, which
means you can enter any HTML5 specific attributes.
In Spring 3.1, the form input tag supports entering a type attribute other than 'text'. This is
intended to allow rendering new HTML5 specific input types such as 'email', 'date', 'range',
and others. Note that entering type='text' is not required since 'text' is the default type.
18.3 Tiles
It is possible to integrate Tiles - just as any other view technology - in web applications
using Spring. The following describes in a broad way how to do this.
NOTE: This section focuses on Spring's support for Tiles 2 (the standalone version of
Tiles, requiring Java 5+) in the
org.springframework.web.servlet.view.tiles2 package as as well as Tiles
3 in the org.springframework.web.servlet.view.tiles3 package. Spring also
continues to support Tiles 1.x (a.k.a. "Struts Tiles", as shipped with Struts 1.1+; compatible
with Java 1.4) in the original org.springframework.web.servlet.view.tiles
package.
18.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.
Tiles version 2.1.2 or higher
Commons BeanUtils
Commons Digester
Commons Logging
As you can see, there are five files containing definitions, which are all located in the
'WEB-INF/defs' directory. At initialization of the WebApplicationContext, the files
will be loaded and the definitions factory will be initialized. After that has been done, the
Tiles includes in the definition files can be used as views within your Spring web
application. To be able to use the views you have to have a ViewResolver just as with
any other view technology used with Spring. Below you can find two possibilities, the
UrlBasedViewResolver and the ResourceBundleViewResolver.
UrlBasedViewResolver
The UrlBasedViewResolver instantiates the given viewClass for each view it has to
resolve.
<bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView"/>
</bean>
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"/>
</bean>
...
welcomeView.(class)=org.springframework.web.servlet.view.tiles2.TilesView
welcomeView.url=welcome (this is the name of a Tiles definition)
vetsView.(class)=org.springframework.web.servlet.view.tiles2.TilesView
vetsView.url=vetsView (again, this is the name of a Tiles definition)
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 easily mix
different view technologies.
Note that the TilesView class for Tiles 2 supports JSTL (the JSP Standard Tag Library)
out of the box, whereas there is a separate TilesJstlView subclass in the Tiles 1.x
support.
SimpleSpringPreparerFactory and SpringBeanPreparerFactory
As an advanced feature, Spring also supports two special Tiles 2 PreparerFactory
implementations. Check out the Tiles documentation for details on how to use
ViewPreparer references in your Tiles definition files.
Specify SimpleSpringPreparerFactory to autowire ViewPreparer instances based
on specified preparer classes, applying Spring's container callbacks as well as applying
configured Spring BeanPostProcessors. If Spring's context-wide annotation-config has
been activated, annotations in ViewPreparer classes will be automatically detected and
applied. Note that this expects preparer classes in the Tiles definition files, just like the
default PreparerFactory does.
Specify SpringBeanPreparerFactory to operate on specified preparer names
instead of classes, obtaining the corresponding Spring bean from the DispatcherServlet's
application context. The full bean creation process will be in the control of the Spring
application context in this case, allowing for the use of explicit dependency injection
configuration, scoped beans etc. Note that you need to define one Spring bean definition
per preparer name (as used in your Tiles definitions).
<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/defs/general.xml</value>
<value>/WEB-INF/defs/widgets.xml</value>
<value>/WEB-INF/defs/administrator.xml</value>
<value>/WEB-INF/defs/customer.xml</value>
<value>/WEB-INF/defs/templates.xml</value>
</list>
</property>
<!-- resolving preparer names as Spring bean definition names -->
<property name="preparerFactoryClass"
value="org.springframework.web.servlet.view.tiles2.SpringBeanPreparerFactory"/>
</bean>
18.4.1 Dependencies
Your web application will need to include velocity-1.x.x.jar or freemarker2.x.jar in order to work with Velocity or FreeMarker respectively and commonscollections.jar is required for Velocity. Typically they are included in the WEBINF/lib folder where they are guaranteed to be found by a Java EE server and added to
the classpath for your application. It is of course assumed that you already have the
spring-webmvc.jar in your 'WEB-INF/lib' directory too! 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
Note
For non web-apps add a VelocityConfigurationFactoryBean
or a FreeMarkerConfigurationFactoryBean to your
application context definition file.
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"/>
</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.
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
java.util.Properties object and the freemarkerVariables property requires a
java.util.Map.
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/freemarker/"/>
<property name="freemarkerVariables">
<map>
<entry key="xml_escape" value-ref="fmXmlEscape"/>
</map>
</property>
</bean>
See the FreeMarker documentation for details of settings and variables as they apply to the
Configuration object.
Simple binding
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>
<!-- freemarker macros have to be imported into a namespace. We strongly
recommend sticking to 'spring' -->
<#import "/spring.ftl" as spring />
<html>
...
<form action="" method="POST">
Name:
<@spring.bind "command.name" />
<input type="text"
name="${spring.status.expression}"
value="${spring.status.value?default("")}" /><br>
<#list spring.status.errorMessages as error> <b>${error}</b> <br> </#list>
<br>
...
<input type="submit" value="submit"/>
</form>
...
</html>
VTL definition
FTL definition
message (output a
string from a
resource bundle
based on the code
parameter)
#springMessage($code)
<@spring.message code/>
messageText
(output a string from
a resource bundle
based on the code
parameter, falling
back to the value of
the default
parameter)
#springMessageText($code
$text)
<@spring.messageText code,
text/>
#springUrl($relativeUrl)
<@spring.url relativeUrl/>
formInput (standard
input field for
gathering user input)
#springFormInput($path
$attributes)
<@spring.formInput path,
attributes, fieldType/>
formHiddenInput *
(hidden input field for #springFormHiddenInput($path
$attributes)
submitting non-user
input)
<@spring.formHiddenInput
path, attributes/>
formPasswordInput
* (standard input field
for gathering
#springFormPasswordInput($path <@spring.formPasswordInput
passwords. Note that $attributes)
path, attributes/>
no value will ever be
populated in fields of
this type)
formTextarea (large
text field for
gathering long,
freeform text input)
#springFormTextarea($path
$attributes)
<@spring.formTextarea
path, attributes/>
formSingleSelect
(drop down box of
options allowing a
single required value
to be selected)
<@spring.formSingleSelect
#springFormSingleSelect( $path
path, options,
$options $attributes)
attributes/>
formMultiSelect (a
list box of options
allowing the user to
select 0 or more
values)
#springFormMultiSelect($path
$options $attributes)
<@spring.formMultiSelect
path, options,
attributes/>
formRadioButtons
(a set of radio
#springFormRadioButtons($path
buttons allowing a
$options $separator
single selection to be $attributes)
made from the
available choices)
<@spring.formRadioButtons
path, options separator,
attributes/>
formCheckboxes (a
set of checkboxes
allowing 0 or more
values to be
selected)
#springFormCheckboxes($path
$options $separator
$attributes)
<@spring.formCheckboxes
path, options, separator,
attributes/>
formCheckbox (a
single checkbox)
#springFormCheckbox($path
$attributes)
<@spring.formCheckbox
path, attributes/>
showErrors
(simplify display of
validation errors for
the bound field)
#springShowErrors($separator
$classOrStyle)
<@spring.showErrors
separator, classOrStyle/>
* In FTL (FreeMarker), these two macros are not actually required as you can use the
normal formInput macro, specifying 'hidden' or 'password' as the value for the
fieldType parameter.
The parameters to any of the above macros have consistent meanings:
path: the name of the field to bind to (ie "command.name")
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 behavior. 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.
Input Fields
<!-- the Name field example from above using form macros in VTL -->
...
Name:
#springFormInput("command.name" "")<br>
#springShowErrors("<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 displaying 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.
Selection Fields
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'.
...
Town:
<@spring.formRadioButtons "command.address.town", cityMap, "" /><br><br>
This renders a line of radio buttons, one for each value in cityMap using the separator "".
No additional attributes are supplied (the last parameter to the macro is missing). The
cityMap uses the same String for each key-value pair in the map. The map's keys are what
the form actually submits as POSTed request parameters, map values are the labels that
the user sees. In the example above, given a list of three well known cities and a default
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");
Map m = new HashMap();
m.put("cityMap", cityMap);
return m;
}
The code would now produce output where the radio values are the relevant codes but the
user still sees the more user friendly city names.
Town:
<input type="radio" name="address.town" value="LDN"
>
London
<input type="radio" name="address.town" value="PRS"
checked="checked"
>
Paris
<input type="radio" name="address.town" value="NYC"
>
New York
Any tags generated by the Spring macros will now be XHTML compliant after processing
this directive.
In similar fashion, HTML escaping can be specified per field:
<#-- until this point, default HTML escaping is used -->
<#assign htmlEscape = true in spring>
<#-- next field will use HTML escaping -->
<@spring.formInput "command.name" />
<#assign htmlEscape = false in spring>
<#-- all future fields will be bound with HTML escaping off -->
18.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 Web MVC application.
Bean definitions
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"/>
So far we've done nothing that's XSLT specific. The model data has been created in the
same way as you would for any other Spring MVC application. Depending on the
configuration of the application now, that list of words could be rendered by JSP/JSTL by
having them added as request attributes, or they could be handled by Velocity by adding
the object to the VelocityContext. In order to have XSLT render them, they of course
have to be converted into an XML document somehow. There are software packages
available that will automatically 'domify' an object graph, but within Spring, you have
complete flexibility to create the DOM from your model in any way you choose. This
prevents the transformation of XML playing too great a part in the structure of your model
data which is a danger when using tools to manage the domification process.
package xslt;
// imports omitted for brevity
public class HomePage extends AbstractXsltView {
protected Source createXsltSource(Map model, String rootName, HttpServletRequest
request, HttpServletResponse response) throws Exception {
Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
Element root = document.createElement(rootName);
List words = (List) model.get("wordList");
for (Iterator it = words.iterator(); it.hasNext();) {
String nextWord = (String) it.next();
Element wordNode = document.createElement("word");
Text textNode = document.createTextNode(nextWord);
wordNode.appendChild(textNode);
root.appendChild(wordNode);
}
return new DOMSource(root);
}
}
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 getParameters() method of the AbstractXsltView class and return a
Map of the name/value pairs. If your parameters need to derive information from the current
request, you can override the getParameters(HttpServletRequest request)
method instead.
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 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 createXsltSource(..) method(s).
Document transformation
Finally, we have the XSLT code used for transforming the above document. As shown in
the above 'views.properties' file, the stylesheet is called 'home.xslt' and it
lives in the war file in the 'WEB-INF/xsl' directory.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" omit-xml-declaration="yes"/>
<xsl:template match="/">
<html>
<head><title>Hello!</title></head>
<body>
<h1>My First Words</h1>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="word">
<xsl:value-of select="."/><br/>
</xsl:template>
</xsl:stylesheet>
18.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 Java EE containers will also make
them available by default, but it's a possible source of errors to be aware of.
If you want to start with a template spreadsheet or a fillable PDF form to add your model
data to, specify the location as the 'url' property in the view definition
Controller code
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!
And the following is a view generating the same Excel file, now using JExcelApi:
package excel;
// imports omitted for brevity
public class HomePage extends AbstractJExcelView {
protected void buildExcelDocument(Map model,
WritableWorkbook wb,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
WritableSheet sheet = wb.createSheet("Spring", 0);
sheet.addCell(new Label(0, 0, "Spring-Excel test"));
List words = (List) model.get("wordList");
for (int i = 0; i < words.size(); i++) {
sheet.addCell(new Label(2+i, 0, (String) words.get(i)));
}
}
}
Note the differences between the APIs. We've found that the JExcelApi is somewhat more
intuitive, and furthermore, JExcelApi has slightly better image-handling capabilities. There
have been memory problems with large Excel files when using JExcelApi however.
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 automatically when you request the
same page as before.
Once again, amend the controller to return the pdf view with 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.
18.7 JasperReports
JasperReports (http://jasperreports.sourceforge.net) is a powerful open-source reporting
engine that supports the creation of report designs using an easily understood XML file
format. JasperReports is capable of rendering reports in four different formats: CSV, Excel,
HTML and PDF.
18.7.1 Dependencies
Your application will need to include the latest release of JasperReports, which at the time
of writing was 0.6.1. JasperReports itself depends on the following projects:
BeanShell
Commons BeanUtils
Commons Collections
Commons Digester
Commons Logging
iText
POI
JasperReports also requires a JAXP compliant XML parser.
18.7.2 Configuration
To configure JasperReports views in your Spring container configuration you need to
define a ViewResolver to map view names to the appropriate view class depending on
which format you want your report rendered in.
Render Format
JasperReportsCsvView
CSV
JasperReportsHtmlView
HTML
JasperReportsPdfView
JasperReportsXlsView
Microsoft Excel
JasperReportsMultiFormatView
Mapping one of these classes to a view name and a report file is a matter of adding the
appropriate entries in the resource bundle configured in the previous section as shown
here:
simpleReport.(class)=org.springframework.web.servlet.view.jasperreports.JasperReportsPdfView
simpleReport.url=/WEB-INF/reports/DataSourceReport.jasper
Here you can see that the view with name simpleReport is mapped to the
JasperReportsPdfView class, causing the output of this report to be rendered in PDF
format. The url property of the view is set to the location of the underlying report file.
Using JasperReportsMultiFormatView
The JasperReportsMultiFormatView allows for the report format to be specified at
runtime. The actual rendering of the report is delegated to one of the other JasperReports
In this example, the mapping key is determined from the extension of the request URI and
is added to the model under the default format key: format. If you wish to use a different
format key then you can configure this using the formatKey property of the
JasperReportsMultiFormatView class.
By default the following mapping key mappings are configured in
JasperReportsMultiFormatView:
View Class
csv
JasperReportsCsvView
html
JasperReportsHtmlView
JasperReportsPdfView
xls
JasperReportsXlsView
Here you can see that two Collection instances are being added to the model. To
ensure that the correct one is used, we simply modify our view configuration as
appropriate:
simpleReport.(class)=org.springframework.web.servlet.view.jasperreports.JasperReportsPdfView
simpleReport.url=/WEB-INF/reports/DataSourceReport.jasper
simpleReport.reportDataKey=myBeanData
Be aware that when using the first approach, Spring will use the first instance of
JRDataSource or Collection that it encounters. If you need to place multiple
instances of JRDataSource or Collection into the model you need to use the second
approach.
This defines a master report file that expects the sub-report to be passed in as an instance
of net.sf.jasperreports.engine.JasperReports under the parameter
ProductsSubReport. When configuring your Jasper view class, you can instruct Spring
to load a report file and pass it into the JasperReports engine as a sub-report using the
subReportUrls property:
<property name="subReportUrls">
<map>
Here, the key of the Map corresponds to the name of the sub-report parameter in the report
design file, and the entry is the URL of the report file. Spring will load this report file,
compiling it if necessary, and pass it into the JasperReports engine under the given key.
Here, the key you supply must correspond to both the key used in your ModelAndView
and the key used in your report design file.
Here you can see that the JasperReportsHtmlView is configured with an exporter
parameter for
net.sf.jasperreports.engine.export.JRHtmlExporterParameter.HTML_FOOTER
which will output a footer in the resulting HTML.
// implementation omitted
}
@Override
protected List<Entry> buildFeedEntries(Map<String, Object> model,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
// implementation omitted
}
}
19.1 Introduction
This chapter details Spring's integration with third party web frameworks such as JSF,
Struts, WebWork, and Tapestry.
One of the core value propositions of the Spring
Framework is that of enabling choice. In a general
sense, Spring does not force one to use or buy
into any particular architecture, technology, or
methodology (although it certainly recommends
some over others). This freedom to pick and
choose the architecture, technology, or
methodology that is most relevant to a developer
and his or her development team is arguably most
evident in the web area, where Spring provides its
own web framework (Spring MVC), while at the
same time providing integration with a number of
popular third party web frameworks. This allows
one to continue to leverage any and all of the skills
one may have acquired in a particular web
framework such as Struts, while at the same time
being able to enjoy the benefits afforded by Spring
in other areas such as data access, declarative
transaction management, and flexible
configuration and application assembly.
Having dispensed with the woolly sales patter (c.f.
the previous paragraph), the remainder of this
chapter will concentrate upon the meaty details of
integrating your favorite web framework with
cases. In Spring, these service objects, any other business-specific objects, data access
objects, etc. exist in a distinct 'business context', which contains no web or presentation
layer objects (presentation objects such as Spring MVC controllers are typically configured
in a distinct 'presentation context'). This section details how one configures a Spring
container (a WebApplicationContext) that contains all of the 'business beans' in
one's application.
On to specifics: all that one need do is to declare a ContextLoaderListener in the
standard Java EE servlet web.xml file of one's web application, and add a
contextConfigLocation <context-param/> section (in the same file) that defines
which set of Spring XML configuration files to load.
Find below the <listener/> configuration:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
scope support.
Note
Spring Web Flow 2.0 provides rich JSF support through its newly
established Spring Faces module, both for JSF-centric usage (as
described in this section) and for Spring-centric usage (using JSF
views within a Spring MVC dispatcher). Check out the Spring Web
Flow website for details!
The key element in Spring's JSF integration is the JSF 1.1 VariableResolver
mechanism. On JSF 1.2, Spring supports the ELResolver mechanism as a nextgeneration version of JSF EL integration.
19.3.4 FacesContextUtils
A custom VariableResolver works well when mapping one's properties to beans in
faces-config.xml, but at times one may need to grab a bean explicitly. The
FacesContextUtils class makes this easy. It is similar to
WebApplicationContextUtils, except that it takes a FacesContext parameter
rather than a ServletContext parameter.
ApplicationContext ctx = FacesContextUtils.getWebApplicationContext(FacesContext.getCurrentInstance());
19.4.1 ContextLoaderPlugin
The ContextLoaderPlugin is a Struts 1.1+ plug-in that loads a Spring context file for
the Struts ActionServlet. This context refers to the root WebApplicationContext
(loaded by the ContextLoaderListener) as its parent. The default name of the context
file is the name of the mapped servlet, plus -servlet.xml. If ActionServlet is defined in
web.xml as <servlet-name>action</servlet-name>, the default is /WEBINF/action-servlet.xml.
To configure this plug-in, add the following XML to the plug-ins section near the bottom of
your struts-config.xml file:
<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn"/>
The location of the context configuration files can be customized using the
'contextConfigLocation' property.
<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="contextConfigLocation"
value="/WEB-INF/action-servlet.xml,/WEB-INF/applicationContext.xml"/>
</plug-in>
It is possible to use this plugin to load all your context files, which can be useful when
using testing tools like StrutsTestCase. StrutsTestCase's MockStrutsTestCase won't
initialize Listeners on startup so putting all your context files in the plugin is a workaround.
(A bug has been filed for this issue, but has been closed as 'Wont Fix').
After configuring this plug-in in struts-config.xml, you can configure your Action to be
managed by Spring. Spring (1.1.3+) provides two ways to do this:
Override Struts' default RequestProcessor with Spring's
DelegatingRequestProcessor.
Use the DelegatingActionProxy class in the type attribute of your <actionmapping>.
Both of these methods allow you to manage your Actions and their dependencies in the
action-servlet.xml file. The bridge between the Action in struts-config.xml and actionservlet.xml is built with the action-mapping's "path" and the bean's "name". If you have the
following in your struts-config.xml file:
<action path="/users" .../>
You must define that Action's bean with the "/users" name in action-servlet.xml:
<bean name="/users" .../>
DelegatingRequestProcessor
To configure the DelegatingRequestProcessor in your struts-config.xml file,
override the "processorClass" property in the <controller> element. These lines follow the
<action-mapping> element.
<controller>
<set-property property="processorClass"
value="org.springframework.web.struts.DelegatingRequestProcessor"/>
</controller>
After adding this setting, your Action will automatically be looked up in Spring's context file,
no matter what the type. In fact, you don't even need to specify a type. Both of the following
snippets will work:
<action path="/user" type="com.whatever.struts.UserAction"/>
<action path="/user"/>
If you're using Struts' modules feature, your bean names must contain the module prefix.
For example, an action defined as <action path="/user"/> with module prefix
"admin" requires a bean name with <bean name="/admin/user"/>.
Note
If you are using Tiles in your Struts application, you must configure your
<controller> with the DelegatingTilesRequestProcessor
instead.
DelegatingActionProxy
If you have a custom RequestProcessor and can't use the
DelegatingRequestProcessor or DelegatingTilesRequestProcessor
approaches, you can use the DelegatingActionProxy as the type in your actionmapping.
<action path="/user" type="org.springframework.web.struts.DelegatingActionProxy"
name="userForm" scope="request" validate="false" parameter="method">
<forward name="list" path="/userList.jsp"/>
<forward name="edit" path="/userForm.jsp"/>
</action>
The bean definition in action-servlet.xml remains the same, whether you use a custom
RequestProcessor or the DelegatingActionProxy.
If you define your Action in a context file, the full feature set of Spring's bean container
will be available for it: dependency injection as well as the option to instantiate a new
Action instance for each request. To activate the latter, add scope="prototype" to your
Action's bean definition.
<bean name="/user" scope="prototype" autowire="byName"
class="org.example.web.UserAction"/>
Spring includes subclasses for all of the standard Struts Actions - the Spring versions
merely have Support appended to the name:
ActionSupport,
DispatchActionSupport,
LookupDispatchActionSupport and
MappingDispatchActionSupport.
The recommended strategy is to use the approach that best suits your project. Subclassing
makes your code more readable, and you know exactly how your dependencies are
resolved. In contrast, using the ContextLoaderPlugin allows you to easily add new
dependencies in your context XML file. Either way, Spring provides some nice options for
integrating with Struts.
means afforded by Spring. The real beauty of the rest of this Spring-Tapestry integration is
that the elegant and flexible design of Tapestry itself makes doing this dependency
injection of Spring-managed beans a cinch. (Another nice thing is that this Spring-Tapestry
integration code was written - and continues to be maintained - by the Tapestry creator
Howard M. Lewis Ship, so hats off to him for what is really some silky smooth integration).
Inside the Tapestry application, the above bean definitions need to be loaded into a Spring
container, and any relevant Tapestry pages need to be supplied (injected) with 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 Java EE 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. Having said that, 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 IoC principle; 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 part of the page and component lifecycle.
Note
This next section is applicable to Tapestry 3.x. If you are using
Tapestry version 4.x, please consult the section entitled the section
called Dependency Injecting Spring Beans into Tapestry pages Tapestry 4.x style.
This engine class places the Spring Application Context as an attribute called
"appContext" in this Tapestry app's 'Global' object. Make sure to register the fact that this
special IEngine instance should be used for this Tapestry application, with an entry in the
Tapestry application definition file. For example:
file: xportal.application:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE application PUBLIC
"-//Apache Software Foundation//Tapestry Specification 3.0//EN"
"http://jakarta.apache.org/tapestry/dtd/Tapestry_3_0.dtd">
<application
name="Whatever xPortal"
engine-class="com.whatever.web.xportal.MyEngine">
</application>
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:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE page-specification PUBLIC
"-//Apache Software Foundation//Tapestry Specification 3.0//EN"
"http://jakarta.apache.org/tapestry/dtd/Tapestry_3_0.dtd">
<page-specification class="com.whatever.web.xportal.pages.Login">
<property-specification
<property-specification
<property-specification
<property-specification
<property-specification
name="username" type="java.lang.String"/>
name="password" type="java.lang.String"/>
name="error" type="java.lang.String"/>
name="callback" type="org.apache.tapestry.callback.ICallback" persistent="yes"/>
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>
<bean name="delegate" class="com.whatever.web.xportal.PortalValidationDelegate"/>
<bean name="validator" class="org.apache.tapestry.valid.StringValidator" lifecycle="page">
<set-property name="required" expression="true"/>
<set-property name="clientScriptingEnabled" expression="true"/>
</bean>
<component id="inputUsername" type="ValidField">
<static-binding name="displayName" value="Username"/>
<binding name="value" expression="username"/>
<binding name="validator" expression="beans.validator"/>
</component>
<component id="inputPassword" type="ValidField">
<binding name="value" expression="password"/>
<binding name="validator" expression="beans.validator"/>
<static-binding name="displayName" value="Password"/>
<binding name="hidden" expression="true"/>
</component>
</page-specification>
For the sake of 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 successfully 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, PageRenderListener {
/** the key under which the authenticated user object is stored in the visit as */
public static final String USER_KEY = "user";
/** The name of the cookie that identifies a user **/
private static final String COOKIE_NAME = Login.class.getName() + ".username";
private final static int ONE_WEEK = 7 * 24 * 60 * 60;
public abstract String getUsername();
public abstract void setUsername(String username);
public abstract String getPassword();
public abstract void setPassword(String password);
public abstract ICallback getCallback();
public abstract void setCallback(ICallback value);
public abstract UserService getUserService();
public abstract AuthenticationService getAuthenticationService();
protected IValidationDelegate getValidationDelegate() {
return (IValidationDelegate) getBeans().getBean("delegate");
}
protected void setErrorField(String componentId, String message) {
IFormComponent field = (IFormComponent) getComponent(componentId);
IValidationDelegate delegate = getValidationDelegate();
delegate.setFormComponent(field);
delegate.record(new ValidatorException(message));
}
/**
* 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) {
String password = getPassword();
// Do a little extra work to clear out the password.
setPassword(null);
IValidationDelegate delegate = getValidationDelegate();
delegate.setFormComponent((IFormComponent) getComponent("inputPassword"));
delegate.recordFieldInputValue(null);
// An error, from a validation field, may already have occurred.
if (delegate.getHasErrors()) {
return;
}
try {
User user = getAuthenticationService().login(getUsername(), getPassword());
loginUser(user, cycle);
}
catch (FailedLoginException ex) {
this.setError("Login failed: " + ex.getMessage());
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) {
String username = user.getUsername();
// Get the visit object; this will likely force the
// creation of the visit object and an HttpSession
Map visit = (Map) getVisit();
visit.put(USER_KEY, user);
// After logging in, go to the MyLibrary page, unless otherwise specified
ICallback callback = getCallback();
if (callback == null) {
cycle.activate("Home");
}
else {
callback.performCallback(cycle);
}
IEngine engine = getEngine();
Cookie cookie = new Cookie(COOKIE_NAME, username);
cookie.setPath(engine.getServletPath());
cookie.setMaxAge(ONE_WEEK);
// Record the user's username in a cookie
cycle.getRequestContext().addCookie(cookie);
engine.forgetPage(getPageName());
}
public void pageBeginRender(PageEvent event) {
if (getUsername() == null) {
setUsername(getRequestCycle().getRequestContext().getCookieValue(COOKIE_NAME));
}
}
}
We are almost done. All that remains is the HiveMind configuration that exposes the
Spring container stored in the ServletContext as a HiveMind service; for example:
<?xml version="1.0"?>
<module id="com.javaforge.tapestry.spring" version="0.1.1">
<service-point id="SpringApplicationInitializer"
interface="org.apache.tapestry.services.ApplicationInitializer"
visibility="private">
<invoke-factory>
<construct class="com.javaforge.tapestry.spring.SpringApplicationInitializer">
<set-object property="beanFactoryHolder"
value="service:hivemind.lib.DefaultSpringBeanFactoryHolder" />
</construct>
</invoke-factory>
</service-point>
<!-- Hook the Spring setup into the overall application initialization. -->
<contribution
configuration-id="tapestry.init.ApplicationInitializers">
<command id="spring-context"
object="service:SpringApplicationInitializer" />
</contribution>
</module>
If you are using Java 5 (and thus have access to annotations), then that really is it.
If you are not using Java 5, then one obviously doesn't annotate one's Tapestry page
classes with annotations; instead, one simply uses good old fashioned XML to declare the
dependency injection; for example, inside the .page or .jwc file for the Login page (or
component):
<inject property="userService" object="spring:userService"/>
<inject property="authenticationService" object="spring:authenticationService"/>
In this example, we've managed to allow service beans defined in a Spring container to be
provided to the Tapestry 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 throughout
the stack in this Tapestry application.
methods.
The framework is designed around a
DispatcherPortlet that dispatches requests to handlers, with configurable handler
mappings and view resolution, just as the DispatcherServlet in the web framework
does. File upload is also supported in the same way.
Locale resolution and theme resolution are not supported in Portlet MVC - these areas are
in the purview of the portal/portlet container and are not appropriate at the Spring level.
However, all mechanisms in Spring that depend on the locale (such as internationalization
of messages) will still function properly because DispatcherPortlet exposes the
current locale in the same way as DispatcherServlet.
Explanation
handler
mapping(s)
(Section 20.5, Handler mappings) a list of pre- and postprocessors and controllers that will be executed if they match
certain criteria (for instance a matching portlet mode specified
with the controller)
controller(s)
view resolver
multipart
resolver
handler
exception
resolver
When a DispatcherPortlet is setup for use and a request comes in for that specific
DispatcherPortlet, it starts processing the request. The list below describes the
complete process a request goes through if handled by a DispatcherPortlet:
1. The locale returned by PortletRequest.getLocale() is bound to the request to
let elements in the process resolve the locale to use when processing the request
(rendering the view, preparing data, etc.).
2. If a multipart resolver is specified and this is an ActionRequest, the request is
inspected for multiparts and if they are found, it is wrapped in a
MultipartActionRequest for further processing by other elements in the process.
(See Section 20.7, Multipart (file upload) support for further information about
multipart handling).
3. An appropriate handler is searched for. If a handler is found, the execution chain
associated with the handler (pre-processors, post-processors, controllers) will be
executed in order to prepare a model.
4. If a model is returned, the view is rendered, using the view resolver that has been
configured with the WebApplicationContext. If no model is returned (which could
be due to a pre- or post-processor intercepting the request, for example, for security
reasons), no view is rendered, since the request could already have been fulfilled.
Exceptions that are thrown during processing of the request get picked up by any of the
handler exception resolvers that are declared in the WebApplicationContext. Using
these exception resolvers you can define custom behavior in case such exceptions get
thrown.
You can customize Spring's DispatcherPortlet by adding context parameters in the
portlet.xml file or portlet init-parameters. The possibilities are listed below.
contextClass
Explanation
Class that implements
WebApplicationContext, which will be used
to instantiate the context used by this portlet. If
this parameter isn't specified, the
XmlPortletApplicationContext will be
used.
viewRendererUrl
20.4 Controllers
The controllers in Portlet MVC are very similar to the Web MVC Controllers, and porting
code from one to the other should be simple.
The basis for the Portlet MVC controller architecture is the
org.springframework.web.portlet.mvc.Controller interface, which is listed
below.
public interface Controller {
/**
* Process the render request and return a ModelAndView object which the
* DispatcherPortlet will render.
*/
ModelAndView handleRenderRequest(RenderRequest request, RenderResponse response)
throws Exception;
/**
* Process the action request. There is nothing to return.
*/
void handleActionRequest(ActionRequest request, ActionResponse response)
throws Exception;
}
As you can see, the Portlet Controller interface requires two methods that handle the
two phases of a portlet request: the action request and the render request. The action
phase should be capable of handling an action request, and the render phase should be
capable of handling a render request and returning an appropriate model and view. While
the Controller interface is quite abstract, Spring Portlet MVC offers several controllers
that already contain a lot of the functionality you might need; most of these are very similar
to controllers from Spring Web MVC. The Controller interface just defines the most
common functionality required of every controller: handling an action request, handling a
render request, and returning a model and a view.
Explanation
requireSession
synchronizeSession
cacheSeconds
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import org.springframework.web.portlet.mvc.AbstractController;
import org.springframework.web.portlet.ModelAndView;
public class SampleController extends AbstractController {
public ModelAndView handleRenderRequestInternal(RenderRequest request, RenderResponse response) {
ModelAndView mav = new ModelAndView("foo");
mav.addObject("message", "Hello World!");
return mav;
}
}
<bean id="sampleController" class="samples.SampleController">
<property name="cacheSeconds" value="120"/>
</bean>
The class above and the declaration in the web application context is all you need besides
setting up a handler mapping (see Section 20.5, Handler mappings) to get this very
simple controller working.
20.4.4 PortletWrappingController
Instead of developing new controllers, it is possible to use existing portlets and map
requests to them from a DispatcherPortlet. Using the
PortletWrappingController, you can instantiate an existing Portlet as a
Controller as follows:
<bean id="myPortlet" class="org.springframework.web.portlet.mvc.PortletWrappingController">
<property name="portletClass" value="sample.MyPortlet"/>
<property name="portletName" value="my-portlet"/>
<property name="initParameters">
<value>config=/WEB-INF/my-portlet-config.xml</value>
</property>
</bean>
This can be very valuable since you can then use interceptors to pre-process and postprocess requests going to these portlets. Since JSR-168 does not support any kind of filter
mechanism, this is quite handy. For example, this can be used to wrap the Hibernate
OpenSessionInViewInterceptor around a MyFaces JSF Portlet.
anything available to the portlet request can be used in a custom handler mapping.
The rest of this section describes three of Spring Portlet MVC's most commonly used
handler mappings. They all extend AbstractHandlerMapping and share the following
properties:
interceptors: The list of interceptors to use. HandlerInterceptors are
discussed in Section 20.5.4, Adding HandlerInterceptors.
defaultHandler: The default handler to use, when this handler mapping does not
result in a matching handler.
order: Based on the value of the order property (see the
org.springframework.core.Ordered interface), Spring will sort all handler
mappings available in the context and apply the first matching handler.
lazyInitHandlers: Allows for lazy initialization of singleton handlers (prototype
handlers are always lazily initialized). Default value is false. This property is directly
implemented in the three concrete Handlers.
20.5.1 PortletModeHandlerMapping
This is a simple handler mapping that maps incoming requests based on the current mode
of the portlet (e.g. view, edit, help). An example:
<bean class="org.springframework.web.portlet.handler.PortletModeHandlerMapping">
<property name="portletModeMap">
<map>
<entry key="view" value-ref="viewHandler"/>
<entry key="edit" value-ref="editHandler"/>
<entry key="help" value-ref="helpHandler"/>
</map>
</property>
</bean>
20.5.2 ParameterHandlerMapping
If we need to navigate around to multiple controllers without changing portlet mode, the
simplest way to do this is with a request parameter that is used as the key to control the
mapping.
ParameterHandlerMapping uses the value of a specific request parameter to control
the mapping. The default name of the parameter is 'action', but can be changed using
the 'parameterName' property.
The bean configuration for this mapping will look something like this:
<bean class="org.springframework.web.portlet.handler.ParameterHandlerMapping>
<property name="parameterMap">
<map>
<entry key="add" value-ref="addItemHandler"/>
<entry key="edit" value-ref="editItemHandler"/>
<entry key="delete" value-ref="deleteItemHandler"/>
</map>
</property>
</bean>
20.5.3 PortletModeParameterHandlerMapping
The most powerful built-in handler mapping,
PortletModeParameterHandlerMapping combines the capabilities of the two
previous ones to allow different navigation within each portlet mode.
Again the default name of the parameter is "action", but can be changed using the
parameterName property.
By default, the same parameter value may not be used in two different portlet modes. This
is so that if the portal itself changes the portlet mode, the request will no longer be valid in
the mapping. This behavior can be changed by setting the allowDupParameters
20.5.5 HandlerInterceptorAdapter
As with the servlet package, the portlet package has a concrete implementation of
HandlerInterceptor called HandlerInterceptorAdapter. This class has empty
versions of all the methods so that you can inherit from this class and implement just one or
two methods when that is all you need.
20.5.6 ParameterMappingInterceptor
The portlet package also has a concrete interceptor named
ParameterMappingInterceptor that is meant to be used directly with
ParameterHandlerMapping and PortletModeParameterHandlerMapping.
This interceptor will cause the parameter that is being used to control the mapping to be
Of course you also need to put the appropriate jars in your classpath for the multipart
resolver to work. In the case of the CommonsMultipartResolver, you need to use
commons-fileupload.jar. Be sure to use at least version 1.1 of Commons
FileUpload as previous versions do not support JSR-168 Portlet applications.
Now that you have seen how to set Portlet MVC up to handle multipart requests, let's talk
about how to actually use it. When DispatcherPortlet detects a multipart request, it
activates the resolver that has been declared in your context and hands over the request.
What the resolver then does is wrap the current ActionRequest in a
MultipartActionRequest that has support for multipart file uploads. Using the
MultipartActionRequest you can get information about the multiparts contained by
this request and actually get access to the multipart files themselves in your controllers.
Note that you can only receive multipart file uploads as part of an ActionRequest, not
as part of a RenderRequest.
As you can see, we've created a field named file that matches the property of the bean
that holds the byte[] array. Furthermore we've added the encoding attribute
(enctype="multipart/form-data"), which is necessary to let the browser know
how to encode the multipart fields (do not forget this!).
Just as with any other property that's not automagically convertible to a string or primitive
type, to be able to put binary data in your objects you have to register a custom editor with
the PortletRequestDataBinder. There are a couple of editors available for handling
files and setting the results on an object. There's a StringMultipartFileEditor
capable of converting files to Strings (using a user-defined character set), and there is a
ByteArrayMultipartFileEditor which converts files to byte arrays. They function
analogous to the CustomDateEditor.
So, to be able to upload files using a form, declare the resolver, a mapping to a controller
that will process the bean, and the controller itself.
<bean id="portletMultipartResolver"
class="org.springframework.web.portlet.multipart.CommonsPortletMultipartResolver"/>
<bean class="org.springframework.web.portlet.handler.PortletModeHandlerMapping">
<property name="portletModeMap">
<map>
<entry key="view" value-ref="fileUploadController"/>
</map>
</property>
</bean>
<bean id="fileUploadController" class="examples.FileUploadController">
<property name="commandClass" value="examples.FileUploadBean"/>
<property name="formView" value="fileuploadform"/>
<property name="successView" value="confirmation"/>
</bean>
After that, create the controller and the actual class to hold the file property.
public class FileUploadController extends SimpleFormController {
public void onSubmitAction(ActionRequest request, ActionResponse response,
Object command, BindException errors) throws Exception {
// cast the bean
FileUploadBean bean = (FileUploadBean) command;
// let's see if there's content there
byte[] file = bean.getFile();
if (file == null) {
// hmm, that's strange, the user did not upload anything
}
// do something with the file here
}
protected void initBinder(
PortletRequest request, PortletRequestDataBinder binder) throws Exception {
// to actually be able to convert Multipart instance to byte[]
// we have to register a custom editor
binder.registerCustomEditor(byte[].class, new ByteArrayMultipartFileEditor());
// now Spring knows how to handle multipart object and convert
}
}
public class FileUploadBean {
private byte[] file;
public void setFile(byte[] file) {
this.file = file;
}
public byte[] getFile() {
return file;
}
}
As you can see, the FileUploadBean has a property of type byte[] that holds the file.
The controller registers a custom editor to let Spring know how to actually convert the
multipart objects the resolver has found to properties specified by the bean. In this
example, nothing is done with the byte[] property of the bean itself, but in practice you
can do whatever you want (save it in a database, mail it to somebody, etc).
An equivalent example in which a file is bound straight to a String-typed property on a form
backing object might look like this:
public class FileUploadController extends SimpleFormController {
public void onSubmitAction(ActionRequest request, ActionResponse response,
Object command, BindException errors) throws Exception {
// cast the bean
FileUploadBean bean = (FileUploadBean) command;
// let's see if there's content there
String file = bean.getFile();
if (file == null) {
// hmm, that's strange, the user did not upload anything
}
// do something with the file here
}
protected void initBinder(
PortletRequest request, PortletRequestDataBinder binder) throws Exception {
// to actually be able to convert Multipart instance to a String
// we have to register a custom editor
binder.registerCustomEditor(String.class,
new StringMultipartFileEditor());
// now Spring knows how to handle multipart objects and convert
}
}
public class FileUploadBean {
private String file;
public void setFile(String file) {
this.file = file;
}
public String getFile() {
return file;
}
}
Of course, this last example only makes (logical) sense in the context of uploading a plain
text file (it wouldn't work so well in the case of uploading an image file).
The third (and final) option is where one binds directly to a MultipartFile property
declared on the (form backing) object's class. In this case one does not need to register
any custom property editor because there is no type conversion to be performed.
public class FileUploadController extends SimpleFormController {
public void onSubmitAction(ActionRequest request, ActionResponse response,
Object command, BindException errors) throws Exception {
// cast the bean
FileUploadBean bean = (FileUploadBean) command;
// let's see if there's content there
MultipartFile file = bean.getFile();
if (file == null) {
// hmm, that's strange, the user did not upload anything
}
// do something with the file here
}
}
public class FileUploadBean {
private MultipartFile file;
public void setFile(MultipartFile file) {
this.file = file;
}
public MultipartFile getFile() {
return file;
}
}
(except for validation results, which need to follow right after the corresponding command
object, if desired):
Request and/or response objects (Portlet API). You may choose any specific
request/response type, e.g. PortletRequest / ActionRequest / RenderRequest. An
explicitly declared action/render argument is also used for mapping specific request
types onto a handler method (in case of no other information given that differentiates
between action and render requests).
Session object (Portlet API): of type PortletSession. An argument of this type will
enforce the presence of a corresponding session. As a consequence, such an
argument will never be null.
org.springframework.web.context.request.WebRequest or
org.springframework.web.context.request.NativeWebRequest.
Allows for generic request parameter access as well as request/session attribute
access, without ties to the native Servlet/Portlet API.
java.util.Locale for the current request locale (the portal locale in a Portlet
environment).
java.io.InputStream / java.io.Reader for access to the request's content.
This will be the raw InputStream/Reader as exposed by the Portlet API.
java.io.OutputStream / java.io.Writer for generating the response's
content. This will be the raw OutputStream/Writer as exposed by the Portlet API.
@RequestParam annotated parameters for access to specific Portlet request
parameters. Parameter values will be converted to the declared method argument
type.
java.util.Map / org.springframework.ui.Model /
org.springframework.ui.ModelMap for enriching the implicit model that will be
exposed to the web view.
Command/form objects to bind parameters to: as bean properties or fields, with
customizable type conversion, depending on @InitBinder methods and/or the
HandlerAdapter configuration - see the "webBindingInitializer" property on
AnnotationMethodHandlerAdapter. Such command objects along with their
validation results will be exposed as model attributes, by default using the nonqualified command class name in property notation (e.g. "orderAddress" for type
"mypackage.OrderAddress"). Specify a parameter-level ModelAttribute
annotation for declaring a specific model attribute name.
org.springframework.validation.Errors /
org.springframework.validation.BindingResult validation results for a
preceding command/form object (the immediate preceding argument).
org.springframework.web.bind.support.SessionStatus status handle
for marking form processing as complete (triggering the cleanup of session attributes
that have been indicated by the @SessionAttributes annotation at the handler
type level).
The following return types are supported for handler methods:
A ModelAndView object, with the model implicitly enriched with command objects
and the results of @ModelAttribute annotated reference data accessor methods.
A Model object, with the view name implicitly determined through a
RequestToViewNameTranslator and the model implicitly enriched with
command objects and the results of @ModelAttribute annotated reference data
accessor methods.
A Map object for exposing a model, with the view name implicitly determined through a
RequestToViewNameTranslator and the model implicitly enriched with
command objects and the results of @ModelAttribute annotated reference data
accessor methods.
A View object, with the model implicitly determined through command objects and
@ModelAttribute annotated reference data accessor methods. The handler
method may also programmatically enrich the model by declaring a Model argument
(see above).
A String value which is interpreted as view name, with the model implicitly
determined through command objects and @ModelAttribute annotated reference
data accessor methods. The handler method may also programmatically enrich the
model by declaring a Model argument (see above).
void if the method handles the response itself (e.g. by writing the response content
directly).
Any other return type will be considered a single model attribute to be exposed to the
view, using the attribute name specified through @ModelAttribute at the method
level (or the default attribute name based on the return type's class name otherwise).
The model will be implicitly enriched with command objects and the results of
@ModelAttribute annotated reference data accessor methods.
Parameters using this annotation are required by default, but you can specify that a
parameter is optional by setting @RequestParam's required attribute to false (e.g.,
@RequestParam(value="id", required=false)).
@RequestMapping("EDIT")
@SessionAttributes("site")
public class PetSitesEditController {
// ...
@ModelAttribute("petSites")
public Properties getPetSites() {
return this.petSites;
}
@RequestMapping(params = "action=add") // action phase
public void populateSite(
@ModelAttribute("site") PetSite petSite, BindingResult result,
SessionStatus status, ActionResponse response) {
new PetSiteValidator().validate(petSite, result);
if (!result.hasErrors()) {
this.petSites.put(petSite.getName(), petSite.getUrl());
status.setComplete();
response.setRenderParameter("action", "list");
}
}
}
// ...
}
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 using Hessian as the
protocol.
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
The servicePort property has been omitted (it defaults to 0). This
means that an anonymous port will be used to communicate with the
service.
To link in the service on the client, we'll create a separate Spring container, containing the
simple object and the service linking configuration bits:
<bean class="example.SimpleObject">
<property name="accountService" ref="accountService"/>
</bean>
<bean id="accountService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="serviceUrl" value="rmi://HOST:1199/AccountService"/>
<property name="serviceInterface" value="example.AccountService"/>
</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.
You're probably familiar with Spring's DispatcherServlet principles and if so, you
know that now you'll have to create a Spring container configuration resource named
'remoting-servlet.xml' (after the name of your servlet) in the 'WEB-INF'
directory. The application context will be used in the next section.
Alternatively, consider the use of Spring's simpler HttpRequestHandlerServlet.
This allows you to embed the remote exporter definitions in your root application context
(by default in 'WEB-INF/applicationContext.xml'), with individual servlet
definitions pointing to specific exporter beans. Each servlet name needs to match the bean
name of its target exporter in this case.
Now we're ready to link in the service at the client. No explicit handler mapping is
specified, mapping request URLs onto services, so BeanNameUrlHandlerMapping
will be used: Hence, the service will be exported at the URL indicated through its bean
name within the containing DispatcherServlet's mapping (as defined above):
'http://HOST:8080/remoting/AccountService'.
Alternatively, create a HessianServiceExporter in your root application context (e.g.
in 'WEB-INF/applicationContext.xml'):
<bean name="accountExporter" class="org.springframework.remoting.caucho.HessianServiceExporter">
<property name="service" ref="accountService"/>
<property name="serviceInterface" value="example.AccountService"/>
</bean>
In the latter case, define a corresponding servlet for this exporter in 'web.xml', with the
same end result: The exporter getting mapped to the request path
/remoting/AccountService. Note that the servlet name needs to match the bean
name of the target exporter.
<servlet>
<servlet-name>accountExporter</servlet-name>
<servlet-class>org.springframework.web.context.support.HttpRequestHandlerServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>accountExporter</servlet-name>
<url-pattern>/remoting/AccountService</url-pattern>
</servlet-mapping>
In addition, define a corresponding servlet for this exporter in 'web.xml', with the servlet
name matching the bean name of the target exporter:
<servlet>
<servlet-name>accountExporter</servlet-name>
<servlet-class>org.springframework.web.context.support.HttpRequestHandlerServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>accountExporter</servlet-name>
<url-pattern>/remoting/AccountService</url-pattern>
</servlet-mapping>
If you are running outside of a servlet container and are using Sun's Java 6, then you can
use the built-in HTTP server implementation. You can configure the
SimpleHttpServerFactoryBean together with a
SimpleHttpInvokerServiceExporter as is shown in this example:
<bean name="accountExporter"
class="org.springframework.remoting.httpinvoker.SimpleHttpInvokerServiceExporter">
<property name="service" ref="accountService"/>
<property name="serviceInterface" value="example.AccountService"/>
</bean>
<bean id="httpServer"
class="org.springframework.remoting.support.SimpleHttpServerFactoryBean">
<property name="contexts">
<util:map>
<entry key="/remoting/AccountService" value-ref="accountExporter"/>
</util:map>
</property>
<property name="port" value="8080" />
</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>
Where serviceInterface is our remote business interface the clients will use.
wsdlDocumentUrl is the URL for the WSDL file. Spring needs this at startup time to
create the JAX-RPC Service. namespaceUri corresponds to the targetNamespace in the
.wsdl file. serviceName corresponds to the service name in the .wsdl file. portName
corresponds to the port name in the .wsdl file.
Accessing the web service is now very easy as we have a bean factory for it that will
From the client code we can access the web service just as if it was a normal class, except
that it throws RemoteException.
public class AccountClientImpl {
private RemoteAccountService service;
public void setService(RemoteAccountService service) {
this.service = service;
}
public void foo() {
try {
service.insertAccount(...);
}
catch (RemoteException ex) {
// ouch
}
}
}
We can get rid of the checked RemoteException since Spring supports automatic
conversion to its corresponding unchecked RemoteException. This requires that we
provide a non-RMI interface also. Our configuration is now:
<bean id="accountWebService" class="org.springframework.remoting.jaxrpc.JaxRpcPortProxyFactoryBean">
<property name="serviceInterface" value="example.AccountService"/>
<property name="portInterface" value="example.RemoteAccountService"/>
...
</bean>
Where serviceInterface is changed to our non RMI interface. Our RMI interface is
now defined using the property portInterface. Our client code can now avoid handling
java.rmi.RemoteException:
public class AccountClientImpl {
private AccountService service;
public void setService(AccountService service) {
this.service = service;
}
public void foo() {
service.insertAccount(...);
}
}
Note that you can also drop the "portInterface" part and specify a plain business interface
as "serviceInterface". In this case, JaxRpcPortProxyFactoryBean will automatically
switch to the JAX-RPC "Dynamic Invocation Interface", performing dynamic invocations
without a fixed port stub. The advantage is that you don't even need to have an RMIcompliant Java port interface around (e.g. in case of a non-Java target web service); all you
need is a matching business interface. Check out JaxRpcPortProxyFactoryBean's
javadoc for details on the runtime implications.
We will use Axis to register bean mappings on the client side. To do this we need to
register the bean mappings programmatically:
public class AxisPortProxyFactoryBean extends JaxRpcPortProxyFactoryBean {
protected void postProcessJaxRpcService(Service service) {
TypeMappingRegistry registry = service.getTypeMappingRegistry();
TypeMapping mapping = registry.createTypeMapping();
registerBeanMapping(mapping, Account.class, "Account");
registry.register("http://schemas.xmlsoap.org/soap/encoding/", mapping);
}
protected void registerBeanMapping(TypeMapping mapping, Class type, String name) {
QName qName = new QName("http://localhost:8080/account/services/accountService", name);
mapping.register(type, qName,
new BeanSerializerFactory(type, qName),
new BeanDeserializerFactory(type, qName));
}
}
The last thing we must remember to do is to change the Spring configuration to use our
factory bean:
<bean id="accountWebService" class="example.AccountHandlerJaxRpcPortProxyFactoryBean">
...
</bean>
@WebService(serviceName="AccountService")
public class AccountServiceEndpoint {
@Autowired
private AccountService biz;
@WebMethod
public void insertAccount(Account acc) {
biz.insertAccount(acc);
}
@WebMethod
public List<Account> getAccounts(String name) {
return biz.getAccounts(name);
}
}
From the client code we can access the web service just as if it was a normal class:
public class AccountClientImpl {
private AccountService service;
public void setService(AccountService service) {
this.service = service;
}
public void foo() {
service.insertAccount(...);
}
}
NOTE: The above is slightly simplified in that JAX-WS requires endpoint interfaces and
implementation classes to be annotated with @WebService, @SOAPBinding etc
annotations. This means that you cannot (easily) use plain Java interfaces and
implementation classes as JAX-WS endpoint artifacts; you need to annotate them
accordingly first. Check the JAX-WS documentation for details on those requirements.
21.6 JMS
It is also possible to expose services transparently using JMS as the underlying
communication protocol. The JMS remoting support in the Spring Framework is pretty
basic - it sends and receives on the same thread and in the same non-transactional
Session, and as such throughput will be very implementation dependent. Note that these
single-threaded and non-transactional constraints apply only to Spring's JMS remoting
support. See Chapter 23, JMS (Java Message Service) for information on Spring's rich
support for JMS-based messaging.
The following interface is used on both the server and the client side.
package com.foo;
public interface CheckingAccountService {
public void cancelAccount(Long accountId);
}
The following simple implementation of the above interface is used on the server-side.
package com.foo;
public class SimpleCheckingAccountService implements CheckingAccountService {
public void cancelAccount(Long accountId) {
System.out.println("Cancelling account [" + accountId + "]");
}
}
This configuration file contains the JMS-infrastructure beans that are shared on both the
client and server.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://ep-t43:61616"/>
</bean>
<bean id="queue" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="mmm"/>
</bean>
</beans>
package com.foo;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Server {
public static void main(String[] args) throws Exception {
new ClassPathXmlApplicationContext(new String[]{"com/foo/server.xml", "com/foo/jms.xml"});
}
}
package com.foo;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Client {
public static void main(String[] args) throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
new String[] {"com/foo/client.xml", "com/foo/jms.xml"});
CheckingAccountService service = (CheckingAccountService) ctx.getBean("checkingAccountService");
service.cancelAccount(new Long(10));
}
}
You may also wish to investigate the support provided by the Lingo project, which (to quote
the homepage blurb) ... is a lightweight POJO based remoting and messaging library
based on the Spring Framework's remoting libraries which extends it to support JMS.
The main reason why auto-detection of implemented interfaces does not occur for remote
interfaces is to avoid opening too many doors to remote callers. The target object might
implement internal callback interfaces like InitializingBean or DisposableBean
which one would not want to expose to callers.
Offering a proxy with all interfaces implemented by the target usually does not matter in the
local case. But when exporting a remote service, you should expose a specific service
interface, with specific operations intended for remote usage. Besides internal callback
interfaces, the target might implement multiple business interfaces, with just one of them
intended for remote exposure. For these reasons, we require such a service interface to be
specified.
This is a trade-off between configuration convenience and the risk of accidental exposure
of internal methods. Always specifying a service interface is not too much effort, and puts
you on the safe side regarding controlled exposure of specific methods.
21.9.1 RestTemplate
Invoking RESTful services in Java is typically done using a helper class such as Jakarta
Commons HttpClient. For common REST operations this approach is too low level as
shown below.
String uri = "http://example.com/hotels/1/bookings";
PostMethod post = new PostMethod(uri);
String request = // create booking request content
post.setRequestEntity(new StringRequestEntity(request));
httpClient.executeMethod(post);
if (HttpStatus.SC_CREATED == post.getStatusCode()) {
Header location = post.getRequestHeader("Location");
if (location != null) {
System.out.println("Created new booking at :" + location.getValue());
}
}
RestTemplate provides higher level methods that correspond to each of the six main HTTP
methods that make invoking many RESTful services a one-liner and enforce REST best
practices.
RestTemplate Method
DELETE
delete
GET
getForObject
getForEntity
HEAD
OPTIONS
POST
PUT
The names of RestTemplate methods follow a naming convention, the first part
indicates what HTTP method is being invoked and the second part indicates what is
returned. For example, the method getForObject() will perform a GET, convert the
HTTP response into an object type of your choice and return that object. The method
postForLocation() will do a POST, converting the given object into a HTTP request
and return the response HTTP Location header where the newly created object can be
found. In case of an exception processing the HTTP request, an exception of the type
RestClientException will be thrown; this behavior can be changed by plugging in
another ResponseErrorHandler implementation into the RestTemplate.
Objects passed to and returned from these methods are converted to and from HTTP
messages by HttpMessageConverter instances. Converters for the main mime types
are registered by default, but you can also write your own converter and register it via the
messageConverters() bean property. The default converter instances registered with
the template are ByteArrayHttpMessageConverter,
using a Map<String,String>.
To create an instance of RestTemplate you can simply call the default no-arg
constructor. This will use standard Java classes from the java.net package as the
underlying implementation to create HTTP requests. This can be overridden by specifying
an implementation of ClientHttpRequestFactory. Spring provides the
implementation HttpComponentsClientHttpRequestFactory that uses the
Apache HttpComponents HttpClient to create requests.
HttpComponentsClientHttpRequestFactory is configured using an instance of
org.apache.http.client.HttpClient which can in turn be configured with
credentials information or connection pooling functionality.
Tip
Note that the java.net implementation for HTTP requests may raise
an exception when accessing the status of a response that represents
an error (e.g. 401). If this is an issue, switch to
HttpComponentsClientHttpRequestFactory instead.
The previous example using Apache HttpComponents HttpClient directly rewritten to
use the RestTemplate is shown below
uri = "http://example.com/hotels/{id}/bookings";
RestTemplate template = new RestTemplate();
Booking booking = // create booking object
URI location = template.postForLocation(uri, booking, "1");
The general callback interface is RequestCallback and is called when the execute
method is invoked.
public <T> T execute(String url, HttpMethod method, RequestCallback requestCallback,
ResponseExtractor<T> responseExtractor,
String... urlVariables)
// also has an overload with urlVariables as a Map<String, String>.
and allows you to manipulate the request headers and write to the request body. When
using the execute method you do not have to worry about any resource management, the
template will always close the request and handle any errors. Refer to the API
documentation for more information on using the execute method and the meaning of its
other method arguments.
In the above example, we first prepare a request entity that contains the
MyRequestHeader header. We then retrieve the response, and read the
MyResponseHeader and body.
Concrete implementations for the main media (mime) types are provided in the framework
and are registered by default with the RestTemplate on the client-side and with
AnnotationMethodHandlerAdapter on the server-side.
The implementations of HttpMessageConverters are described in the following
sections. For all converters a default media type is used but can be overridden by setting
the supportedMediaTypes bean property
StringHttpMessageConverter
An HttpMessageConverter implementation that can read and write Strings from the
HTTP request and response. By default, this converter supports all text media types
(text/*), and writes with a Content-Type of text/plain.
FormHttpMessageConverter
An HttpMessageConverter implementation that can read and write form data from the
HTTP request and response. By default, this converter reads and writes the media type
application/x-www-form-urlencoded. Form data is read from and written into a
MultiValueMap<String, String>.
ByteArrayHttpMessageConverter
An HttpMessageConverter implementation that can read and write byte arrays from
the HTTP request and response. By default, this converter supports all media types (*/*),
and writes with a Content-Type of application/octet-stream. This can be
overridden by setting the supportedMediaTypes property, and overriding
getContentType(byte[]).
MarshallingHttpMessageConverter
An HttpMessageConverter implementation that can read and write XML using
Spring's Marshaller and Unmarshaller abstractions from the
org.springframework.oxm package. This converter requires a Marshaller and
Unmarshaller before it can be used. These can be injected via constructor or bean
properties. By default this converter supports (text/xml) and (application/xml).
MappingJackson2HttpMessageConverter (or
MappingJacksonHttpMessageConverter with Jackson 1.x)
An HttpMessageConverter implementation that can read and write JSON using
SourceHttpMessageConverter
An HttpMessageConverter implementation that can read and write
javax.xml.transform.Source from the HTTP request and response. Only
DOMSource, SAXSource, and StreamSource are supported. By default, this converter
supports (text/xml) and (application/xml).
BufferedImageHttpMessageConverter
An HttpMessageConverter implementation that can read and write
java.awt.image.BufferedImage from the HTTP request and response. This
converter reads and writes the media type supported by the Java I/O API.
One of the main reasons to use the Business Methods Interface pattern is to ensure that
synchronization between method signatures in local interface and bean implementation
class is automatic. Another reason is that it later makes it much easier for us to switch to a
POJO (plain old Java object) implementation of the service if it makes sense to do so. Of
course well also need to implement the local home interface and provide an
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;
public void setMyComponent(MyComponent myComponent) {
this.myComponent = myComponent;
}
We can subsequently use this instance variable in any business method in the controller.
Now assuming we are obtaining our controller object out of a Spring container, we can (in
the same context) configure a LocalStatelessSessionProxyFactoryBean
instance, which will be the EJB proxy object. The configuration of the proxy, and setting of
the myComponent property of the controller is done with a configuration entry such as:
<bean id="myComponent"
class="org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean">
<property name="jndiName" value="ejb/myBean"/>
<property name="businessInterface" value="com.mycom.MyComponent"/>
</bean>
<bean id="myController" class="com.mycom.myController">
<property name="myComponent" ref="myComponent"/>
</bean>
Theres a lot of work happening behind the scenes, courtesy of the Spring AOP framework,
although you arent forced to work with AOP concepts to enjoy the results. The
myComponent bean definition creates a proxy for the EJB, which implements the
business method interface. The EJB local home is cached on startup, so theres only a
single JNDI lookup. Each time the EJB is invoked, the proxy invokes the classname
method on the local EJB and invokes the corresponding business method on the EJB.
The myController bean definition sets the myComponent property of the controller
class to the EJB proxy.
Alternatively (and preferably in case of many such proxy definitions), consider using the
<jee:local-slsb> configuration element in Spring's "jee" namespace:
<jee:local-slsb id="myComponent" jndi-name="ejb/myBean"
business-interface="com.mycom.MyComponent"/>
<bean id="myController" class="com.mycom.myController">
This EJB access mechanism delivers huge simplification of application code: the web tier
code (or other EJB client code) has no dependence on the use of EJB. If we want to
replace this EJB reference with a POJO or a mock object or other test stub, we could
simply change the myComponent bean definition without changing a line of Java code.
Additionally, we havent had to write a single line of JNDI lookup or other EJB plumbing
code as part of our application.
Benchmarks and experience in real applications indicate that the performance overhead of
this approach (which involves reflective invocation of the target EJB) is minimal, and is
typically undetectable in typical use. Remember that we dont want to make fine-grained
calls to EJBs anyway, as theres a cost associated with the EJB infrastructure in the
application server.
There is one caveat with regards to the JNDI lookup. In a bean container, this class is
normally best used as a singleton (there simply is no reason to make it a prototype).
However, if that bean container pre-instantiates singletons (as do the various XML
ApplicationContext variants) you may have a problem if the bean container is loaded
before the EJB container loads the target EJB. That is because the JNDI lookup will be
performed in the init() method of this class and then cached, but the EJB will not have
been bound at the target location yet. The solution is to not pre-instantiate this factory
object, but allow it to be created on first use. In the XML containers, this is controlled via the
lazy-init attribute.
Although this will not be of interest to the majority of Spring users, those doing
programmatic AOP work with EJBs may want to look at
LocalSlsbInvokerInterceptor.
Accessing EJB 2.x Session Beans and EJB 3 Session Beans via Spring is largely
transparent. Spring's EJB accessors, including the <jee:local-slsb> and
<jee:remote-slsb> facilities, transparently adapt to the actual component at runtime.
They handle a home interface if found (EJB 2.x style), or perform straight component
invocations if no home interface is available (EJB 3 style).
Note: For EJB 3 Session Beans, you could effectively use a JndiObjectFactoryBean
/ <jee:jndi-lookup> as well, since fully usable component references are exposed for
plain JNDI lookups there. Defining explicit <jee:local-slsb> / <jee:remoteslsb> lookups simply provides consistent and more explicit EJB access configuration.
The Spring EJB support base classes will by default create and load a Spring IoC
container as part of their lifecycle, which is then available to the EJB (for example, as used
in the code above to obtain the POJO service object). The loading is done via a strategy
object which is a subclass of BeanFactoryLocator. The actual implementation of
You would then need to create a bean definition file named beanRefContext.xml. This
file defines all bean factories (usually in the form of application contexts) that may be used
in the EJB. In many cases, this file will only contain a single bean definition such as this
(where businessApplicationContext.xml contains the bean definitions for all
business service POJOs):
<beans>
<bean id="businessBeanFactory" class="org.springframework.context.support.ClassPathXmlApplicationContext">
<constructor-arg value="businessApplicationContext.xml" />
</bean>
</beans>
interceptor that resolves Spring 2.5's @Autowired annotation in the EJB component
class:
org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor.
This interceptor can be applied through an @Interceptors annotation in the EJB
component class, or through an interceptor-binding XML element in the EJB
deployment descriptor.
@Stateless
@Interceptors(SpringBeanAutowiringInterceptor.class)
public class MyFacadeEJB implements MyFacadeLocal {
// automatically injected with a matching Spring bean
@Autowired
private MyComponent myComp;
// for business method, delegate to POJO service impl.
public String myFacadeMethod(...) {
return myComp.myMethod(...);
}
...
}
23.2.2 Connections
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 of the JMS
interfaces so that they can participate in declarative transaction management and perform
pooling of connections and sessions. In order to use this implementation, Java EE
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.
Between the ConnectionFactory and the Send operation there are three intermediate
objects that are created and destroyed. To optimise the resource usage and increase
performance two implementations of IConnectionFactory are provided.
SingleConnectionFactory
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 standard ConnectionFactory
that would typically come from JNDI.
CachingConnectionFactory
The CachingConnectionFactory extends the functionality of
SingleConnectionFactory and adds the caching of Sessions, MessageProducers,
and MessageConsumers. The initial cache size is set to 1, use the property
SessionCacheSize to increase the number of cached sessions. Note that the number of
actual cached sessions will be more than that number as sessions are cached based on
their acknowledgment mode, so there can be up to 4 cached session instances when
SessionCacheSize is set to one, one for each AcknowledgementMode.
MessageProducers and MessageConsumers are cached within their owning session and
also take into account the unique properties of the producers and consumers when
caching. MessageProducers are cached based on their destination. MessageConsumers
are cached based on a key composed of the destination, selector, noLocal delivery flag,
and the durable subscription name (if creating durable consumers).
destinations contained in JNDI and optionally falls back to the behavior contained in
DynamicDestinationResolver.
Quite often the destinations used in a JMS application are only known at runtime and
therefore cannot be administratively created when the application is deployed. This is often
because there is shared application logic between interacting system components that
create destinations at runtime according to a well-known naming convention. Even though
the creation of dynamic destinations is not part of the JMS specification, most vendors
have provided this functionality. Dynamic destinations are created with a name defined by
the user which differentiates them from temporary destinations and are often not registered
in JNDI. The API used to create dynamic destinations varies from provider to provider
since the properties associated with the destination are vendor specific. However, a simple
implementation choice that is sometimes made by vendors is to disregard the warnings in
the JMS specification and to use the TopicSession method createTopic(String
topicName) or the QueueSession method createQueue(String queueName) to
create a new destination with default destination properties. Depending on the vendor
implementation, DynamicDestinationResolver may then also create a physical
destination instead of only resolving one.
The boolean property pubSubDomain is used to configure the JmsTemplate with
knowledge of what JMS domain is being used. By default the value of this property is false,
indicating that the point-to-point domain, Queues, will be used. This property used by
JmsTemplate determines the behavior of dynamic destination resolution via
implementations of the DestinationResolver interface.
You can also configure the JmsTemplate with a default destination via the property
defaultDestination. The default destination will be used with send and receive operations
that do not refer to a specific destination.
SimpleMessageListenerContainer
This message listener container is the simpler of the two standard flavors. It creates a fixed
number of JMS sessions and consumers at startup, registers the listener using the
standard JMS MessageConsumer.setMessageListener() method, and leaves it up
the JMS provider to perform listener callbacks. This variant does not allow for dynamic
adaption to runtime demands or for participation in externally managed transactions.
Compatibility-wise, it stays very close to the spirit of the standalone JMS specification - but
is generally not compatible with Java EE's JMS restrictions.
DefaultMessageListenerContainer
This message listener container is the one used in most cases. In contrast to
SimpleMessageListenerContainer, this container variant does allow for dynamic
adaption to runtime demands and is able to participate in externally managed transactions.
Each received message is registered with an XA transaction when configured with a
JtaTransactionManager; so processing may take advantage of XA transaction
semantics. This listener container strikes a good balance between low requirements on the
JMS provider, advanced functionality such as transaction participation, and compatibility
with Java EE environments.
javax.jms.ConnectionFactory;
javax.jms.JMSException;
javax.jms.Message;
javax.jms.Queue;
javax.jms.Session;
import org.springframework.jms.core.MessageCreator;
import org.springframework.jms.core.JmsTemplate;
public class JmsQueueSender {
private JmsTemplate jmsTemplate;
private Queue queue;
This example uses the MessageCreator callback to create a text message from the
supplied Session object. The JmsTemplate is constructed by passing a reference to a
ConnectionFactory. As an alternative, a zero argument constructor and
connectionFactory is provided and can be used for constructing the instance in JavaBean
style (using a BeanFactory or plain Java code). Alternatively, consider deriving from
Spring's JmsGatewaySupport convenience base class, which provides pre-built bean
properties for JMS configuration.
The method send(String destinationName, MessageCreator creator) lets
you send 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.
message.setJMSCorrelationID("123-00001");
return message;
}
});
}
javax.jms.JMSException;
javax.jms.Message;
javax.jms.MessageListener;
javax.jms.TextMessage;
Once you've implemented your MessageListener, it's time to create a message listener
container.
Find below an example of how to define and configure one of the message listener
containers that ships with Spring (in this case the
DefaultMessageListenerContainer).
<!-- this is the Message Driven POJO (MDP) -->
<bean id="messageListener" class="jmsexample.ExampleListener" />
<!-- and this is the message listener container -->
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="destination" ref="destination"/>
<property name="messageListener" ref="messageListener" />
</bean>
Please refer to the Spring Javadoc of the various message listener containers for a full
description of the features supported by each implementation.
You can choose to have your MDPs implement this interface (in preference to the standard
JMS MessageListener interface) if you want your MDPs to be able to respond to any
received messages (using the Session supplied in the onMessage(Message,
Session) method). All of the message listener container implementations that ship with
Spring have support for MDPs that implement either the MessageListener or
SessionAwareMessageListener interface. Classes that implement the
SessionAwareMessageListener come with the caveat that they are then tied to
Spring through the interface. The choice of whether or not to use it is left entirely up to you
as an application developer or architect.
Please note that the 'onMessage(..)' method of the
SessionAwareMessageListener interface throws JMSException. In contrast to the
standard JMS MessageListener interface, when using the
SessionAwareMessageListener interface, it is the responsibility of the client code to
handle any exceptions thrown.
In particular, note how the above implementation of the MessageDelegate interface (the
above DefaultMessageDelegate class) has no JMS dependencies at all. It truly is a
POJO that we will make into an MDP via the following configuration.
<!-- this is the Message Driven POJO (MDP) -->
<bean id="messageListener" class="org.springframework.jms.listener.adapter.MessageListenerAdapter">
<constructor-arg>
<bean class="jmsexample.DefaultMessageDelegate"/>
</constructor-arg>
</bean>
<!-- and this is the message listener container... -->
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="destination" ref="destination"/>
<property name="messageListener" ref="messageListener" />
</bean>
Below is an example of another MDP that can only handle the receiving of JMS
TextMessage messages. Notice how the message handling method is actually called
'receive' (the name of the message handling method in a
MessageListenerAdapter defaults to 'handleMessage'), but it is configurable (as
you will see below). Notice also how the 'receive(..)' method is strongly typed to
receive and respond only to JMS TextMessage messages.
public interface TextMessageDelegate {
void receive(TextMessage message);
}
public class DefaultTextMessageDelegate implements TextMessageDelegate {
// implementation elided for clarity...
}
Please note that if the above 'messageListener' receives a JMS Message of a type
other than TextMessage, an IllegalStateException will be thrown (and
subsequently swallowed). Another of the capabilities of the MessageListenerAdapter
class is the ability to automatically send back a response Message if a handler method
returns a non-void value. Consider the interface and class:
public interface ResponsiveTextMessageDelegate {
// notice the return type...
String receive(TextMessage message);
}
public class DefaultResponsiveTextMessageDelegate implements ResponsiveTextMessageDelegate {
// implementation elided for clarity...
}
Then you just need to add it to our earlier container configuration. The container will take
care of the rest.
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="destination" ref="destination"/>
<property name="messageListener" ref="messageListener"/>
<property name="transactionManager" ref="transactionManager"/>
</bean>
The specified WorkManager may also point to an environment-specific thread pool typically through SimpleTaskWorkManager's "asyncTaskExecutor" property.
Consider defining a shared thread pool for all your ResourceAdapter instances if you
happen to use multiple adapters.
In some environments (e.g. WebLogic 9 or above), the entire ResourceAdapter object
may be obtained from JNDI instead (using <jee:jndi-lookup>). The Spring-based
message listeners can then interact with the server-hosted ResourceAdapter, also
using the server's built-in WorkManager.
Please consult the JavaDoc for JmsMessageEndpointManager,
JmsActivationSpecConfig, and ResourceAdapterFactoryBean for more
details.
Spring also provides a generic JCA message endpoint manager which is not tied to JMS:
org.springframework.jca.endpoint.GenericMessageEndpointManager.
This component allows for using any message listener type (e.g. a CCI MessageListener)
and any provider-specific ActivationSpec object. Check out your JCA provider's
documentation to find out about the actual capabilities of your connector, and consult
GenericMessageEndpointManager's JavaDoc for the Spring-specific configuration
details.
Note
JCA-based message endpoint management is very analogous to EJB
2.1 Message-Driven Beans; it uses the same underlying resource
provider contract. Like with EJB 2.1 MDBs, any message listener
interface supported by your JCA provider can be used in the Spring
context as well. Spring nevertheless provides explicit 'convenience'
support for JMS, simply because JMS is the most common endpoint
API used with the JCA endpoint management contract.
The example above is equivalent to creating two distinct listener container bean definitions
and two distinct MessageListenerAdapter bean definitions as demonstrated in
Section 23.4.4, The MessageListenerAdapter. In addition to the attributes shown
above, the listener element may contain several optional ones. The following table
describes all available attributes:
Description
id
destination
(required)
ref
(required)
method
responsedestination
The following table describes all available attributes. Consult the class-level Javadoc of
the AbstractMessageListenerContainer and its concrete subclasses for more
details on the individual properties. The Javadoc also provides a discussion of transaction
choices and message redelivery scenarios.
Description
containertype
connectionfactory
task-executor
destinationresolver
messageconverter
destinationtype
client-id
cache
concurrency
prefetch
Configuring a JCA-based listener container with the "jms" schema support is very similar.
<jms:jca-listener-container resource-adapter="myResourceAdapter"
destination-resolver="myDestinationResolver"
transaction-manager="myTransactionManager"
concurrency="10">
<jms:listener destination="queue.orders" ref="myMessageListener"/>
</jms:jca-listener-container>
The available configuration options for the JCA variant are described in the following table:
Description
resourceadapter
activationspec-factory
destinationresolver
messageconverter
destinationtype
client-id
transactionmanager
concurrency
prefetch
24. JMX
24.1 Introduction
The JMX support in Spring provides you with the features to easily and transparently
integrate your Spring application into a JMX infrastructure.
Specifically, Spring's JMX support provides four
core features:
The automatic registration of any Spring bean
as a JMX MBean
A flexible mechanism for controlling the
management interface of your beans
The declarative exposure of MBeans over
remote, JSR-160 connectors
The simple proxying of both local and remote
JMX?
This chapter is not an
introduction to JMX... it doesn't
try to explain the motivations of
why one might want to use JMX
(or indeed what the letters JMX
actually stand for). If you are new
to JMX, check out Section 24.8,
Further Resources at the end
of this chapter.
MBean resources
These features are designed to work without coupling your application components to
either Spring or JMX interfaces and classes. Indeed, for the most part your application
classes need not be aware of either Spring or JMX in order to take advantage of the Spring
JMX features.
To expose the properties and methods of this bean as attributes and operations of an
MBean you simply configure an instance of the MBeanExporter class in your
configuration file and pass in the bean as shown below:
<beans>
<!-- this bean must not be lazily initialized if the exporting is to happen -->
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter" lazy-init="false">
<property name="beans">
<map>
<entry key="bean:name=testBean1" value-ref="testBean"/>
</map>
</property>
</bean>
<bean id="testBean" class="org.springframework.jmx.JmxTestBean">
<property name="name" value="TEST"/>
<property name="age" value="100"/>
</bean>
</beans>
The pertinent bean definition from the above configuration snippet is the exporter bean.
The beans property tells the MBeanExporter exactly which of your beans must be
exported to the JMX MBeanServer. In the default configuration, the key of each entry in
the beans Map is used as the ObjectName for the bean referenced by the corresponding
entry value. This behavior can be changed as described in Section 24.4, Controlling the
ObjectNames for your beans.
With this configuration the testBean bean is exposed as an MBean under the
ObjectName bean:name=testBean1. By default, all public properties of the bean are
exposed as attributes and all public methods (bar those inherited from the Object class)
are exposed as operations.
For platforms/cases where the existing MBeanServer has a dynamic (or unknown)
agentId which is retrieved through lookup methods, one should use factory-method:
<beans>
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="server">
<!-- Custom MBeanServerLocator -->
<bean class="platform.package.MBeanServerLocator" factory-method="locateMBeanServer"/>
</property>
<!-- other beans here -->
</bean>
</beans>
Here, the bean called spring:mbean=true is already a valid JMX MBean and will be
automatically registered by Spring. By default, beans that are autodetected for JMX
registration have their bean name used as the ObjectName. This behavior can be
overridden as detailed in Section 24.4, Controlling the ObjectNames for your beans.
It is possible to control the behavior of exactly what happens when an MBean is registered
with an MBeanServer. Spring's JMX support allows for three different registration
behaviors to control the registration behavior when the registration process finds that an
MBean has already been registered under the same ObjectName; these registration
behaviors are summarized on the following table:
Explanation
REGISTRATION_IGNORE_EXISTING
In the previous example, you had little control over the management interface of your bean;
all of the public properties and methods of each exported bean was exposed as JMX
attributes and operations respectively. To exercise finer-grained control over exactly which
properties and methods of your exported beans are actually exposed as JMX attributes
and operations, Spring JMX provides a comprehensive and extensible mechanism for
controlling the management interfaces of your beans.
this.name = name;
}
@ManagedAttribute(defaultValue="foo", persistPeriod=300)
public String getName() {
return name;
}
@ManagedOperation(description="Add two numbers")
@ManagedOperationParameters({
@ManagedOperationParameter(name = "x", description = "The first number"),
@ManagedOperationParameter(name = "y", description = "The second number")})
public int add(int x, int y) {
return x + y;
}
public void dontExposeMe() {
throw new RuntimeException();
}
}
Here you can see that the JmxTestBean class is marked with the ManagedResource
annotation and that this ManagedResource annotation is configured with a set of
properties. These properties can be used to configure various aspects of the MBean that is
generated by the MBeanExporter, and are explained in greater detail later in section
entitled Section 24.3.3, Source-Level Metadata Types.
You will also notice that both the age and name properties are annotated with the
ManagedAttribute annotation, but in the case of the age property, only the getter is
marked. This will cause both of these properties to be included in the management
interface as attributes, but the age attribute will be read-only.
Finally, you will notice that the add(int, int) method is marked with the
ManagedOperation attribute whereas the dontExposeMe() method is not. This will
cause the management interface to contain only one operation, add(int, int), when
using the MetadataMBeanInfoAssembler.
The configuration below shows how you configure the MBeanExporter to use the
MetadataMBeanInfoAssembler:
<beans>
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="assembler" ref="assembler"/>
<property name="namingStrategy" ref="namingStrategy"/>
<property name="autodetect" value="true"/>
</bean>
<bean id="jmxAttributeSource"
class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource"/>
<!-- will create management interface using annotation metadata -->
<bean id="assembler"
class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler">
<property name="attributeSource" ref="jmxAttributeSource"/>
</bean>
<!-- will pick up the ObjectName from the annotation -->
<bean id="namingStrategy"
class="org.springframework.jmx.export.naming.MetadataNamingStrategy">
<property name="attributeSource" ref="jmxAttributeSource"/>
</bean>
<bean id="testBean" class="org.springframework.jmx.AnnotationTestBean">
<property name="name" value="TEST"/>
<property name="age" value="100"/>
</bean>
</beans>
Here you can see that an MetadataMBeanInfoAssembler bean has been configured
with an instance of the AnnotationJmxAttributeSource class and passed to the
MBeanExporter through the assembler property. This is all that is required to take
advantage of metadata-driven management interfaces for your Spring-exposed MBeans.
Annotation
Annotation
Type
@ManagedResource
Class
@ManagedOperation
Method
@ManagedAttribute
Method (only
getters and
setters)
@ManagedOperationParameter
and
Method
@ManagedOperationParameters
The following configuration parameters are available for use on these source-level
metadata types:
Description
Applies to
ObjectName
Used by
MetadataNamingStrategy
ManagedResource
to determine the ObjectName
of a managed resource
description
ManagedResource,
ManagedAttribute,
ManagedOperation,
ManagedOperationParameter
ManagedResource,
ManagedAttribute
defaultValue
ManagedAttribute
log
ManagedResource
logFile
ManagedResource
persistPolicy
ManagedResource
persistPeriod
ManagedResource
persistLocation
ManagedResource
persistName
ManagedResource
name
ManagedOperationParameter
index
ManagedOperationParameter
index
parameter
ManagedOperationParameter
Notice that in this configuration no beans are passed to the MBeanExporter; however,
the JmxTestBean will still be registered since it is marked with the ManagedResource
attribute and the MetadataMBeanInfoAssembler detects this and votes to include it.
The only problem with this approach is that the name of the JmxTestBean now has
business meaning. You can address this issue by changing the default behavior for
ObjectName creation as defined in Section 24.4, Controlling the ObjectNames for your
beans.
This interface defines the methods and properties that will be exposed as operations and
attributes on the JMX MBean. The code below shows how to configure Spring JMX to use
this interface as the definition for the management interface:
<beans>
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="bean:name=testBean5" value-ref="testBean"/>
</map>
</property>
<property name="assembler">
<bean class="org.springframework.jmx.export.assembler.InterfaceBasedMBeanInfoAssembler">
<property name="managedInterfaces">
<value>org.springframework.jmx.IJmxTestBean</value>
</property>
</bean>
</property>
</bean>
<bean id="testBean" class="org.springframework.jmx.JmxTestBean">
<property name="name" value="TEST"/>
<property name="age" value="100"/>
</bean>
</beans>
Here you can see that the methods add and myOperation will be exposed as JMX
operations and getName(), setName(String) and getAge() will be exposed as the
appropriate half of a JMX attribute. In the code above, the method mappings apply to
beans that are exposed to JMX. To control method exposure on a bean-by-bean basis, use
the methodMappings property of MethodNameMBeanInfoAssembler to map bean
names to lists of method names.
You can provide a reference to a particular MBean server if necessary, and the
defaultDomain attribute (a property of AnnotationMBeanExporter) accepts an
alternate value for the generated MBean ObjectNames' domains. This would be used in
place of the fully qualified package name as described in the previous section on
MetadataNamingStrategy.
@EnableMBeanExport(server="myMBeanServer", defaultDomain="myDomain")
@Configuration
ContextConfiguration {
}
Note
Do not use interface-based AOP proxies in combination with
autodetection of JMX annotations in your bean classes. Interfacebased proxies 'hide' the target class, which also hides the JMX
managed resource annotations. Hence, use target-class proxies in that
case: through setting the 'proxy-target-class' flag on <aop:config/>,
<tx:annotation-driven/>, etc. Otherwise, your JMX beans
might be silently ignored at startup...
If the ObjectName property is set Spring will automatically register your connector with
the MBeanServer under that ObjectName. The example below shows the full set of
parameters which you can pass to the ConnectorServerFactoryBean when creating
a JMXConnector:
<bean id="serverConnector"
class="org.springframework.jmx.support.ConnectorServerFactoryBean">
<property name="objectName" value="connector:name=iiop"/>
<property name="serviceUrl"
value="service:jmx:iiop://localhost/jndi/iiop://localhost:900/myconnector"/>
<property name="threaded" value="true"/>
<property name="daemon" value="true"/>
<property name="environment">
<map>
<entry key="someKey" value="someValue"/>
</map>
</property>
</bean>
Note that when using a RMI-based connector you need the lookup service (tnameserv or
rmiregistry) to be started in order for the name registration to complete. If you are using
Spring to export remote services for you via RMI, then Spring will already have constructed
an RMI registry. If not, you can easily start a registry using the following snippet of
configuration:
In the case of the above example, MX4J 3.0.0 was used; see the official MX4J
documentation for more information.
Here you can see that a proxy is created for the MBean registered under the
ObjectName: bean:name=testBean. The set of interfaces that the proxy will
implement is controlled by the proxyInterfaces property and the rules for mapping
methods and properties on these interfaces to operations and attributes on the MBean are
the same rules used by the InterfaceBasedMBeanInfoAssembler.
The MBeanProxyFactoryBean can create a proxy to any MBean that is accessible via
an MBeanServerConnection. By default, the local MBeanServer is located and used,
but you can override this and provide an MBeanServerConnection pointing to a
remote MBeanServer to cater for proxies pointing to remote MBeans:
<bean id="clientConnector"
class="org.springframework.jmx.support.MBeanServerConnectionFactoryBean">
<property name="serviceUrl" value="service:jmx:rmi://remotehost:9875"/>
</bean>
<bean id="proxy" class="org.springframework.jmx.access.MBeanProxyFactoryBean">
<property name="objectName" value="bean:name=testBean"/>
<property name="proxyInterface" value="org.springframework.jmx.IJmxTestBean"/>
<property name="server" ref="clientConnector"/>
</bean>
24.7 Notifications
Spring's JMX offering includes comprehensive support for JMX notifications.
javax.management.AttributeChangeNotification;
javax.management.Notification;
javax.management.NotificationFilter;
javax.management.NotificationListener;
<beans>
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="bean:name=testBean1" value-ref="testBean"/>
</map>
</property>
<property name="notificationListenerMappings">
<map>
<entry key="bean:name=testBean1">
<bean class="com.example.ConsoleLoggingNotificationListener"/>
</entry>
</map>
</property>
</bean>
<bean id="testBean" class="org.springframework.jmx.JmxTestBean">
<property name="name" value="TEST"/>
<property name="age" value="100"/>
</bean>
</beans>
With the above configuration in place, every time a JMX Notification is broadcast
from the target MBean (bean:name=testBean1), the
ConsoleLoggingNotificationListener bean that was registered as a listener via
the notificationListenerMappings property will be notified. The
ConsoleLoggingNotificationListener bean can then take whatever action it
deems appropriate in response to the Notification.
You can also use straight bean names as the link between exported beans and listeners:
<beans>
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="bean:name=testBean1" value-ref="testBean"/>
</map>
</property>
<property name="notificationListenerMappings">
<map>
<entry key="testBean">
<bean class="com.example.ConsoleLoggingNotificationListener"/>
</entry>
</map>
</property>
</bean>
<bean id="testBean" class="org.springframework.jmx.JmxTestBean">
<property name="name" value="TEST"/>
<property name="age" value="100"/>
</bean>
</beans>
If one wants to register a single NotificationListener instance for all of the beans
that the enclosing MBeanExporter is exporting, one can use the special wildcard '*'
(sans quotes) as the key for an entry in the notificationListenerMappings
property map; for example:
<property name="notificationListenerMappings">
<map>
<entry key="*">
<bean class="com.example.ConsoleLoggingNotificationListener"/>
</entry>
</map>
</property>
If one needs to do the inverse (that is, register a number of distinct listeners against an
MBean), then one has to use the notificationListeners list property instead (and in
preference to the notificationListenerMappings property). This time, instead of
configuring simply a NotificationListener for a single MBean, one configures
NotificationListenerBean instances... a NotificationListenerBean
encapsulates a NotificationListener and the ObjectName (or ObjectNames)
that it is to be registered against in an MBeanServer. The
NotificationListenerBean also encapsulates a number of other properties such as
a NotificationFilter and an arbitrary handback object that can be used in
advanced JMX notification scenarios.
The configuration when using NotificationListenerBean instances is not wildly
different to what was presented previously:
<beans>
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="bean:name=testBean1" value-ref="testBean"/>
</map>
</property>
<property name="notificationListeners">
<list>
<bean class="org.springframework.jmx.export.NotificationListenerBean">
<constructor-arg>
<bean class="com.example.ConsoleLoggingNotificationListener"/>
</constructor-arg>
<property name="mappedObjectNames">
<list>
<value>bean:name=testBean1</value>
</list>
</property>
</bean>
</list>
</property>
</bean>
<bean id="testBean" class="org.springframework.jmx.JmxTestBean">
<property name="name" value="TEST"/>
<property name="age" value="100"/>
</bean>
</beans>
The above example is equivalent to the first notification example. Lets assume then that
we want to be given a handback object every time a Notification is raised, and that
additionally we want to filter out extraneous Notifications by supplying a
NotificationFilter. (For a full discussion of just what a handback object is, and
indeed what a NotificationFilter is, please do consult that section of the JMX
specification (1.2) entitled 'The JMX Notification Model'.)
<beans>
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="bean:name=testBean1" value-ref="testBean1"/>
<entry key="bean:name=testBean2" value-ref="testBean2"/>
</map>
</property>
<property name="notificationListeners">
<list>
<bean class="org.springframework.jmx.export.NotificationListenerBean">
<constructor-arg ref="customerNotificationListener"/>
<property name="mappedObjectNames">
<list>
<!-- handles notifications from two distinct MBeans -->
<value>bean:name=testBean1</value>
<value>bean:name=testBean2</value>
</list>
</property>
<property name="handback">
<bean class="java.lang.String">
<constructor-arg value="This could be anything..."/>
</bean>
</property>
<property name="notificationFilter" ref="customerNotificationListener"/>
</bean>
</list>
</property>
</bean>
<!-- implements both the NotificationListener and NotificationFilter interfaces -->
<bean id="customerNotificationListener" class="com.example.ConsoleLoggingNotificationListener"/>
<bean id="testBean1" class="org.springframework.jmx.JmxTestBean">
<property name="name" value="TEST"/>
<property name="age" value="100"/>
</bean>
<bean id="testBean2" class="org.springframework.jmx.JmxTestBean">
<property name="name" value="ANOTHER TEST"/>
<property name="age" value="200"/>
</bean>
</beans>
Note that the NotificationPublisher will be set after the managed bean has been
registered with an MBeanServer.
Using a NotificationPublisher instance is quite straightforward... one simply
creates a JMX Notification instance (or an instance of an appropriate
Notification subclass), populates the notification with the data pertinent to the event
that is to be published, and one then invokes the
sendNotification(Notification) on the NotificationPublisher instance,
passing in the Notification.
Find below a simple example... in this scenario, exported instances of the JmxTestBean
are going to publish a NotificationEvent every time the add(int, int) operation
is invoked.
package org.springframework.jmx;
import org.springframework.jmx.export.notification.NotificationPublisherAware;
import org.springframework.jmx.export.notification.NotificationPublisher;
import javax.management.Notification;
public class JmxTestBean implements IJmxTestBean, NotificationPublisherAware {
private
private
private
private
String name;
int age;
boolean isSuperman;
NotificationPublisher publisher;
The NotificationPublisher interface and the machinery to get it all working is one
of the nicer features of Spring's JMX support. It does however come with the price tag of
coupling your classes to both Spring and JMX; as always, the advice here is to be
pragmatic... if you need the functionality offered by the NotificationPublisher and
you can accept the coupling to both Spring and JMX, then do so.
In non-managed mode, you must configure the ConnectionFactory you want to use in
the configuration of Spring as a JavaBean. The LocalConnectionFactoryBean class
offers this setup style, passing in the ManagedConnectionFactory implementation of
your connector, exposing the application-level CCI ConnectionFactory.
<bean id="eciManagedConnectionFactory" class="com.ibm.connector2.cics.ECIManagedConnectionFactory">
<property name="serverName" value="TXSERIES"/>
<property name="connectionURL" value="tcp://localhost/"/>
<property name="portNumber" value="2006"/>
</bean>
<bean id="eciConnectionFactory" class="org.springframework.jca.support.LocalConnectionFactoryBean">
<property name="managedConnectionFactory" ref="eciManagedConnectionFactory"/>
</bean>
Note
You can't directly instantiate a specific ConnectionFactory. You
need to go through the corresponding implementation of the
ManagedConnectionFactory interface for your connector. This
interface is part of the JCA SPI specification.
</bean>
</property>
</bean>
Note
This ConnectionFactory adapter cannot directly be configured
with a ConnectionSpec. Use an intermediary
ConnectionSpecConnectionFactoryAdapter that the
SingleConnectionFactory talks to if you require a single
connection for a specific ConnectionSpec.
An output Record can be used to receive data back from the EIS. Hence, a specific
implementation of the RecordExtractor interface can be passed to Spring's
CciTemplate for extracting data from the output Record.
public interface RecordExtractor {
Object extractData(Record record) throws ResourceException, SQLException, DataAccessException;
}
Depending on the template method called, CciTemplate will know which execute
method to call on the interaction. In any case, a correctly initialized InteractionSpec
instance is mandatory.
CciTemplate.execute(..) can be used in two ways:
With direct Record arguments. In this case, you simply need to pass the CCI input
record in, and the returned object be the corresponding CCI output record.
With application objects, using record mapping. In this case, you need to provide
corresponding RecordCreator and RecordExtractor instances.
With the first approach, the following methods of the template will be used. These methods
directly correspond to those on the Interaction interface.
public class CciTemplate implements CciOperations {
public Record execute(InteractionSpec spec, Record inputRecord)
throws DataAccessException { ... }
public void execute(InteractionSpec spec, Record inputRecord, Record outputRecord)
throws DataAccessException { ... }
}
With the second approach, we need to specify the record creation and record extraction
strategies as arguments. The interfaces used are those describe in the previous section on
Unless the outputRecordCreator property is set on the template (see the following
section), every method will call the corresponding execute method of the CCI
Interaction with two parameters: InteractionSpec and input Record, receiving
an output Record as return value.
CciTemplate also provides methods to create IndexRecord and MappedRecord
outside a RecordCreator implementation, through its createIndexRecord(..) and
createMappedRecord(..) methods. This can be used within DAO implementations to
create Record instances to pass into corresponding CciTemplate.execute(..)
methods.
public class CciTemplate implements CciOperations {
public IndexedRecord createIndexedRecord(String name) throws DataAccessException { ... }
public MappedRecord createMappedRecord(String name) throws DataAccessException { ... }
}
cciTemplate.setOutputRecordCreator(new EciOutputRecordCreator());
Note
As the CciTemplate class is thread-safe, it will usually be configured
as a shared instance.
25.3.5 Summary
The following table summarizes the mechanisms of the CciTemplate class and the
corresponding methods called on the CCI Interaction interface:
CciTemplate
outputRecordCreator
property
execute method
called on the CCI
Interaction
Record
execute(InteractionSpec,
Record)
not set
Record
execute(InteractionSpec,
Record)
Record
execute(InteractionSpec,
Record)
set
boolean
execute(InteractionSpec,
Record, Record)
void
execute(InteractionSpec,
Record, Record)
not set
void
execute(InteractionSpec,
Record, Record)
void
execute(InteractionSpec,
Record, Record)
set
void
execute(InteractionSpec,
Record, Record)
Record
execute(InteractionSpec,
RecordCreator)
not set
Record
execute(InteractionSpec,
Record)
Record
execute(InteractionSpec,
RecordCreator)
set
void
execute(InteractionSpec,
Record, Record)
Record
execute(InteractionSpec,
Record, RecordExtractor)
not set
Record
execute(InteractionSpec,
Record)
Record
execute(InteractionSpec,
Record, RecordExtractor)
set
void
execute(InteractionSpec,
Record, Record)
Record
execute(InteractionSpec,
RecordCreator,
RecordExtractor)
not set
Record
execute(InteractionSpec,
Record)
Record
execute(InteractionSpec,
RecordCreator,
RecordExtractor)
set
void
execute(InteractionSpec,
Record, Record)
Note
InteractionSpec objects can either be shared across multiple
template calls or newly created inside every callback method. This is
completely up to the DAO implementation.
Then the program can use CCI via Spring's template and specify mappings between
custom objects and CCI Records.
public class MyDaoImpl extends CciDaoSupport implements MyDao {
public OutputObject getData(InputObject input) {
ECIInteractionSpec interactionSpec = ...;
OutputObject output = (ObjectOutput) getCciTemplate().execute(interactionSpec,
new RecordCreator() {
public Record createRecord(RecordFactory recordFactory) throws ResourceException {
return new CommAreaRecord(input.toString().getBytes());
}
},
new RecordExtractor() {
public Object extractData(Record record) throws ResourceException {
CommAreaRecord commAreaRecord = (CommAreaRecord)record;
String str = new String(commAreaRecord.toByteArray());
String field1 = string.substring(0,6);
String field2 = string.substring(6,1);
return new OutputObject(Long.parseLong(field1), field2);
}
});
return output;
}
}
Note
With a ConnectionCallback, the Connection used will be
managed and closed by the CciTemplate, but any interactions
created on the connection must be managed by the callback
implementation.
For a more specific callback, you can implement an InteractionCallback. The
passed-in Interaction will be managed and closed by the CciTemplate in this case.
public class MyDaoImpl extends CciDaoSupport implements MyDao {
public String getData(String input) {
ECIInteractionSpec interactionSpec = ...;
String output = (String) getCciTemplate().execute(interactionSpec,
new InteractionCallback() {
public Object doInInteraction(Interaction interaction, ConnectionFactory factory)
throws ResourceException {
Record input = new CommAreaRecord(inputString.getBytes());
Record output = new CommAreaRecord();
interaction.execute(holder.getInteractionSpec(), input, output);
return new String(output.toByteArray());
}
});
return output;
}
}
For the examples above, the corresponding configuration of the involved Spring beans
could look like this in non-managed mode:
<bean id="managedConnectionFactory" class="com.ibm.connector2.cics.ECIManagedConnectionFactory">
<property name="serverName" value="TXSERIES"/>
<property name="connectionURL" value="local:"/>
<property name="userName" value="CICSUSER"/>
<property name="password" value="CICS"/>
</bean>
<bean id="connectionFactory" class="org.springframework.jca.support.LocalConnectionFactoryBean">
<property name="managedConnectionFactory" ref="managedConnectionFactory"/>
</bean>
<bean id="component" class="mypackage.MyDaoImpl">
<property name="connectionFactory" ref="connectionFactory"/>
</bean>
In managed mode (that is, in a Java EE environment), the configuration could look as
follows:
<jee:jndi-lookup id="connectionFactory" jndi-name="eis/cicseci"/>
<bean id="component" class="MyDaoImpl">
<property name="connectionFactory" ref="connectionFactory"/>
</bean>
25.4.1 MappingRecordOperation
MappingRecordOperation essentially performs the same work as CciTemplate, but
represents a specific, pre-configured operation as an object. It provides two template
methods to specify how to convert an input object to a input record, and how to convert an
output record to an output object (record mapping):
createInputRecord(..) to specify how to convert an input object to an input
Record
extractOutputData(..) to specify how to extract an output object from an output
Record
Here are the signatures of these methods:
public abstract class MappingRecordOperation extends EisOperation {
...
protected abstract Record createInputRecord(RecordFactory recordFactory, Object inputObject)
throws ResourceException, DataAccessException { ... }
protected abstract Object extractOutputData(Record outputRecord)
throws ResourceException, SQLException, DataAccessException { ... }
...
}
Thereafter, in order to execute an EIS operation, you need to use a single execute method,
passing in an application-level input object and receiving an application-level output object
as result:
public abstract class MappingRecordOperation extends EisOperation {
...
public Object execute(Object inputObject) throws DataAccessException {
...
}
As you can see, contrary to the CciTemplate class, this execute(..) method does
not have an InteractionSpec as argument. Instead, the InteractionSpec is global
to the operation. The following constructor must be used to instantiate an operation object
with a specific InteractionSpec:
InteractionSpec spec = ...;
MyMappingRecordOperation eisOperation = new MyMappingRecordOperation(getConnectionFactory(), spec);
...
25.4.2 MappingCommAreaOperation
Some connectors use records based on a COMMAREA which represents an array of bytes
containing parameters to send to the EIS and data returned by it. Spring provides a special
operation class for working directly on COMMAREA rather than on records. The
MappingCommAreaOperation class extends the MappingRecordOperation class
to provide such special COMMAREA support. It implicitly uses the CommAreaRecord
class as input and output record type, and provides two new methods to convert an input
object into an input COMMAREA and the output COMMAREA into an output object.
object into an input COMMAREA and the output COMMAREA into an output object.
public abstract class MappingCommAreaOperation extends MappingRecordOperation {
...
protected abstract byte[] objectToBytes(Object inObject)
throws IOException, DataAccessException;
protected abstract Object bytesToObject(byte[] bytes)
throws IOException, DataAccessException;
...
}
25.4.4 Summary
The operation object approach uses records in the same manner as the CciTemplate
class.
MappingRecordOperation
outputRecordCreator
property
execute method
called on the CCI
Interaction
Object execute(Object)
not set
Record
execute(InteractionSpec,
Record)
Object execute(Object)
set
boolean
execute(InteractionSpec,
Record, Record)
Then the application can execute the operation object, with the person identifier as
argument. Note that operation object could be set up as shared instance, as it is threadsafe.
public class MyDaoImpl extends CciDaoSupport implements MyDao {
public Person getPerson(int id) {
PersonMappingOperation query = new PersonMappingOperation(getConnectionFactory());
Person person = (Person) query.execute(new Integer(id));
return person;
}
}
In managed mode (that is, in a Java EE environment), the configuration could look as
follows:
<jee:jndi-lookup id="targetConnectionFactory" jndi-name="eis/blackbox"/>
<bean id="connectionFactory"
class="org.springframework.jca.cci.connection.ConnectionSpecConnectionFactoryAdapter">
<property name="targetConnectionFactory" ref="targetConnectionFactory"/>
<property name="connectionSpec">
<bean class="com.sun.connector.cciblackbox.CciConnectionSpec">
<property name="user" value="sa"/>
<property name="password" value=""/>
</bean>
</property>
</bean>
<bean id="component" class="MyDaoImpl">
<property name="connectionFactory" ref="connectionFactory"/>
</bean>
accessing a CICS with ECI mode with the IBM CICS ECI connector.
Firstly, the CCI InteractionSpec needs to be initialized to specify which CICS
program to access and how to interact with it.
public abstract class EciMappingOperation extends MappingCommAreaOperation {
public EciMappingOperation(ConnectionFactory connectionFactory, String programName) {
setConnectionFactory(connectionFactory);
ECIInteractionSpec interactionSpec = new ECIInteractionSpec(),
interactionSpec.setFunctionName(programName);
interactionSpec.setInteractionVerb(ECIInteractionSpec.SYNC_SEND_RECEIVE);
interactionSpec.setCommareaLength(30);
setInteractionSpec(interactionSpec);
setOutputRecordCreator(new EciOutputRecordCreator());
}
private static class EciOutputRecordCreator implements RecordCreator {
public Record createRecord(RecordFactory recordFactory) throws ResourceException {
return new CommAreaRecord();
}
}
}
In managed mode (that is, in a Java EE environment), the configuration could look as
follows:
<jee:jndi-lookup id="connectionFactory" jndi-name="eis/cicseci"/>
<bean id="component" class="MyDaoImpl">
<property name="connectionFactory" ref="connectionFactory"/>
</bean>
25.5 Transactions
JCA specifies several levels of transaction support for resource adapters. The kind of
transactions that your resource adapter supports is specified in its ra.xml file. There are
essentially three options: none (for example with CICS EPI connector), local transactions
(for example with a CICS ECI connector), global transactions (for example with an IMS
connector).
<connector>
<resourceadapter>
<!-- <transaction-support>NoTransaction</transaction-support> -->
<!-- <transaction-support>LocalTransaction</transaction-support> -->
<transaction-support>XATransaction</transaction-support>
<resourceadapter>
<connector>
For global transactions, you can use Spring's generic transaction infrastructure to
demarcate transactions, with JtaTransactionManager as backend (delegating to the
Java EE server's distributed transaction coordinator underneath).
For local transactions on a single CCI ConnectionFactory, Spring provides a specific
transaction management strategy for CCI, analogous to the
DataSourceTransactionManager for JDBC. The CCI API defines a local transaction
object and corresponding local transaction demarcation methods. Spring's
CciLocalTransactionManager executes such local CCI transactions, fully compliant
with Spring's generic PlatformTransactionManager abstraction.
<jee:jndi-lookup id="eciConnectionFactory" jndi-name="eis/cicseci"/>
<bean id="eciTransactionManager"
class="org.springframework.jca.cci.connection.CciLocalTransactionManager">
<property name="connectionFactory" ref="eciConnectionFactory"/>
</bean>
Both transaction strategies can be used with any of Spring's transaction demarcation
facilities, be it declarative or programmatic. This is a consequence of Spring's generic
PlatformTransactionManager abstraction, which decouples transaction
demarcation from the actual execution strategy. Simply switch between
JtaTransactionManager and CciLocalTransactionManager as needed,
keeping your transaction demarcation as-is.
For more information on Spring's transaction facilities, see the chapter entitled Chapter 12,
Transaction Management.
26. Email
26.1 Introduction
The Spring Framework provides a helpful utility
library for sending email that shields the user from
the specifics of the underlying mailing system and
is responsible for low level resource handling on
behalf of the client.
The org.springframework.mail package is
Library dependencies
The following additional jars to
be on the classpath of your
application in order to be able to
use the Spring Framework's
email library.
library
The JAF
activation.jar
library
All of these libraries are freely
available on the web.
exceptions with the root exception being MailException. Please refer to the JavaDocs
for more information on the rich mail exception hierarchy.
The org.springframework.mail.javamail.JavaMailSender interface adds
specialized JavaMail features such as MIME message support to the MailSender
interface (from which it inherits). JavaMailSender also provides a callback interface for
preparation of JavaMail MIME messages, called
org.springframework.mail.javamail.MimeMessagePreparator
26.2 Usage
Let's assume there is a business interface called OrderManager:
public interface OrderManager {
void placeOrder(Order order);
}
Let us also assume that there is a requirement stating that an email message with an order
number needs to be generated and sent to a customer placing the relevant order.
javax.mail.Message;
javax.mail.MessagingException;
javax.mail.internet.InternetAddress;
javax.mail.internet.MimeMessage;
import
import
import
import
javax.mail.internet.MimeMessage;
org.springframework.mail.MailException;
org.springframework.mail.javamail.JavaMailSender;
org.springframework.mail.javamail.MimeMessagePreparator;
Note
The mail code is a crosscutting concern and could well be a candidate
for refactoring into a custom Spring AOP aspect, which then could be
executed at appropriate joinpoints on the OrderManager target.
The Spring Framework's mail support ships with the standard JavaMail implementation.
Please refer to the relevant JavaDocs for more information.
Attachments
The following example shows you how to use the MimeMessageHelper to send an
email along with a single JPEG image attachment.
JavaMailSenderImpl sender = new JavaMailSenderImpl();
sender.setHost("mail.host.com");
MimeMessage message = sender.createMimeMessage();
// use the true flag to indicate you need a multipart message
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setTo("test@host.com");
helper.setText("Check out this image!");
// let's attach the infamous windows Sample file (this time copied to c:/)
FileSystemResource file = new FileSystemResource(new File("c:/Sample.jpg"));
helper.addAttachment("CoolImage.jpg", file);
sender.send(message);
Inline resources
The following example shows you how to use the MimeMessageHelper to send an
email along with an inline image.
JavaMailSenderImpl sender = new JavaMailSenderImpl();
sender.setHost("mail.host.com");
MimeMessage message = sender.createMimeMessage();
// use the true flag to indicate you need a multipart message
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setTo("test@host.com");
// use the true flag to indicate the text included is HTML
helper.setText("<html><body><img src='cid:identifier1234'></body></html>", true);
// 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);
Warning
Inline resources are added to the mime message using the specified
Content-ID (identifier1234 in the above example). The order
in which you are adding the text and the resource are very important.
Be sure to first add the text and after that the resources. If you are doing
it the other way around, it won't work!
Creating HTML-based email content in Java code is tedious and error prone
There is no clear separation between display logic and business logic
Changing the display structure of the email content requires writing Java code,
recompiling, redeploying...
Typically the approach taken to address these issues is to use a template library such as
FreeMarker or Velocity to define the display structure of email content. This leaves your
code tasked only with creating the data that is to be rendered in the email template and
sending the email. It is definitely a best practice for when the content of your emails
becomes even moderately complex, and with the Spring Framework's support classes for
FreeMarker and Velocity becomes quite easy to do. Find below an example of using the
Velocity template library to create email content.
A Velocity-based example
To use Velocity to create your email template(s), you will need to have the Velocity
libraries available on your classpath. You will also need to create one or more Velocity
templates for the email content that your application needs. Find below the Velocity
template that this example will be using. As you can see it is HTML-based, and since it is
plain text it can be created using your favorite HTML or text editor.
# in the com/foo/package
<html>
<body>
<h3>Hi ${user.userName}, welcome to the Chipping Sodbury On-the-Hill message boards!</h3>
<div>
Your email address is <a href="mailto:${user.emailAddress}">${user.emailAddress}</a>.
</div>
</body>
</html>
Find below some simple code and Spring XML configuration that makes use of the above
Velocity template to create email content and send email(s).
package com.foo;
import
import
import
import
import
org.apache.velocity.app.VelocityEngine;
org.springframework.mail.javamail.JavaMailSender;
org.springframework.mail.javamail.MimeMessageHelper;
org.springframework.mail.javamail.MimeMessagePreparator;
org.springframework.ui.velocity.VelocityEngineUtils;
import javax.mail.internet.MimeMessage;
import java.util.HashMap;
import java.util.Map;
public class SimpleRegistrationService implements RegistrationService {
private JavaMailSender mailSender;
private VelocityEngine velocityEngine;
public void setMailSender(JavaMailSender mailSender) {
this.mailSender = mailSender;
}
public void setVelocityEngine(VelocityEngine velocityEngine) {
this.velocityEngine = velocityEngine;
}
public void register(User user) {
// Do the registration logic...
sendConfirmationEmail(user);
}
private void sendConfirmationEmail(final User user) {
MimeMessagePreparator preparator = new MimeMessagePreparator() {
public void prepare(MimeMessage mimeMessage) throws Exception {
MimeMessageHelper message = new MimeMessageHelper(mimeMessage);
message.setTo(user.getEmailAddress());
message.setFrom("webmaster@csonth.gov.uk"); // could be parameterized...
Map model = new HashMap();
model.put("user", user);
String text = VelocityEngineUtils.mergeTemplateIntoString(
velocityEngine, "com/dns/registration-confirmation.vm", model);
message.setText(text, true);
}
};
this.mailSender.send(preparator);
}
}
TaskExecutor abstraction to pool threads. However, if your beans need thread pooling
behavior, it is possible to use this abstraction for your own needs.
java.util.concurrent
CommonJ is a set of
specifications jointly developed
between BEA and IBM. These
specifications are not Java EE
standards, but are standard
across BEA's and IBM's
Application Server
implementations.
As you can see, rather than retrieving a thread from the pool and executing yourself, you
add your Runnable to the queue and the TaskExecutor uses its internal rules to
decide when the task gets executed.
To configure the rules that the TaskExecutor will use, simple bean properties have
been exposed.
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="5" />
<property name="maxPoolSize" value="10" />
<property name="queueCapacity" value="25" />
</bean>
<bean id="taskExecutorExample" class="TaskExecutorExample">
<constructor-arg ref="taskExecutor" />
</bean>
The simplest method is the one named 'schedule' that takes a Runnable and Date only.
That will cause the task to run once after the specified time. All of the other methods are
capable of scheduling tasks to run repeatedly. The fixed-rate and fixed-delay methods are
for simple, periodic execution, but the method that accepts a Trigger is much more flexible.
As you can see, the TriggerContext is the most important part. It encapsulates all of
the relevant data, and is open for extension in the future if necessary. The
TriggerContext is an interface (a SimpleTriggerContext implementation is used
by default). Here you can see what methods are available for Trigger implementations.
public interface TriggerContext {
Date lastScheduledExecutionTime();
Date lastActualExecutionTime();
Date lastCompletionTime();
}
You are free to pick and choose the relevant annotations for your application. For example,
if you only need support for @Scheduled, simply omit @EnableAsync. For more finegrained control you can additionally implement the SchedulingConfigurer and/or
AsyncConfigurer interfaces. See the Javadoc for full details.
If you prefer XML configuration use the <task:annotation-driven> element.
<task:annotation-driven executor="myExecutor" scheduler="myScheduler"/>
<task:executor id="myExecutor" pool-size="5"/>
<task:scheduler id="myScheduler" pool-size="10"/>}
Notice with the above XML that an executor reference is provided for handling those tasks
that correspond to methods with the @Async annotation, and the scheduler reference is
provided for managing those methods annotated with @Scheduled.
If a fixed rate execution is desired, simply change the property name specified within the
annotation. The following would be executed every 5 seconds measured between the
successive start times of each invocation.
@Scheduled(fixedRate=5000)
public void doSomething() {
// something that should execute periodically
}
For fixed-delay and fixed-rate tasks, an initial delay may be specified indicating the number
of milliseconds to wait before the first execution of the method.
@Scheduled(initialDelay=1000, fixedRate=5000)
public void doSomething() {
// something that should execute periodically
}
If simple periodic scheduling is not expressive enough, then a cron expression may be
Notice that the methods to be scheduled must have void returns and must not expect any
arguments. If the method needs to interact with other objects from the Application Context,
then those would typically have been provided through dependency injection.
Note
Make sure that you are not initializing multiple instances of the same
@Scheduled annotation class at runtime, unless you do want to
schedule callbacks to each such instance. Related to this, make sure
that you do not use @Configurable on bean classes which are
annotated with @Scheduled and registered as regular Spring beans
with the container: You would get double initialization otherwise, once
through the container and once through the @Configurable aspect,
with the consequence of each @Scheduled method being invoked
twice.
Unlike the methods annotated with the @Scheduled annotation, these methods can
expect arguments, because they will be invoked in the "normal" way by callers at runtime
rather than from a scheduled task being managed by the container. For example, the
following is a legitimate application of the @Async annotation.
@Async
void doSomething(String s) {
// this will be executed asynchronously
}
Even methods that return a value can be invoked asynchronously. However, such methods
are required to have a Future typed return value. This still provides the benefit of
asynchronous execution so that the caller can perform other tasks prior to calling get()
on that Future.
@Async
Future<String> returnSomething(int i) {
// this will be executed asynchronously
}
In this case, "otherExecutor" may be the name of any Executor bean in the Spring
container, or may be the name of a qualifier associated with any Executor, e.g. as
specified with the <qualifier> element or Spring's @Qualifier annotation.
The value provided for the 'id' attribute will be used as the prefix for thread names within
the pool. The 'scheduler' element is relatively straightforward. If you do not provide a 'poolsize' attribute, the default thread pool will only have a single thread. There are no other
configuration options for the scheduler.
As with the scheduler above, the value provided for the 'id' attribute will be used as the
prefix for thread names within the pool. As far as the pool size is concerned, the 'executor'
element supports more configuration options than the 'scheduler' element. For one thing,
the thread pool for a ThreadPoolTaskExecutor is itself more configurable. Rather
than just a single size, an executor's thread pool may have different values for the core and
the max size. If a single value is provided then the executor will have a fixed-size thread
pool (the core and max sizes are the same). However, the 'executor' element's 'pool-size'
attribute also accepts a range in the form of "min-max".
<task:executor id="executorWithPoolSizeRange"
pool-size="5-25"
queue-capacity="100"/>
As you can see from that configuration, a 'queue-capacity' value has also been provided.
The configuration of the thread pool should also be considered in light of the executor's
queue capacity. For the full description of the relationship between pool size and queue
capacity, consult the documentation for ThreadPoolExecutor. The main idea is that when a
task is submitted, the executor will first try to use a free thread if the number of active
threads is currently less than the core size. If the core size has been reached, then the task
will be added to the queue as long as its capacity has not yet been reached. Only then, if
the queue's capacity has been reached, will the executor create a new thread beyond the
core size. If the max size has also been reached, then the executor will reject the task.
By default, the queue is unbounded, but this is rarely the desired configuration, because it
can lead to OutOfMemoryErrors if enough tasks are added to that queue while all pool
threads are busy. Furthermore, if the queue is unbounded, then the max size has no effect
at all. Since the executor will always try the queue before creating a new thread beyond
the core size, a queue must have a finite capacity for the thread pool to grow beyond the
core size (this is why a fixed size pool is the only sensible case when using an unbounded
queue).
In a moment, we will review the effects of the keep-alive setting which adds yet another
factor to consider when providing a pool size configuration. First, let's consider the case, as
mentioned above, when a task is rejected. By default, when a task is rejected, a thread
pool executor will throw a TaskRejectedException. However, the rejection policy is
actually configurable. The exception is thrown when using the default rejection policy
which is the AbortPolicy implementation. For applications where some tasks can be
skipped under heavy load, either the DiscardPolicy or DiscardOldestPolicy may
be configured instead. Another option that works well for applications that need to throttle
the submitted tasks under heavy load is the CallerRunsPolicy. Instead of throwing an
exception or discarding tasks, that policy will simply force the thread that is calling the
submit method to run the task itself. The idea is that such a caller will be busy while
running that task and not able to submit other tasks immediately. Therefore it provides a
simple way to throttle the incoming load while maintaining the limits of the thread pool and
queue. Typically this allows the executor to "catch up" on the tasks it is handling and
thereby frees up some capacity on the queue, in the pool, or both. Any of these options can
be chosen from an enumeration of values available for the 'rejection-policy' attribute on the
'executor' element.
<task:executor id="executorWithCallerRunsPolicy"
pool-size="5-25"
queue-capacity="100"
rejection-policy="CALLER_RUNS"/>
As you can see, the scheduler is referenced by the outer element, and each individual task
includes the configuration of its trigger metadata. In the preceding example, that metadata
defines a periodic trigger with a fixed delay indicating the number of milliseconds to wait
after each task execution has completed. Another option is 'fixed-rate', indicating how often
the method should be executed regardless of how long any previous execution takes.
Additionally, for both fixed-delay and fixed-rate tasks an 'initial-delay' parameter may be
specified indicating the number of milliseconds to wait before the first execution of the
method. For more control, a "cron" attribute may be provided instead. Here is an example
The job detail bean has all information it needs to run the job (ExampleJob). The timeout
is specified in 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;
public class ExampleJob extends QuartzJobBean {
private int timeout;
/**
* Setter called after the ExampleJob is instantiated
* with the value from the JobDetailBean (5)
*/
public void setTimeout(int timeout) {
this.timeout = timeout;
}
protected void executeInternal(JobExecutionContext ctx) throws JobExecutionException {
// do the actual work
}
}
All additional settings from the job detail bean are of course available to you as well.
Note: Using the name and group properties, you can modify the name and the group of
the job, respectively. By default, the name of the job matches the bean name of the job
detail bean (in the example above, this is exampleJob).
The above example will result in the doIt method being called on the
exampleBusinessObject method (see below):
public class ExampleBusinessObject {
// properties and collaborators
public void doIt() {
// do the actual work
}
}
<bean id="exampleBusinessObject" class="examples.ExampleBusinessObject"/>
Using the MethodInvokingJobDetailFactoryBean, you don't need to create oneline 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
each other. 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 classes
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="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="exampleBusinessObject" />
<property name="targetMethod" value="doIt" />
<property name="concurrent" value="false" />
</bean>
Note
By default, jobs will run in a concurrent fashion.
Now we've set up two triggers, one running every 50 seconds with a starting delay of 10
seconds and one every morning at 6 AM. To finalize everything, we need to set up the
SchedulerFactoryBean:
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="cronTrigger" />
<ref bean="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, etc. Have a look
at the SchedulerFactoryBean Javadoc for more information.
String getMessage();
}
Here is the definition of a class that has a dependency on the Messenger interface.
package org.springframework.scripting;
public class DefaultBookingService implements BookingService {
private Messenger messenger;
public void setMessenger(Messenger messenger) {
this.messenger = messenger;
}
public void processBooking() {
// use the injected Messenger object...
}
}
Finally, here are the bean definitions that will effect the injection of the Groovy-defined
Messenger implementation into an instance of the DefaultBookingService class.
Note
To use the custom dynamic language tags to define dynamiclanguage-backed beans, you need to have the XML Schema preamble
at the top of your Spring XML configuration file. You also need to be
using a Spring ApplicationContext implementation as your IoC
container. Using the dynamic-language-backed beans with a plain
BeanFactory implementation is supported, but you have to manage
the plumbing of the Spring internals to do so.
For more information on schema-based configuration, see Appendix E,
XML Schema-based configuration.
XML Schema
All of the configuration examples
in this chapter make use of the
new XML Schema support that
was added in Spring 2.0.
<lang:language/>
<lang:jruby/> (JRuby)
<lang:groovy/> (Groovy)
<lang:bsh/> (BeanShell)
The exact attributes and child elements that are
available for configuration depends on exactly
which language the bean has been defined in (the
language-specific sections below provide the full
lowdown on this).
Refreshable beans
One of the (if not the) most compelling value adds of the dynamic language support in
Spring is the 'refreshable bean' feature.
A refreshable bean is a dynamic-language-backed bean that with a small amount of
configuration, a dynamic-language-backed bean can monitor changes in its underlying
source file resource, and then reload itself when the dynamic language source file is
changed (for example when a developer edits and saves changes to the file on the
filesystem).
This allows a developer to deploy any number of dynamic language source files as part of
an application, configure the Spring container to create beans backed by dynamic
language source files (using the mechanisms described in this chapter), and then later, as
requirements change or some other external factor comes into play, simply edit a dynamic
language source file and have any change they make reflected in the bean that is backed
by the changed dynamic language source file. There is no need to shut down a running
application (or redeploy in the case of a web application). The dynamic-language-backed
bean so amended will pick up the new state and logic from the changed dynamic language
source file.
Note
Please note that this feature is off by default.
Let's take a look at an example to see just how easy it is to start using refreshable beans.
To turn on the refreshable beans feature, you simply have to specify exactly one additional
attribute on the <lang:language/> element of your bean definition. So if we stick with
the example from earlier in this chapter, here's what we would change in the Spring XML
configuration to effect refreshable beans:
<beans>
<!-- this bean is now 'refreshable' due to the presence of the 'refresh-check-delay' attribute -->
<lang:groovy id="messenger"
refresh-check-delay="5000" <!-- switches refreshing on with 5 seconds between checks -->
script-source="classpath:Messenger.groovy">
<lang:property name="message" value="I Can Do The Frug" />
</lang:groovy>
<bean id="bookingService" class="x.y.DefaultBookingService">
<property name="messenger" ref="messenger" />
</bean>
</beans>
That really is all you have to do. The 'refresh-check-delay' attribute defined on the
'messenger' bean definition is the number of milliseconds after which the bean will be
refreshed with any changes made to the underlying dynamic language source file. You can
turn off the refresh behavior by assigning a negative value to the 'refresh-checkdelay' attribute. Remember that, by default, the refresh behavior is disabled. If you don't
want the refresh behavior, then simply don't define the attribute.
If we then run the following application we can exercise the refreshable feature; please do
excuse the 'jumping-through-hoops-to-pause-the-execution' shenanigans in this next slice
of code. The System.in.read() call is only there so that the execution of the program
pauses while I (the author) go off and edit the underlying dynamic language source file so
that the refresh will trigger on the dynamic-language-backed bean when the program
resumes execution.
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.scripting.Messenger;
public final class Boot {
public static void main(final String[] args) throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
Messenger messenger = (Messenger) ctx.getBean("messenger");
System.out.println(messenger.getMessage());
// pause execution while I go off and make changes to the source file...
System.in.read();
System.out.println(messenger.getMessage());
}
}
Let's assume then, for the purposes of this example, that all calls to the getMessage()
method of Messenger implementations have to be changed such that the message is
surrounded by quotes. Below are the changes that I (the author) make to the
Messenger.groovy source file when the execution of the program is paused.
package org.springframework.scripting
class GroovyMessenger implements Messenger {
private String message = "Bingo"
public String getMessage() {
// change the implementation to surround the message in quotes
return "'" + this.message + "'"
}
public void setMessage(String message) {
this.message = message
}
}
When the program executes, the output before the input pause will be I Can Do The
Frug. After the change to the source file is made and saved, and the program resumes
execution, the result of calling the getMessage() method on the dynamic-languagebacked Messenger implementation will be 'I Can Do The Frug' (notice the
inclusion of the additional quotes).
It is important to understand that changes to a script will not trigger a refresh if the changes
occur within the window of the 'refresh-check-delay' value. It is equally important
to understand that changes to the script are not actually 'picked up' until a method is called
on the dynamic-language-backed bean. It is only when a method is called on a dynamiclanguage-backed bean that it checks to see if its underlying script source has changed.
Any exceptions relating to refreshing the script (such as encountering a compilation error,
or finding that the script file has been deleted) will result in a fatal exception being
propagated to the calling code.
The refreshable bean behavior described above does not apply to dynamic language
source files defined using the <lang:inline-script/> element notation (see the
section called Inline dynamic language source files). Additionally, it only applies to beans
where changes to the underlying source file can actually be detected; for example, by code
that checks the last modified date of a dynamic language source file that exists on the
filesystem.
If we put to one side the issues surrounding whether it is good practice to define dynamic
language source inside a Spring configuration file, the <lang:inline-script/>
element can be useful in some scenarios. For instance, we might want to quickly add a
Spring Validator implementation to a Spring MVC Controller. This is but a
moment's work using inline source. (See Section 28.4.2, Scripted Validators for such an
example.)
Find below an example of defining the source for a JRuby-based bean directly in a Spring
XML configuration file using the inline: notation. (Notice the use of the < characters to
denote a '<' character. In such a case surrounding the inline source in a <![CDATA[]]>
region might be better.)
<lang:jruby id="messenger" script-interfaces="org.springframework.scripting.Messenger">
<lang:inline-script>
require 'java'
include_class 'org.springframework.scripting.Messenger'
class RubyMessenger < Messenger
def setMessage(message)
@@message = message
end
def getMessage
@@message
end
end
</lang:inline-script>
<lang:property name="message" value="Hello World!" />
</lang:jruby>
In practice this limitation is not as significant as it first appears since setter injection is the
injection style favored by the overwhelming majority of developers anyway (let's leave the
discussion as to whether that is a good thing to another day).
jruby.jar
And here is the Spring XML that defines an instance of the RubyMessenger JRuby bean.
<lang:jruby id="messageService"
script-interfaces="org.springframework.scripting.Messenger"
script-source="classpath:RubyMessenger.rb">
<lang:property name="message" value="Hello World!" />
</lang:jruby>
Take note of the last line of that JRuby source ('RubyMessenger.new'). When using
JRuby in the context of Spring's dynamic language support, you are encouraged to
instantiate and return a new instance of the JRuby class that you want to use as a
dynamic-language-backed bean as the result of the execution of your JRuby source. You
can achieve this by simply instantiating a new instance of your JRuby class on the last line
of the source file like so:
require 'java'
include_class 'org.springframework.scripting.Messenger'
# class definition same as above...
If you forget to do this, it is not the end of the world; this will however result in Spring having
to trawl (reflectively) through the type representation of your JRuby class looking for a class
to instantiate. In the grand scheme of things this will be so fast that you'll never notice it, but
it is something that can be avoided by simply having a line such as the one above as the
last line of your JRuby script. If you don't supply such a line, or if Spring cannot find a
JRuby class in your script to instantiate then an opaque
ScriptCompilationException will be thrown immediately after the source is
executed by the JRuby interpreter. The key text that identifies this as the root cause of an
exception can be found immediately below (so if your Spring container throws the
following exception when creating your dynamic-language-backed bean and the following
text is there in the corresponding stacktrace, this will hopefully allow you to identify and
then easily rectify the issue):
org.springframework.scripting.ScriptCompilationException:
Compilation of JRuby script returned ''
To rectify this, simply instantiate a new instance of whichever class you want to expose as
a JRuby-dynamic-language-backed bean (as shown above). Please also note that you can
actually define as many classes and objects as you want in your JRuby script; what is
important is that the source file as a whole must return an object (for Spring to configure).
See Section 28.4, Scenarios for some scenarios where you might want to use JRubybased beans.
groovy-1.5.5.jar
asm-2.2.2.jar
antlr-2.7.6.jar
The resulting output from running the above program will be (unsurprisingly) 10. (Exciting
example, huh? Remember that the intent is to illustrate the concept. Please consult the
dynamic language showcase project for a more complex example, or indeed Section 28.4,
Scenarios later in this chapter).
It is important that you do not define more than one class per Groovy source file. While this
is perfectly legal in Groovy, it is (arguably) a bad practice: in the interests of a consistent
approach, you should (in the opinion of this author) respect the standard Java conventions
of one (public) class per source file.
The Spring Framework will instantiate an instance of your Groovy-backed bean, and will
then pass the created GroovyObject to the specified GroovyObjectCustomizer if
one has been defined. You can do whatever you like with the supplied GroovyObject
reference: it is expected that the setting of a custom MetaClass is what most folks will
want to do with this callback, and you can see an example of doing that below.
public final class SimpleMethodTracingCustomizer implements GroovyObjectCustomizer {
public void customize(GroovyObject goo) {
DelegatingMetaClass metaClass = new DelegatingMetaClass(goo.getMetaClass()) {
public Object invokeMethod(Object object, String methodName, Object[] arguments) {
System.out.println("Invoking '" + methodName + "'.");
return super.invokeMethod(object, methodName, arguments);
}
};
metaClass.initialize();
goo.setMetaClass(metaClass);
}
}
If you are not using the Spring 2.0 namespace support, you can still use the
GroovyObjectCustomizer functionality.
<bean id="calculator" class="org.springframework.scripting.groovy.GroovyScriptFactory">
<constructor-arg value="classpath:org/springframework/scripting/groovy/Calculator.groovy"/>
<!-- define the GroovyObjectCustomizer (as an inner bean) -->
<constructor-arg>
<bean id="tracingCustomizer" class="example.SimpleMethodTracingCustomizer" />
</constructor-arg>
</bean>
<bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor"/>
bsh-2.0b4.jar
and JavaScript.
In contrast to Groovy, BeanShell-backed bean
definitions require some (small) additional configuration. The implementation of the
BeanShell dynamic language support in Spring is interesting in that what happens is this:
Spring creates a JDK dynamic proxy implementing all of the interfaces that are specified in
the 'script-interfaces' attribute value of the <lang:bsh> element (this is why
you must supply at least one interface in the value of the attribute, and (accordingly)
program to interfaces when using BeanShell-backed beans). This means that every
method call on a BeanShell-backed object is going through the JDK dynamic proxy
invocation mechanism.
Let's look at a fully working example of using a BeanShell-based bean that implements the
Messenger interface that was defined earlier in this chapter (repeated below for your
convenience).
package org.springframework.scripting;
public interface Messenger {
String getMessage();
}
Here is the BeanShell 'implementation' (the term is used loosely here) of the Messenger
interface.
String message;
String getMessage() {
return message;
}
void setMessage(String aMessage) {
message = aMessage;
}
And here is the Spring XML that defines an 'instance' of the above 'class' (again, the term
is used very loosely here).
<lang:bsh id="messageService" script-source="classpath:BshMessenger.bsh"
script-interfaces="org.springframework.scripting.Messenger">
<lang:property name="message" value="Hello World!" />
</lang:bsh>
See Section 28.4, Scenarios for some scenarios where you might want to use BeanShellbased beans.
28.4 Scenarios
The possible scenarios where defining Spring managed beans in a scripting language
would be beneficial are, of course, many and varied. This section describes two possible
use cases for the dynamic language support in Spring.
org.springframework.showcase.fortune.service.FortuneService
org.springframework.showcase.fortune.domain.Fortune
org.springframework.web.servlet.ModelAndView
org.springframework.web.servlet.mvc.Controller
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
class FortuneController implements Controller {
@Property FortuneService fortuneService
ModelAndView handleRequest(
HttpServletRequest request, HttpServletResponse httpServletResponse) {
return new ModelAndView("tell", "fortune", this.fortuneService.tellFortune())
}
}
<lang:groovy id="fortune"
refresh-check-delay="3000"
script-source="/WEB-INF/groovy/FortuneController.groovy">
<lang:property name="fortuneService" ref="fortuneService"/>
</lang:groovy>
express complex validation logic using a loosely typed dynamic language (that may also
have support for inline regular expressions) as opposed to regular Java.
Again, developing validators as dynamic-language-backed beans allows you to change
validation logic by simply editing and saving a simple text file; any such changes will
(depending on the configuration) automatically be reflected in the execution of a running
application and would not require the restart of an application.
Note
Please note that in order to effect the automatic 'pickup' of any changes
to dynamic-language-backed beans, you will have had to enable the
'refreshable beans' feature. See the section called Refreshable beans
for a full and detailed treatment of this feature.
Find below an example of a Spring
org.springframework.validation.Validator implemented using the Groovy
dynamic language. (See Section 7.2, Validation using Spring's Validator interface for
a discussion of the Validator interface.)
import org.springframework.validation.Validator
import org.springframework.validation.Errors
import org.springframework.beans.TestBean
class TestBeanValidator implements Validator {
boolean supports(Class clazz) {
return TestBean.class.isAssignableFrom(clazz)
}
void validate(Object bean, Errors errors) {
if(bean.name?.trim()?.size() > 0) {
return
}
errors.reject("whitespace", "Cannot be composed wholly of whitespace.")
}
}
28.5.2 Scoping
In case it is not immediately obvious, scripted beans can of course be scoped just like any
other bean. The scope attribute on the various <lang:language/> elements allows
you to control the scope of the underlying scripted bean, just as it does with a regular bean.
(The default scope is singleton, just as it is with 'regular' beans.)
Find below an example of using the scope attribute to define a Groovy bean scoped as a
prototype.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:lang="http://www.springframework.org/schema/lang"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd">
<lang:groovy id="messenger" script-source="classpath:Messenger.groovy" scope="prototype">
<lang:property name="message" value="I Can Do The RoboCop" />
</lang:groovy>
<bean id="bookingService" class="x.y.DefaultBookingService">
<property name="messenger" ref="messenger" />
</bean>
</beans>
See Section 5.5, Bean scopes in Chapter 5, The IoC container for a fuller discussion of
the scoping support in the Spring Framework.
Cache vs Buffer
The terms "buffer" and "cache"
tend to be used interchangeably;
note however they represent
different things. A buffer is used
traditionally as an intermediate
temporary store for data
between a fast and a slow entity.
As one party would have to wait
for the other affecting
performance, the buffer
alleviates this by allowing entire
blocks of data to move at once
rather then in small chunks. The
data is written and read only
once from the buffer.
Furthermore, the buffers are
visible to at least one party which
is aware of it.
A cache on the other hand by
definition is hidden and neither
party is aware that caching
occurs.It as well improves
performance but does that by
In the snippet above, the method findBook is associated with the cache named books.
Each time the method is called, the cache is checked to see whether the invocation has
been already executed and does not have to be repeated. While in most cases, only one
cache is declared, the annotation allows multiple names to be specified so that more then
one cache are being used. In this case, each of the caches will be checked before
executing the method - if at least one cache is hit, then the associated value will be
returned:
Note
All the other caches that do not contain the method will be updated as
well even though the cached method was not actually executed.
If more the one param is given, return a key computed from the hashes of all
parameters.
This approach works well for objects with natural keys as long as the hashCode()
reflects that. If that is not the case then for distributed or persistent environments, the
strategy needs to be changed as the objects hashCode is not preserved. In fact, depending
on the JVM implementation or running conditions, the same hashCode can be reused for
different objects, in the same VM instance.
To provide a different default key generator, one needs to implement the
org.springframework.cache.KeyGenerator interface. Once configured, the
generator will be used for each declaration that does not specify its own key generation
strategy (see below).
At first glance, while the two boolean arguments influence the way the book is found,
they are no use for the cache. Further more what if only one of the two is important while
the other is not?
For such cases, the @Cacheable annotation allows the user to specify how the key is
generated through its key attribute. The developer can use SpEL to pick the arguments of
interest (or their nested properties), perform operations or even invoke arbitrary methods
without having to write any code or implement any interface. This is the recommended
approach over the default generator since methods tend to be quite different in signatures
as the code base grows; while the default strategy might work for some methods, it rarely
does for all methods.
Below are some examples of various SpEL declarations - if you are not familiar with it, do
yourself a favour and read Chapter 8, Spring Expression Language (SpEL):
@Cacheable(value="books", key="#isbn"
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
@Cacheable(value="books", key="#isbn.rawNumber")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
@Cacheable(value="books", key="T(someType).hash(#isbn)")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
The snippets above, show how easy it is to select a certain argument, one of its properties
or even an arbitrary (static) method.
Conditional caching
Sometimes, a method might not be suitable for caching all the time (for example, it might
depend on the given arguments). The cache annotations support such functionality
through the conditional parameter which takes a SpEL expression that is evaluated to
either true or false. If true, the method is cached - if not, it behaves as if the method is
not cached, that is executed every since time no matter what values are in the cache or
what arguments are used. A quick example - the following method will be cached, only if
the argument name has a length shorter then 32:
@Cacheable(value="book", condition="#name.length < 32")
public Book findBook(String name)
In addition the conditional parameter, the unless parameter can be used to veto the
adding of a value to the cache. Unlike conditional, unless SpEL expressions are
evalulated after the method has been called. Expanding on the previous example perhaps we only want to cache paperback books:
@Cacheable(value="book", condition="#name.length < 32", unless="#result.hardback")
public Book findBook(String name)
Location
Description
Example
#root.methodName
method
root object
#root.method.name
target
root object
#root.target
targetClass
root object
#root.targetClass
args
root object
#root.args[0]
caches
root object
Collection of caches
against which the current
method is executed
#root.caches[0].name
evaluation
context
argument
name
result
evaluation
context
iban
or
a0
or p<#arg> notation
as an alias).
#result
generally discouraged because they have different behaviors. While the latter causes the
method execution to be skipped by using the cache, the former forces the execution in
order to execute a cache update. This leads to unexpected behavior and with the
exception of specific corner-cases (such as annotations having conditions that exclude
them from each other), such declarations should be avoided.
This option comes in handy when an entire cache region needs to be cleared out - rather
then evicting each entry (which would take a long time since it is inefficient), all the entires
are removed in one operation as shown above. Note that the framework will ignore any key
specified in this scenario as it does not apply (the entire cache is evicted not just one
entry).
One can also indicate whether the eviction should occur after (the default) or before the
method executes through the beforeInvocation attribute. The former provides the
same semantics as the rest of the annotations - once the method completes successfully,
an action (in this case eviction) on the cache is executed. If the method does not execute
(as it might be cached) or an exception is thrown, the eviction does not occur. The latter
(beforeInvocation=true) causes the eviction to occur always, before the method is
invoked - this is useful in cases where the eviction does not need to be tied to the method
outcome.
It is important to note that void methods can be used with @CacheEvict - as the methods
act as triggers, the return values are ignored (as they don't interact with the cache) - this is
not the case with @Cacheable which adds/update data into the cache and thus requires a
result.
cachemanager
mode
Annotation Attribute
Default
N/A (See
CachingConfigurer cacheManager
Javadoc)
mode
proxy
Description
Name of cache
manager to use.
Only required if
the name of the
cache manager
is not
cacheManager,
as in the
example above.
The default mode
"proxy"
processes
annotated beans
to be proxied
using Spring's
AOP framework
(following proxy
semantics, as
discussed above,
applying to
method calls
coming in
through the proxy
only). The
alternative mode
"aspectj" instead
weaves the
affected classes
with Spring's
AspectJ caching
aspect, modifying
the target class
byte code to
apply to any kind
of method call.
AspectJ weaving
requires springaspects.jar in the
classpath as well
as load-time
weaving (or
compile-time
weaving)
enabled. (See
the section called
Spring
configuration for
details on how to
set up load-time
weaving.)
proxytargetclass
order
Applies to proxy
mode only.
Controls what
type of caching
proxies are
created for
classes
annotated with
the
@Cacheable or
@CacheEvict
annotations. If
the proxytarget-class
attribute is set to
true, then
class-based
proxies are
created. If
proxytarget-class
is false or if the
attribute is
omitted, then
standard JDK
interface-based
proxies are
created. (See
Section 9.6,
Proxying
mechanisms for
a detailed
examination of
the different
proxy types.)
proxyTargetClass
false
order
Note
<cache:annotation-driven/> only looks for
@Cacheable/@CacheEvict on beans in the same application
context it is defined in. This means that, if you put
<cache:annotation-driven/> in a
WebApplicationContext for a DispatcherServlet, it only
checks for @Cacheable/@CacheEvict beans in your controllers,
and not your services. See Section 17.2, The DispatcherServlet
for more information.
Tip
Spring recommends that you only
annotate concrete classes (and
methods of concrete classes) with
the @Cache* annotation, as
opposed to annotating interfaces.
You certainly can place the
@Cache* annotation on an
interface (or an interface method),
but this works only as you would
expect it to if you are using
interface-based proxies. The fact
that Java annotations are not
inherited from interfaces means
that if you are using class-based
proxies (proxy-targetclass="true") or the weavingbased aspect
(mode="aspectj"), then the
caching settings are not
recognized by the proxying and
weaving infrastructure, and the
object will not be wrapped in a
caching proxy, which would be
decidedly bad.
@Cacheable/@CachePut/@CacheEvict
When using proxies, you should
apply the @Cache* annotations
only to methods with public
visibility. If you do annotate
protected, private or packagevisible methods with these
annotations, no error is raised,
but the annotated method does
not exhibit the configured
caching settings. Consider the
use of AspectJ (see below) if you
need to annotate non-public
methods as it changes the
bytecode itself.
Note
In proxy mode (which is the default), only external method calls coming
in through the proxy are intercepted. This means that self-invocation, in
effect, a method within the target object calling another method of the
target object, will not lead to an actual caching at runtime even if the
invoked method is marked with @Cacheable - considering using the
aspectj mode in this case.
Above, we have defined our own SlowService annotation which itself is annotated with
@Cacheable - now we can replace the following code:
@Cacheable(value="books", key="#isbn")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
with:
@SlowService
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
Even though @SlowService is not a Spring annotation, the container automatically picks
up its declaration at runtime and understands its meaning. Note that as mentioned above,
the annotation-driven behavior needs to be enabled.
In the configuration above, the bookService is made cacheable. The caching semantics
to apply are encapsulated in the cache:advice definition which instructs method
findBooks to be used for putting data into the cache while method loadBooks for
evicting data. Both definitions are working against the books cache.
The aop:config definition applies the cache advice to the appropriate points in the
program by using the AspectJ pointcut expression (more information is available in
Chapter 9, Aspect Oriented Programming with Spring). In the example above, all methods
from the BookService are considered and the cache advice applied to them.
The declarative XML caching supports all of the annotation-based model so moving
between the two should be fairly easy - further more both can be used inside the same
application. The XML based approach does not touch the target code however it is
inherently more verbose; when dealing with classes with overloaded methods that are
targeted for caching, identifying the proper methods does take an extra effort since the
method argument is not a good discriminator - in these cases, the AspectJ pointcut can be
used to cherry pick the target methods and apply the appropriate caching functionality.
However through XML, it is easier to apply a package/group/interface-wide caching (again
due to the AspectJ pointcut) and to create template-like definitions (as we did in the
example above by defining the target cache through the cache:definitions cache
attribute).
The snippet above uses the SimpleCacheManager to create a CacheManager for the
two, nested Concurrent Cache implementations named default and books. Note that
the names are configured directly for each cache.
As the cache is created by the application, it is bound to its lifecycle, making it suitable for
basic use cases, tests or simple applications. The cache scales well and is very fast but it
does not provide any management or persistence capabilities nor eviction contracts.
This setup bootstraps ehcache library inside Spring IoC (through bean ehcache) which is
then wired into the dedicated CacheManager implementation. Note the entire ehcachespecific configuration is read from the resource ehcache.xml.
additionally, through the fallbackToNoOpCache flag, adds a no op cache that for all the
definitions not handled by the configured cache managers. That is, every cache definition
not found in either jdkCache or gemfireCache (configured above) will be handled by
the no op cache, which will not store any information causing the target method to be
executed every time.
A.1.1 Hibernate
For the currently recommended usage patterns for Hibernate see Section 15.3, Hibernate
The HibernateTemplate
The basic programming model for templating looks as follows, for methods that can be part
of any custom data access object or business service. There are no restrictions on the
implementation of the surrounding object at all, it just needs to provide a Hibernate
SessionFactory. It can get the latter from anywhere, but preferably as bean reference
from a Spring IoC container - via a simple setSessionFactory(..) bean property
setter. The following snippets show a DAO definition in a Spring container, referencing the
The HibernateTemplate class provides many methods that mirror the methods
exposed on the Hibernate Session interface, in addition to a number of convenience
methods such as the one shown above. If you need access to the Session to invoke
methods that are not exposed on the HibernateTemplate, you can always drop down
to a callback-based approach like so.
public class ProductDaoImpl implements ProductDao {
private HibernateTemplate hibernateTemplate;
public void setSessionFactory(SessionFactory sessionFactory) {
this.hibernateTemplate = new HibernateTemplate(sessionFactory);
}
public Collection loadProductsByCategory(final String category) throws DataAccessException {
return this.hibernateTemplate.execute(new HibernateCallback() {
public Object doInHibernate(Session session) {
Criteria criteria = session.createCriteria(Product.class);
criteria.add(Expression.eq("category", category));
criteria.setMaxResults(6);
return criteria.list();
}
};
}
}
A callback implementation effectively can be used for any Hibernate data access.
HibernateTemplate will ensure that Session instances are properly opened and
closed, and automatically participate in transactions. The template instances are threadsafe and reusable, they can thus be kept as instance variables of the surrounding class.
For simple single step actions like a single find, load, saveOrUpdate, or delete call,
HibernateTemplate offers alternative convenience methods that can replace such one
line callback implementations. Furthermore, Spring provides a convenient
HibernateDaoSupport base class that provides a setSessionFactory(..)
method for receiving a SessionFactory, and getSessionFactory() and
getHibernateTemplate()for use by subclasses. In combination, this allows for very
simple DAO implementations for typical requirements:
public class ProductDaoImpl extends HibernateDaoSupport implements ProductDao {
public Collection loadProductsByCategory(String category) throws DataAccessException {
return this.getHibernateTemplate().find(
"from test.Product product where product.category=?", category);
}
}
code can also be written in a more traditional fashion, without wrapping the Hibernate
access code in a callback, while still respecting and participating in Spring's generic
DataAccessException hierarchy. The HibernateDaoSupport base class offers
methods to access the current transactional Session and to convert exceptions in such a
scenario; similar methods are also available as static helpers on the
SessionFactoryUtils class. Note that such code will usually pass 'false' as the
value of the getSession(..) methods 'allowCreate' argument, to enforce running
within a transaction (which avoids the need to close the returned Session, as its lifecycle
is managed by the transaction).
public class HibernateProductDao extends HibernateDaoSupport implements ProductDao {
public Collection loadProductsByCategory(String category) throws DataAccessException, MyException {
Session session = getSession(false);
try {
Query query = session.createQuery("from test.Product product where product.category=?");
query.setString(0, category);
List result = query.list();
if (result == null) {
throw new MyException("No search results.");
}
return result;
}
catch (HibernateException ex) {
throw convertHibernateAccessException(ex);
}
}
}
The advantage of such direct Hibernate access code is that it allows any checked
application exception to be thrown within the data access code; contrast this to the
HibernateTemplate class which is restricted to throwing only unchecked exceptions
within the callback. Note that you can often defer the corresponding checks and the
throwing of application exceptions to after the callback, which still allows working with
HibernateTemplate. In general, the HibernateTemplate class' convenience
methods are simpler and more convenient for many scenarios.
A.1.2 JDO
For the currently recommended usage patterns for JDO see Section 15.4, JDO
JdoTemplate and JdoDaoSupport
Each JDO-based DAO will then receive the PersistenceManagerFactory through
dependency injection. Such a DAO could be coded against plain JDO API, working with
the given PersistenceManagerFactory, but will usually rather be used with the
Spring Framework's JdoTemplate:
<beans>
<bean id="myProductDao" class="product.ProductDaoImpl">
<property name="persistenceManagerFactory" ref="myPmf"/>
</bean>
</beans>
public class ProductDaoImpl implements ProductDao {
private JdoTemplate jdoTemplate;
public void setPersistenceManagerFactory(PersistenceManagerFactory pmf) {
this.jdoTemplate = new JdoTemplate(pmf);
}
public Collection loadProductsByCategory(final String category) throws DataAccessException {
return (Collection) this.jdoTemplate.execute(new JdoCallback() {
public Object doInJdo(PersistenceManager pm) throws JDOException {
Query query = pm.newQuery(Product.class, "category = pCategory");
query.declareParameters("String pCategory");
List result = query.execute(category);
// do some further stuff with the result list
return result;
}
});
}
}
A callback implementation can effectively be used for any JDO data access.
JdoTemplate will ensure that PersistenceManagers are properly opened and
closed, and automatically participate in transactions. The template instances are threadsafe and reusable, they can thus be kept as instance variables of the surrounding class.
For simple single-step actions such as a single find, load, makePersistent, or
delete call, JdoTemplate offers alternative convenience methods that can replace
such one line callback implementations. Furthermore, Spring provides a convenient
JdoDaoSupport base class that provides a
setPersistenceManagerFactory(..) method for receiving a
PersistenceManagerFactory, and getPersistenceManagerFactory() and
getJdoTemplate() for use by subclasses. In combination, this allows for very simple
DAO implementations for typical requirements:
public class ProductDaoImpl extends JdoDaoSupport implements ProductDao {
public Collection loadProductsByCategory(String category) throws DataAccessException {
return getJdoTemplate().find(
Product.class, "category = pCategory", "String category", new Object[] {category});
}
}
As alternative to working with Spring's JdoTemplate, you can also code Spring-based
DAOs at the JDO API level, explicitly opening and closing a PersistenceManager. As
elaborated in the corresponding Hibernate section, the main advantage of this approach is
that your data access code is able to throw checked exceptions. JdoDaoSupport offers a
variety of support methods for this scenario, for fetching and releasing a transactional
PersistenceManager as well as for converting exceptions.
A.1.3 JPA
For the currently recommended usage patterns for JPA see Section 15.5, JPA
JpaTemplate and JpaDaoSupport
Each JPA-based DAO will then receive a EntityManagerFactory via dependency
injection. Such a DAO can be coded against plain JPA and work with the given
EntityManagerFactory or through Spring's JpaTemplate:
<beans>
<bean id="myProductDao" class="product.ProductDaoImpl">
<property name="entityManagerFactory" ref="myEmf"/>
</bean>
</beans>
public class JpaProductDao implements ProductDao {
private JpaTemplate jpaTemplate;
public void setEntityManagerFactory(EntityManagerFactory emf) {
this.jpaTemplate = new JpaTemplate(emf);
}
public Collection loadProductsByCategory(final String category) throws DataAccessException {
return (Collection) this.jpaTemplate.execute(new JpaCallback() {
public Object doInJpa(EntityManager em) throws PersistenceException {
Query query = em.createQuery("from Product as p where p.category = :category");
query.setParameter("category", category);
List result = query.getResultList();
// do some further processing with the result list
return result;
}
});
}
}
The JpaCallback implementation allows any type of JPA data access. The
JpaTemplate will ensure that EntityManagers are properly opened and closed and
Besides working with Spring's JpaTemplate, one can also code Spring-based DAOs
against the JPA, doing one's own explicit EntityManager handling. As also elaborated
in the corresponding Hibernate section, the main advantage of this approach is that your
data access code is able to throw checked exceptions. JpaDaoSupport offers a variety
of support methods for this scenario, for retrieving and releasing a transaction
EntityManager, as well as for converting exceptions.
JpaTemplate mainly exists as a sibling of JdoTemplate and HibernateTemplate, offering
the same style for people used to it.
A.3.1 JmsTemplate
Located in the package
org.springframework.jms.core the class
JmsTemplate102 provides all of the features of
the JmsTemplate described the JMS chapter,
but is based on the JMS 1.0.2 API instead of the
JMS 1.1 API. As a consequence, if you are using
JmsTemplate102 you need to set the boolean
property pubSubDomain to configure the
JmsTemplate with knowledge of what JMS
domain is being used. By default the value of this
property is false, indicating that the point-to-point
domain, Queues, will be used.
Domain Unification
There are two major releases of
the JMS specification, 1.0.2 and
1.1.
JMS 1.0.2 defined two types of
messaging domains, point-topoint (Queues) and
publish/subscribe (Topics). The
1.0.2 API reflected these two
messaging domains by providing
a parallel class hierarchy for
each domain. As a result, a client
application became domain
specific in its use of the JMS API.
JMS 1.1 introduced the concept
of domain unification that
minimized both the functional
differences and client API
differences between the two
domains. As an example of a
functional difference that was
removed, if you use a JMS 1.1
classes such as
Note
MessageListenerAdapter102,
The JMS
1.1
specification
was
released in
April 2002
and
incorporated
as part of
J2EE 1.4 in
November
2003. As a
result,
common
J2EE 1.3
application
servers
which are
still in
widespread
use (such
as BEA
WebLogic
8.1 and IBM
WebSphere
5.1) are
based on
JMS 1.0.2.
SimpleMessageListenerContainer102,
and
DefaultMessageListenerContainer102.
These classes provide the same functionality as
the JMS 1.1 based counterparts but rely only on
the JMS 1.0.2 API.
A.3.3 Connections
The ConnectionFactory interface is part of the
JMS specification and serves as the entry point for
working with JMS. Spring provides an
implementation of the ConnectionFactory
interface, SingleConnectionFactory102,
based on the JMS 1.0.2 API that will return the
same Connection on all
createConnection() calls and ignore calls to
close(). You will need to set the boolean
property pubSubDomain to indicate which
messaging domain is used as
SingleConnectionFactory102 will always
explicitly differentiate between a
javax.jms.QueueConnection and a
javax.jmsTopicConnection.
B.1.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:
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 matches(Class clazz);
}
The matches(Method, Class) method is used to test whether this pointcut will ever
match a given method on a target class. This evaluation can be performed when an AOP
proxy is created, to avoid the need for a test on every method invocation. If the 2-argument
matches method returns true for a given method, and the isRuntime() method for the
MethodMatcher returns true, the 3-argument matches method will be invoked on every
method invocation. This enables a pointcut to look at the arguments passed to the method
invocation immediately before the target advice is to execute.
Most MethodMatchers are static, meaning that their isRuntime() method returns false.
In this case, the 3-argument matches method will never be invoked.
Tip
If possible, try to make pointcuts static, allowing the AOP framework to
cache the results of pointcut evaluation when an AOP proxy is created.
See the previous chapter for a discussion of supported AspectJ pointcut primitives.
Static pointcuts
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.
Attribute-driven pointcuts
An important type of static pointcut is a metadata-driven pointcut. This uses the values of
metadata attributes: typically, source-level metadata.
Dynamic pointcuts
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.
advisors. These do not depend on the state of the proxied object or add new state; they
merely act on the method and arguments.
Per-instance advice is appropriate for introductions, to support mixins. In this case, the
advice adds state to the proxied object.
It's possible to use a mix of shared and per-instance advice in the same AOP proxy.
The MethodInvocation argument to the invoke() method exposes the method being
invoked; the target join point; the AOP proxy; and the arguments to the method. The
invoke() method should return the invocation's result: the return value of the join point.
A simple MethodInterceptor implementation looks as follows:
public class DebugInterceptor implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("Before: invocation=[" + invocation + "]");
Object rval = invocation.proceed();
System.out.println("Invocation returned");
return rval;
}
}
Note the call to the MethodInvocation's proceed() method. This proceeds down the
interceptor chain towards the join point. Most interceptors will invoke this method, and
return its return value. However, a MethodInterceptor, like any around advice, can return a
different value or throw an exception rather than invoke the proceed method. However, you
don't want to do this without good reason!
Note
MethodInterceptors offer interoperability with other AOP Alliancecompliant AOP implementations. The other advice types discussed in
the remainder of this section implement common AOP concepts, but in
a Spring-specific way. While there is an advantage in using the most
specific advice type, stick with MethodInterceptor around advice if you
are likely to want to run the aspect in another AOP framework. Note that
pointcuts are not currently interoperable between frameworks, and the
AOP Alliance does not currently define pointcut interfaces.
Before advice
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 {
void before(Method m, Object[] args, Object target) throws Throwable;
}
Note the return type is void. Before advice can insert custom behavior before the join
point executes, but cannot change the return value. If a before advice throws an exception,
this will abort further execution of the interceptor chain. The exception will propagate back
up the interceptor chain. If it is unchecked, or on the signature of the invoked method, it will
be passed directly to the client; otherwise it will be wrapped in an unchecked exception by
the AOP proxy.
An example of a before advice in Spring, which counts all method invocations:
public class CountingBeforeAdvice implements MethodBeforeAdvice {
private int count;
public void before(Method m, Object[] args, Object target) throws Throwable {
++count;
}
public int getCount() {
return count;
}
}
Tip
Before advice can be used with any pointcut.
Throws advice
Throws advice is invoked after the return of the join point if the join point 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 in the form of:
afterThrowing([Method, args, target], subclassOfThrowable)
Only the last argument is required. The method signatures may have either one or four
arguments, depending on whether the advice method is interested in the method and
arguments. The following classes are examples of throws advice.
The advice below is invoked if a RemoteException is thrown (including subclasses):
public class RemoteThrowsAdvice implements ThrowsAdvice {
public void afterThrowing(RemoteException ex) throws Throwable {
// Do something with remote exception
}
}
The final example illustrates how these two methods could be used in a single class,
which handles both RemoteException and ServletException. Any number of
throws advice methods can be combined in a single class.
public static class CombinedThrowsAdvice implements ThrowsAdvice {
public void afterThrowing(RemoteException ex) throws Throwable {
// Do something with remote exception
}
public void afterThrowing(Method m, Object[] args, Object target, ServletException ex) {
// Do something with all arguments
}
}
Note: If a throws-advice method throws an exception itself, it will override the original
exception (i.e. change the exception thrown to the user). The overriding exception will
typically be a RuntimeException; this is compatible with any method signature. However, if
a throws-advice method throws a checked exception, it will have to match the declared
exceptions of the target method and is hence to some degree coupled to specific target
method signatures. Do not throw an undeclared checked exception that is incompatible
with the target method's signature!
Tip
Throws advice can be used with any pointcut.
An after returning advice has access to the return value (which it cannot modify), invoked
method, methods arguments and target.
The following after returning advice counts all successful method invocations that have not
thrown exceptions:
public class CountingAfterReturningAdvice implements AfterReturningAdvice {
private int count;
public void afterReturning(Object returnValue, Method m, Object[] args, Object target)
throws Throwable {
++count;
}
public int getCount() {
return count;
}
}
This advice doesn't change the execution path. If it throws an exception, this will be thrown
up the interceptor chain instead of the return value.
Tip
After returning advice can be used with any pointcut.
Introduction advice
Spring treats introduction advice as a special kind of interception advice.
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 suppressInterface(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
implements Lockable {
private boolean locked;
public void lock() {
this.locked = true;
}
public void unlock() {
this.locked = false;
}
public boolean locked() {
return this.locked;
}
public Object invoke(MethodInvocation invocation) throws Throwable {
if (locked() && invocation.getMethod().getName().indexOf("set") == 0)
throw new LockedException();
return super.invoke(invocation);
}
}
B.4.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 another 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.
Note that the interceptorNames property takes a list of String: the bean names of the
interceptor or advisors in the current factory. Advisors, interceptors, before, after returning
and throws advice objects can be used. The ordering of advisors is significant.
Note
You might be wondering why the list doesn't hold bean references. The
reason for this is that if the ProxyFactoryBean's singleton property is set
to false, it must be able to return independent proxy instances. If any of
the advisors is itself a prototype, an independent instance would need
to be returned, so it's necessary to be able to obtain an instance of the
prototype from the factory; holding a reference isn't sufficient.
The "person" bean definition above can be used in place of a Person implementation, as
follows:
Person person = (Person) factory.getBean("person");
Other beans in the same IoC context can express a strongly typed dependency on it, as
with an ordinary Java object:
<bean id="personUser" class="com.mycompany.PersonUser">
<property name="person"><ref local="person" /></property>
</bean>
The PersonUser class in this example would expose a property of type Person. As far as
it's concerned, the AOP proxy can be used transparently in place of a "real" person
implementation. However, its class would be a dynamic proxy class. It would be possible
to cast it to the Advised interface (discussed below).
It's possible to conceal the distinction between target and proxy using an anonymous inner
bean, as follows. Only the ProxyFactoryBean definition is different; the advice is
included only for completeness:
<bean id="myAdvisor" class="com.mycompany.MyAdvisor">
<property name="someProperty"><value>Custom string property value</value></property>
</bean>
<bean id="debugInterceptor" class="org.springframework.aop.interceptor.DebugInterceptor"/>
<bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"><value>com.mycompany.Person</value></property>
<!-- Use inner bean, not local reference to target -->
<property name="target">
<bean class="com.mycompany.PersonImpl">
<property name="name"><value>Tony</value></property>
<property name="age"><value>51</value></property>
</bean>
</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 from 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.
prescriptive. While it makes it easy to apply good practices, it avoids forcing a particular
approach.)
If you want to, you can force the use of CGLIB in any case, even if you do have interfaces.
CGLIB proxying works by generating a subclass of the target class at runtime. Spring
configures this generated subclass to delegate method calls to the original target: the
subclass is used to implement the Decorator pattern, weaving in the advice.
CGLIB proxying should generally be transparent to users. However, there are some issues
to consider:
Final methods can't be advised, as they can't be overridden.
As of Spring 3.2 it is no longer required to add CGLIB to your project classpath. CGLIB
classes have been repackaged under org.springframework and included directly in the
spring-core JAR. This is both for user convenience as well as to avoid potential
conflicts with other projects that have dependence on a differing version of CGLIB.
There's little performance difference between CGLIB proxying and dynamic proxies. As of
Spring 1.0, dynamic proxies are slightly faster. However, this may change in the future.
Performance should not be a decisive consideration in this case.
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 wraps the target of the
proxy as an inner bean definition, since the target will never be used on its own anyway.
<bean id="myService" parent="txProxyTemplate">
<property name="target">
<bean class="org.springframework.samples.MyServiceImpl">
</bean>
</property>
</bean>
It is of course possible to override properties from the parent template, such as in this case,
Note that in the example above, we have explicitly marked the parent bean definition as
abstract by using the abstract attribute, as described previously, so that it may not actually
ever be instantiated. Application contexts (but not simple bean factories) will by default preinstantiate all singletons. It is therefore important (at least for singleton beans) that if you
have a (parent) bean definition which you intend to use only as a template, and this
definition specifies a class, you must make sure to set the abstract attribute to true,
otherwise the application context will actually try to pre-instantiate it.
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 introductions).
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");
// Add an advice like an interceptor without a pointcut
// Will match all proxied methods
// Can use for interceptors, before, after returning or throws advice
advised.addAdvice(new DebugInterceptor());
// Add selective advice using a pointcut
advised.addAdvisor(new DefaultPointcutAdvisor(mySpecialPointcut, myAdvice));
assertEquals("Added two advisors",
oldAdvisorCount + 2, advised.getAdvisors().length);
Note
It's questionable whether it's advisable (no pun intended) to modify
advice on a business object in production, although there are no doubt
legitimate usage cases. However, it can be very useful in development:
for example, in tests. I have sometimes found it very useful to be able to
add test code in the form of an interceptor or other advice, getting inside
a method invocation I want to test. (For example, the advice can get
inside a transaction created for that method: for example, to run SQL to
check that a database was correctly updated, before marking the
transaction for roll back.)
Depending on how you created the proxy, you can usually set a frozen flag, in which
case the Advised isFrozen() method will return true, and any attempts to modify
advice through addition or removal will result in an AopConfigException. The ability to
freeze the state of an advised object is useful in some cases, for example, to prevent
calling code removing a security interceptor. It may also be used in Spring 1.1 to allow
aggressive optimization if runtime advice modification is known not to be required.
BeanNameAutoProxyCreator
The BeanNameAutoProxyCreator class is a BeanPostProcessor that
automatically creates AOP proxies for beans with names matching literal values or
wildcards.
<bean 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>
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 any) advice it should apply to each business
object (such as "businessObject1" and "businessObject2" in the example).
This means that any number of advisors can be applied automatically to each business
object. If no pointcut in any of the advisors matches any method in a business object, the
object will not be proxied. As bean definitions are added for new business objects, they
will automatically be proxied if necessary.
Autoproxying in general has the advantage of making it impossible for callers or
dependencies to obtain an un-advised object. Calling getBean("businessObject1") on this
ApplicationContext will return an AOP proxy, not the target business object. (The "inner
bean" idiom shown earlier also offers this benefit.)
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
<bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">
<property name="transactionInterceptor" ref="transactionInterceptor"/>
</bean>
<bean id="customAdvisor" class="com.mycompany.MyAdvisor"/>
<bean id="businessObject1" class="com.mycompany.BusinessObject1">
<!-- Properties omitted -->
</bean>
<bean id="businessObject2" class="com.mycompany.BusinessObject2"/>
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 behavior of the framework
DefaultAdvisorAutoProxyCreator.
Tip
If you require only declarative transaction management, using these
generic XML definitions will result in Spring automatically proxying all
If the attribute aware pointcut matches any methods in the anyBean or other bean
definitions, the mixin will be applied. Note that both lockMixin and lockableAdvisor
definitions are prototypes. The myAttributeAwarePointcut pointcut can be a
singleton definition, as it doesn't hold state for individual advised objects.
references to it.
Changing the target source's target takes effect immediately. The
HotSwappableTargetSource is threadsafe.
You can change the target via the swap() method on HotSwappableTargetSource as
follows:
HotSwappableTargetSource swapper =
(HotSwappableTargetSource) beanFactory.getBean("swapper");
Object oldTarget = swapper.swap(newTarget);
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.
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 its 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 necessary to specify interceptors to use pooling. If
you want only pooling, and no other advice, don't set the interceptorNames property at all.
It's possible to configure Spring so as to be able to cast any pooled object to the
org.springframework.aop.target.PoolingConfig interface, which exposes
information about the configuration and current size of the pool through an introduction.
You'll need to define an advisor like this:
<bean id="poolConfigAdvisor" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="poolTargetSource"/>
<property name="targetMethod" value="getPoolingConfigMixin"/>
</bean>
Note
Pooling stateless service objects is not usually necessary. We don't
believe it should be the default choice, as most stateless objects are
naturally thread safe, and instance pooling is problematic if resources
are cached.
Simpler pooling is available using autoproxying. It's possible to set the TargetSources
used by any autoproxy creator.
There's only one property: the name of the target bean. Inheritance is used in the
TargetSource implementations to ensure consistent naming. As with the pooling target
source, the target bean must be a prototype bean definition.
Note
ThreadLocals come with serious issues (potentially resulting in
memory leaks) when incorrectly using them in a multi-threaded and
multi-classloader environments. One should always consider wrapping
a threadlocal in some other class and never directly use the
ThreadLocal itself (except of course in the wrapper class). Also, one
should always remember to correctly set and unset (where the latter
simply involved a call to ThreadLocal.set(null)) the resource
local to the thread. Unsetting should be done in any case since not
unsetting it might result in problematic behavior. Spring's ThreadLocal
support does this for you and should always be considered in favor of
using ThreadLocals without other proper handling code.
Therefore, in order to avoid errors like the one reported in SPR-9843, any such directives
should be updated to at least one more level of qualification e.g.:
<context:component-scan base-package="org.xyz"/>
URI, even if the 'Accept' header doesn't request those media types.
The newly added support for matrix variables is explained in the section called Matrix
Variables. To preserve backward compatibility, by default, semicolon content is removed
from incoming request URIs and therefore @MatrixVariable cannot be used without
additional configuration. However, when using the MVC Java config and the MVC
namespace, semicolon content is left in the URI so that matrix variables are automatically
supported. The removal of semicolon content is controlled through the UrlPathHelper
property of RequestMappingHandlerMapping.
D.9 Tiles 3
Besides the version number change, the set of Tiles dependencies has also changed. You
will need to have a subset or all of tiles-request-api, tiles-api, tiles-core,
tiles-servlet, tiles-jsp, tiles-el.
D.12.2 Deprecations
The following packages and types have been wholly or partially deprecated in Spring
Framework 3.2 and may be removed in a future version. Click through to the linked
Javadoc for each item for exact details. See also the complete list of deprecations in the
framework.
org.springframework.orm.ibatis
org.springframework.scheduling.backportconcurrent
org.springframework.ejb.support
org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter
org.springframework.web.jsf.DelegatingVariableResolver
org.springframework.web.jsf.SpringBeanVariableResolver
org.springframework.ui.velocity.CommonsLoggingLogSystem
org.springframework.ui.velocity.VelocityEngineUtils
org.springframework.beans.factory.config.BeanReferenceFactoryBean
org.springframework.beans.factory.config.CommonsLogFactoryBean
org.springframework.beans.instrument.classloading.oc4j.OC4JLoadTimeWeaver
org.springframework.transaction.jta.OC4JJtaTransactionManager
org.springframework.web.util.ExpressionEvaluationUtils
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver
org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping
org.springframework.web.servlet.mvc.annotation.ServletAnnotationMappingUtils
org.springframework.jmx.support.MBeanRegistrationSupport
org.springframework.test.context.ContextConfigurationAttributes
org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests:
use of the simpleJdbcTemplate instance variable has been deprecated in favor of
the new jdbcTemplate instance variable.
org.springframework.test.context.testng.AbstractTransactionalTestNGSpringContextTests:
use of the simpleJdbcTemplate instance variable has been deprecated in favor of
the new jdbcTemplate instance variable.
org.springframework.test.jdbc.SimpleJdbcTestUtils has been deprecated in favor of
JdbcTestUtils which now contains all of the functionality previously available in
SimpleJdbcTestUtils.
org.springframework.web.servlet.view.ContentNegotiatingViewResolver
org.springframework.transaction.interceptor.TransactionAspectUtils
org.springframework.http.HttpStatus
org.springframework.web.util.UriUtils
org.springframework.orm.jpa.vendor.TopLinkJpaDialect
org.springframework.orm.jpa.vendor.TopLinkJpaVendorAdapter
org.springframework.orm.util.CachingMapDecorator
DTD support?
Authoring Spring configuration
files using the older DTD style is
still fully supported.
Nothing will break if you forego
the use of the new XML Schema-
instances).
BeanDefinition
Note
The 'xsi:schemaLocation' fragment is not actually required, but
can be included to reference a local copy of a schema (which can be
useful during development).
The above Spring XML configuration fragment is boilerplate that you can copy and paste
(!) and then plug <bean/> definitions into like you have always done. However, the entire
point of switching over is to take advantage of the new Spring 2.0 XML tags since they
make configuration easier. The section entitled Section E.2.2, The util schema
demonstrates how you can start immediately by using some of the more common utility
tags.
The rest of this chapter is devoted to showing examples of the new Spring XML Schema
based configuration, with at least one example for every new tag. The format follows a
before and after style, with a before snippet of XML showing the old (but still 100% legal
and supported) style, followed immediately by an after example showing the equivalent in
the new XML Schema-based style.
<util:constant/>
Before...
<bean id="..." class="...">
<property name="isolation">
<bean id="java.sql.Connection.TRANSACTION_SERIALIZABLE"
class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean" />
</property>
</bean>
Find below an example which shows how a static field is exposed, by using the
staticField property:
<bean id="myField"
class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property name="staticField" value="java.sql.Connection.TRANSACTION_SERIALIZABLE"/>
</bean>
There is also a convenience usage form where the static field is specified as the bean
name:
<bean id="java.sql.Connection.TRANSACTION_SERIALIZABLE"
class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean"/>
This does mean that there is no longer any choice in what the bean id is (so any other
bean that refers to it will also have to use this longer name), but this form is very concise to
define, and very convenient to use as an inner bean since the id doesn't have to be
specified for the bean reference:
<bean id="..." class="...">
<property name="isolation">
<bean id="java.sql.Connection.TRANSACTION_SERIALIZABLE"
class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean" />
</property>
</bean>
This works for classic type-safe emulated enums (on JDK 1.4 and JDK 1.3) as well; Spring
will automatically attempt to match the string property value to a constant on the enum
class.
<util:property-path/>
Before...
The value of the 'path' attribute of the <property-path/> tag follows the form
'beanName.beanProperty'.
There is also a shortcut form, where the bean name is the property path.
<!-- will result in 10, which is the value of property 'age' of bean 'person' -->
<bean id="person.age"
class="org.springframework.beans.factory.config.PropertyPathFactoryBean"/>
This form does mean that there is no choice in the name of the bean. Any reference to it
will also have to use the same id, which is the path. Of course, if used as an inner bean,
there is no need to refer to it at all:
<bean id="..." class="...">
<property name="age">
<bean id="person.age"
class="org.springframework.beans.factory.config.PropertyPathFactoryBean"/>
</property>
</bean>
The result type may be specifically set in the actual definition. This is not necessary for
most use cases, but can be of use for some. Please see the Javadocs for more info on this
feature.
<util:properties/>
Before...
<!-- creates a java.util.Properties instance with values loaded from the supplied location -->
<bean id="jdbcConfiguration" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location" value="classpath:com/foo/jdbc-production.properties"/>
</bean>
<util:list/>
Before...
<!-- creates a java.util.List instance with values loaded from the supplied 'sourceList' -->
<bean id="emails" class="org.springframework.beans.factory.config.ListFactoryBean">
<property name="sourceList">
<list>
<value>pechorin@hero.org</value>
<value>raskolnikov@slums.org</value>
<value>stavrogin@gov.org</value>
<value>porfiry@gov.org</value>
</list>
</property>
</bean>
You can also explicitly control the exact type of List that will be instantiated and
populated via the use of the 'list-class' attribute on the <util:list/> element.
For example, if we really need a java.util.LinkedList to be instantiated, we could
You can also explicitly control the exact type of Map that will be instantiated and populated
via the use of the 'map-class' attribute on the <util:map/> element. For example, if
we really need a java.util.TreeMap to be instantiated, we could use the following
configuration:
<util:map id="emails" map-class="java.util.TreeMap">
<entry key="pechorin" value="pechorin@hero.org"/>
<entry key="raskolnikov" value="raskolnikov@slums.org"/>
<entry key="stavrogin" value="stavrogin@gov.org"/>
<entry key="porfiry" value="porfiry@gov.org"/>
</util:map>
You can also explicitly control the exact type of Set that will be instantiated and populated
via the use of the 'set-class' attribute on the <util:set/> element. For example, if
we really need a java.util.TreeSet to be instantiated, we could use the following
configuration:
<util:set id="emails" set-class="java.util.TreeSet">
<value>pechorin@hero.org</value>
<value>raskolnikov@slums.org</value>
<value>stavrogin@gov.org</value>
<value>porfiry@gov.org</value>
</util:set>
<jee:jndi-lookup/> (simple)
Before...
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/MyDataSource"/>
</bean>
<bean id="userDao" class="com.foo.JdbcUserDao">
<!-- Spring will do the cast automatically (as usual) -->
<property name="dataSource" ref="dataSource"/>
</bean>
After...
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/MyDataSource"/>
<bean id="userDao" class="com.foo.JdbcUserDao">
<!-- Spring will do the cast automatically (as usual) -->
<property name="dataSource" ref="dataSource"/>
</bean>
After...
<jee:jndi-lookup id="simple" jndi-name="jdbc/MyDataSource">
<jee:environment>foo=bar</jee:environment>
</jee:jndi-lookup>
After...
<jee:jndi-lookup id="simple" jndi-name="jdbc/MyDataSource">
<!-- newline-separated, key-value pairs for the environment (standard Properties format) -->
<jee:environment>
foo=bar
ping=pong
</jee:environment>
</jee:jndi-lookup>
<jee:jndi-lookup/> (complex)
Before...
<bean id="simple" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/MyDataSource"/>
<property name="cache" value="true"/>
<property name="resourceRef" value="true"/>
<property name="lookupOnStartup" value="false"/>
<property name="expectedType" value="com.myapp.DefaultFoo"/>
<property name="proxyInterface" value="com.myapp.Foo"/>
</bean>
After...
<jee:jndi-lookup id="simple"
jndi-name="jdbc/MyDataSource"
cache="true"
resource-ref="true"
lookup-on-startup="false"
expected-type="com.myapp.DefaultFoo"
proxy-interface="com.myapp.Foo"/>
<jee:local-slsb/> (simple)
The <jee:local-slsb/> tag configures a reference to an EJB Stateless SessionBean.
Before...
<bean id="simple"
class="org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean">
<property name="jndiName" value="ejb/RentalServiceBean"/>
<property name="businessInterface" value="com.foo.service.RentalService"/>
</bean>
After...
<jee:local-slsb id="simpleSlsb" jndi-name="ejb/RentalServiceBean"
business-interface="com.foo.service.RentalService"/>
<jee:local-slsb/> (complex)
<bean id="complexLocalEjb"
class="org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean">
<property name="jndiName" value="ejb/RentalServiceBean"/>
<property name="businessInterface" value="com.foo.service.RentalService"/>
<property name="cacheHome" value="true"/>
<property name="lookupHomeOnStartup" value="true"/>
<property name="resourceRef" value="true"/>
</bean>
After...
<jee:local-slsb id="complexLocalEjb"
jndi-name="ejb/RentalServiceBean"
business-interface="com.foo.service.RentalService"
cache-home="true"
lookup-home-on-startup="true"
resource-ref="true">
<jee:remote-slsb/>
The <jee:remote-slsb/> tag configures a reference to a remote EJB Stateless
SessionBean.
Before...
<bean id="complexRemoteEjb"
class="org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean">
<property name="jndiName" value="ejb/MyRemoteBean"/>
<property name="businessInterface" value="com.foo.service.RentalService"/>
<property name="cacheHome" value="true"/>
<property name="lookupHomeOnStartup" value="true"/>
<property name="resourceRef" value="true"/>
<property name="homeInterface" value="com.foo.service.RentalService"/>
<property name="refreshHomeOnConnectFailure" value="true"/>
</bean>
After...
<jee:remote-slsb id="complexRemoteEjb"
jndi-name="ejb/MyRemoteBean"
business-interface="com.foo.service.RentalService"
cache-home="true"
lookup-home-on-startup="true"
resource-ref="true"
home-interface="com.foo.service.RentalService"
refresh-home-on-connect-failure="true">
Note
Often when using the tags in the tx namespace you will also be using
the tags from the aop namespace (since the declarative transaction
support in Spring is implemented using AOP). The above XML snippet
contains the relevant lines needed to reference the aop schema so that
the tags in the aop namespace are available to you.
The aop tags deal with configuring all things AOP in Spring: this includes Spring's own
proxy-based AOP framework and Spring's integration with the AspectJ AOP framework.
These tags are comprehensively covered in the chapter entitled Chapter 9, Aspect
Oriented Programming with Spring.
In the interest of completeness, to use the tags in the aop schema, you need to have the
following preamble at the top of your Spring XML configuration file; the text in the following
snippet references the correct schema so that the tags in the aop namespace are available
to you.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- bean definitions here -->
</beans>
Note
The context schema was only introduced in Spring 2.5.
<property-placeholder/>
This element activates the replacement of ${...} placeholders, resolved against the
specified properties file (as a Spring resource location). This element is a convenience
mechanism that sets up a PropertyPlaceholderConfigurer for you; if you need
more control over the PropertyPlaceholderConfigurer, just define one yourself
explicitly.
<annotation-config/>
Activates the Spring infrastructure for various annotations to be detected in bean classes:
Spring's @Required and @Autowired, as well as JSR 250's @PostConstruct,
@PreDestroy and @Resource (if available), and JPA's @PersistenceContext and
@PersistenceUnit (if available). Alternatively, you can choose to activate the
individual BeanPostProcessors for those annotations explicitly.
Note
This element does not activate processing of Spring's
@Transactional annotation. Use the <tx:annotationdriven/> element for that purpose.
<component-scan/>
This element is detailed in Section 5.9, Annotation-based container configuration.
<load-time-weaver/>
This element is detailed in Section 9.8.4, Load-time weaving with AspectJ in the Spring
Framework.
<spring-configured/>
This element is detailed in Section 9.8.1, Using AspectJ to dependency inject domain
objects with Spring.
<mbean-export/>
This element is detailed in Section 24.4.3, Configuring annotation based MBean export.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jdbc="http://www.springframework.org/schema/cache"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/jdbc/spring-cache.xsd">
<!-- bean definitions here -->
</beans>
In the case of the above example, you would assume that there is some logic that will
consume the bean definition and set up some caching infrastructure using the supplied
metadata.
(Don't worry about the fact that this example is very simple; much more detailed examples
follow afterwards. The intent in this first simple example is to walk you through the basic
steps involved.)
(The emphasized line contains an extension base for all tags that will be identifiable
(meaning they have an id attribute that will be used as the bean identifier in the container).
We are able to use this attribute because we imported the Spring-provided 'beans'
namespace.)
The above schema will be used to configure SimpleDateFormat objects, directly in an
XML application context file using the <myns:dateformat/> element.
<myns:dateformat id="dateFormat"
pattern="yyyy-MM-dd HH:mm"
lenient="true"/>
Note that after we've created the infrastructure classes, the above snippet of XML will
essentially be exactly the same as the following XML snippet. In other words, we're just
creating a bean in the container, identified by the name 'dateFormat' of type
SimpleDateFormat, with a couple of properties set.
<bean id="dateFormat" class="java.text.SimpleDateFormat">
<constructor-arg value="yyyy-HH-dd HH:mm"/>
<property name="lenient" value="true"/>
</bean>
Note
The schema-based approach to creating configuration format allows for
The observant reader will notice that there isn't actually a whole lot of parsing logic in this
class. Indeed... the NamespaceHandlerSupport class has a built in notion of
delegation. It supports the registration of any number of BeanDefinitionParser
instances, to which it will delegate to when it needs to parse an element in its namespace.
This clean separation of concerns allows a NamespaceHandler to handle the
orchestration of the parsing of all of the custom elements in its namespace, while
delegating to BeanDefinitionParsers to do the grunt work of the XML parsing; this
means that each BeanDefinitionParser will contain just the logic for parsing a single
custom element, as we can see in the next step
responsible for parsing one distinct top-level XML element defined in the schema. In the
parser, we'll have access to the XML element (and thus its subelements too) so that we
can parse our custom XML content, as can be seen in the following example:
package org.springframework.samples.xml;
import
import
import
import
org.springframework.beans.factory.support.BeanDefinitionBuilder;
org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
org.springframework.util.StringUtils;
org.w3c.dom.Element;
import java.text.SimpleDateFormat;
public class SimpleDateFormatBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
protected Class getBeanClass(Element element) {
return SimpleDateFormat.class;
}
protected void doParse(Element element, BeanDefinitionBuilder bean) {
// this will never be null since the schema explicitly requires that a value be supplied
String pattern = element.getAttribute("pattern");
bean.addConstructorArg(pattern);
// this however is an optional property
String lenient = element.getAttribute("lenient");
if (StringUtils.hasText(lenient)) {
bean.addPropertyValue("lenient", Boolean.valueOf(lenient));
}
}
}
F.5.1 'META-INF/spring.handlers'
The properties file called 'spring.handlers' contains a mapping of XML Schema
URIs to namespace handler classes. So for our example, we need to write the following:
http\://www.mycompany.com/schema/myns=org.springframework.samples.xml.MyNamespaceHandler
(The ':' character is a valid delimiter in the Java properties format, and so the ':'
character in the URI needs to be escaped with a backslash.)
The first part (the key) of the key-value pair is the URI associated with your custom
namespace extension, and needs to match exactly the value of the
'targetNamespace' attribute as specified in your custom XSD schema.
F.5.2 'META-INF/spring.schemas'
The properties file called 'spring.schemas' contains a mapping of XML Schema
locations (referred to along with the schema declaration in XML files that use the schema
as part of the 'xsi:schemaLocation' attribute) to classpath resources. This file is
needed to prevent Spring from absolutely having to use a default EntityResolver that
requires Internet access to retrieve the schema file. If you specify the mapping in this
properties file, Spring will search for the schema on the classpath (in this case
'myns.xsd' in the 'org.springframework.samples.xml' package):
http\://www.mycompany.com/schema/myns/myns.xsd=org/springframework/samples/xml/myns.xsd
The upshot of this is that you are encouraged to deploy your XSD file(s) right alongside the
NamespaceHandler and BeanDefinitionParser classes on the classpath.
The above configuration actually nests custom extensions within each other. The class
that is actually configured by the above <foo:component/> element is the Component
class (shown directly below). Notice how the Component class does not expose a setter
method for the 'components' property; this makes it hard (or rather impossible) to
configure a bean definition for the Component class using setter injection.
package com.foo;
import java.util.ArrayList;
import java.util.List;
public class Component {
private String name;
private List<Component> components = new ArrayList<Component> ();
// mmm, there is no setter method for the 'components'
public void addComponent(Component component) {
this.components.add(component);
}
public List<Component> getComponents() {
return components;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
The typical solution to this issue is to create a custom FactoryBean that exposes a setter
property for the 'components' property.
package com.foo;
import org.springframework.beans.factory.FactoryBean;
import java.util.List;
public class ComponentFactoryBean implements FactoryBean<Component> {
private Component parent;
private List<Component> children;
public void setParent(Component parent) {
this.parent = parent;
}
public void setChildren(List<Component> children) {
this.children = children;
}
public Component getObject() throws Exception {
if (this.children != null && this.children.size() > 0) {
for (Component child : children) {
this.parent.addComponent(child);
}
}
return this.parent;
}
public Class<Component> getObjectType() {
return Component.class;
}
public boolean isSingleton() {
return true;
}
}
This is all very well, and does work nicely, but exposes a lot of Spring plumbing to the end
user. What we are going to do is write a custom extension that hides away all of this Spring
plumbing. If we stick to the steps described previously, we'll start off by creating the XSD
schema to define the structure of our custom tag.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsd:schema xmlns="http://www.foo.com/schema/component"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.foo.com/schema/component"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xsd:element name="component">
<xsd:complexType>
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element ref="component"/>
</xsd:choice>
<xsd:attribute name="id" type="xsd:ID"/>
org.springframework.beans.factory.config.BeanDefinition;
org.springframework.beans.factory.support.AbstractBeanDefinition;
org.springframework.beans.factory.support.BeanDefinitionBuilder;
org.springframework.beans.factory.support.ManagedList;
org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
org.springframework.beans.factory.xml.ParserContext;
org.springframework.util.xml.DomUtils;
org.w3c.dom.Element;
import java.util.List;
public class ComponentBeanDefinitionParser extends AbstractBeanDefinitionParser {
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
return parseComponentElement(element);
}
private static AbstractBeanDefinition parseComponentElement(Element element) {
BeanDefinitionBuilder factory = BeanDefinitionBuilder.rootBeanDefinition(ComponentFactoryBean.class);
factory.addPropertyValue("parent", parseComponent(element));
List<Element> childElements = DomUtils.getChildElementsByTagName(element, "component");
if (childElements != null && childElements.size() > 0) {
parseChildComponents(childElements, factory);
}
return factory.getBeanDefinition();
}
private static BeanDefinition parseComponent(Element element) {
BeanDefinitionBuilder component = BeanDefinitionBuilder.rootBeanDefinition(Component.class);
component.addPropertyValue("name", element.getAttribute("name"));
return component.getBeanDefinition();
}
private static void parseChildComponents(List<Element> childElements, BeanDefinitionBuilder factory) {
ManagedList<BeanDefinition> children = new ManagedList<BeanDefinition>(childElements.size());
for (Element element : childElements) {
children.add(parseComponentElement(element));
}
factory.addPropertyValue("children", children);
}
}
Lastly, the various artifacts need to be registered with the Spring XML infrastructure.
# in 'META-INF/spring.handlers'
http\://www.foo.com/schema/component=com.foo.ComponentNamespaceHandler
# in 'META-INF/spring.schemas'
http\://www.foo.com/schema/component/component.xsd=com/foo/component.xsd
existing bean definitions. In this case you certainly don't want to have to go off and write
your own entire custom extension; rather you just want to add an additional attribute to the
existing bean definition element.
By way of another example, let's say that the service class that you are defining a bean
definition for a service object that will (unknown to it) be accessing a clustered JCache,
and you want to ensure that the named JCache instance is eagerly started within the
surrounding cluster:
<bean id="checkingAccountService" class="com.foo.DefaultCheckingAccountService"
jcache:cache-name="checking.account">
<!-- other dependencies here... -->
</bean>
Now onto the custom extension. Firstly, the authoring of the XSD schema describing the
custom attribute (quite easy in this case).
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsd:schema xmlns="http://www.foo.com/schema/jcache"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.foo.com/schema/jcache"
elementFormDefault="qualified">
<xsd:attribute name="cache-name" type="xsd:string"/>
</xsd:schema>
Next, the parser. Note that in this case, because we are going to be parsing an XML
attribute, we write a BeanDefinitionDecorator rather than a
BeanDefinitionParser.
package com.foo;
import
import
import
import
import
import
import
org.springframework.beans.factory.config.BeanDefinitionHolder;
org.springframework.beans.factory.support.AbstractBeanDefinition;
org.springframework.beans.factory.support.BeanDefinitionBuilder;
org.springframework.beans.factory.xml.BeanDefinitionDecorator;
org.springframework.beans.factory.xml.ParserContext;
org.w3c.dom.Attr;
org.w3c.dom.Node;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class JCacheInitializingBeanDefinitionDecorator implements BeanDefinitionDecorator {
private static final String[] EMPTY_STRING_ARRAY = new String[0];
public BeanDefinitionHolder decorate(
Node source, BeanDefinitionHolder holder, ParserContext ctx) {
String initializerBeanName = registerJCacheInitializer(source, ctx);
createDependencyOnJCacheInitializer(holder, initializerBeanName);
return holder;
}
private void createDependencyOnJCacheInitializer(BeanDefinitionHolder holder, String initializerBeanName) {
AbstractBeanDefinition definition = ((AbstractBeanDefinition) holder.getBeanDefinition());
String[] dependsOn = definition.getDependsOn();
if (dependsOn == null) {
dependsOn = new String[]{initializerBeanName};
} else {
List dependencies = new ArrayList(Arrays.asList(dependsOn));
dependencies.add(initializerBeanName);
dependsOn = (String[]) dependencies.toArray(EMPTY_STRING_ARRAY);
}
definition.setDependsOn(dependsOn);
}
private String registerJCacheInitializer(Node source, ParserContext ctx) {
String cacheName = ((Attr) source).getValue();
String beanName = cacheName + "-initializer";
if (!ctx.getRegistry().containsBeanDefinition(beanName)) {
BeanDefinitionBuilder initializer = BeanDefinitionBuilder.rootBeanDefinition(JCacheInitializer.class);
initializer.addConstructorArg(cacheName);
ctx.getRegistry().registerBeanDefinition(beanName, initializer.getBeanDefinition());
}
return beanName;
}
}
Lastly, the various artifacts need to be registered with the Spring XML infrastructure.
# in 'META-INF/spring.handlers'
http\://www.foo.com/schema/jcache=com.foo.JCacheNamespaceHandler
# in 'META-INF/spring.schemas'
http\://www.foo.com/schema/jcache/jcache.xsd=com/foo/jcache.xsd
Appendix G. spring.tld
G.1 Introduction
One of the view technologies you can use with the Spring Framework is Java Server
Pages (JSPs). To help you implement views using Java Server Pages the Spring
Framework provides you with some tags for evaluating errors, setting themes and
outputting internationalized messages.
Please note that the various tags generated by this form tag library are compliant with the
XHTML-1.0-Strict specification and attendant DTD.
This appendix describes the spring.tld tag library.
Section G.2, The bind tag
Section G.3, The escapeBody tag
Section G.4, The hasBindErrors tag
Section G.5, The htmlEscape tag
Required?
Runtime
Expression?
Description
false
true
ignoreNestedPath false
true
true
htmlEscape
path
true
Required?
Runtime
Expression?
Description
false
true
javaScriptEscape false
true
htmlEscape
Provides Errors instance in case of bind errors. The HTML escaping flag participates in a
page-wide or application-wide setting (i.e. by HtmlEscapeTag or a "defaultHtmlEscape"
context-param in web.xml).
Required?
htmlEscape false
name
true
Runtime
Expression?
Description
true
true
Required?
defaultHtmlEscape true
Runtime
Expression?
true
Description
Set the default value for
HTML escaping, to be put
into the current
PageContext.
arguments
Required?
false
argumentSeparator false
Runtime
Expression?
Description
true
true
code
false
true
htmlEscape
false
true
javaScriptEscape
false
true
true
A
MessageSourceResolvable
argument (direct or through
JSP EL). Fits nicely when
used in conjunction with
Spring's own validation
error classes which all
implement the
MessageSourceResolvable
interface. For example, this
allows you to iterate over all
of the errors in a form,
passing each error (using a
runtime expression) as the
value of this 'message'
attribute, thus effecting the
easy display of such error
messages.
true
true
true
message
false
scope
false
text
false
var
false
path
Required?
true
Runtime
Expression?
true
Description
Set the path that this tag should
apply. E.g. 'customer' to allow bind
paths like 'address.street' rather
than 'customer.address.street'.
arguments
Required?
false
argumentSeparator false
code
false
Runtime
Expression?
Description
true
true
true
htmlEscape
false
true
javaScriptEscape
false
true
true
A
MessageSourceResolvable
argument (direct or through
JSP EL).
true
true
true
message
scope
text
var
false
false
false
false
Required?
htmlEscape false
scope
value
var
false
true
false
Runtime
Expression?
Description
true
true
true
true
url
context
Required?
true
false
Runtime
Expression?
true
true
Description
The URL to build. This value
can include template
{placeholders} that are
replaced with the URL
encoded value of the named
parameter. Parameters must
be defined using the param
tag inside the body of this
tag.
Specifies a remote
application context path. The
default is the current
true
true
false
true
javaScriptEscape false
true
var
false
scope
htmlEscape
false
Required?
Description
true
true
true
false
true
javaScriptEscape false
true
var
scope
htmlEscape
true
Runtime
Expression?
false
false
Appendix H. spring-form.tld
H.1 Introduction
One of the view technologies you can use with the Spring Framework is Java Server
Pages (JSPs). To help you implement views using Java Server Pages the Spring
Framework provides you with some tags for evaluating errors, setting themes and
outputting internationalized messages.
Please note that the various tags generated by this form tag library are compliant with the
XHTML-1.0-Strict specification and attendant DTD.
This appendix describes the spring-form.tld tag library.
Section H.2, The checkbox tag
Section H.3, The checkboxes tag
Section H.4, The errors tag
Section H.5, The form tag
Section H.6, The hidden tag
Section H.7, The input tag
Section H.8, The label tag
Section H.9, The option tag
Section H.10, The options tag
Section H.11, The password tag
Section H.12, The radiobutton tag
Section H.13, The radiobuttons tag
Section H.14, The select tag
Section H.15, The textarea tag
Required?
Runtime
Expression?
Description
accesskey
false
true
cssClass
false
true
cssErrorClass
false
true
cssStyle
false
true
dir
false
true
disabled
false
true
htmlEscape
false
true
id
false
true
label
false
true
lang
false
true
onblur
false
true
onchange
false
true
onclick
false
true
ondblclick
false
true
onfocus
false
true
onkeydown
false
true
onkeypress
false
true
onkeyup
false
true
onmousedown false
true
onmousemove false
true
onmouseout
false
true
onmouseover
false
true
onmouseup
false
true
path
true
true
tabindex
false
true
title
false
true
value
false
true
Required?
Runtime
Expression?
Description
accesskey
false
true
cssClass
false
true
cssErrorClass
false
true
cssStyle
false
true
delimiter
false
true
dir
false
true
true
disabled
false
element
false
true
htmlEscape
false
true
id
false
true
itemLabel
false
true
items
true
true
itemValue
false
true
lang
false
true
onblur
false
true
onchange
false
true
onclick
false
true
ondblclick
false
true
onfocus
false
true
onkeydown
false
true
onkeypress
false
true
onkeyup
false
true
onmousedown false
true
onmousemove false
true
onmouseout
false
true
onmouseover
false
true
onmouseup
false
true
path
true
true
tabindex
false
true
title
false
true
Required?
Runtime
Expression?
Description
cssClass
false
true
cssStyle
false
true
delimiter
false
true
dir
false
true
element
false
true
htmlEscape
false
true
id
false
true
lang
false
true
onclick
false
true
ondblclick
false
true
onkeydown
false
true
onkeypress
false
true
onkeyup
false
true
onmousedown false
true
onmousemove false
true
onmouseout
false
true
onmouseover
false
true
onmouseup
false
true
path
false
true
tabindex
false
true
title
false
true
Required?
Runtime
Expression?
Description
acceptCharset
false
true
action
false
true
commandName false
true
cssClass
false
true
cssStyle
false
true
dir
false
true
enctype
false
true
htmlEscape
false
true
Enable/disable HTML
escaping of rendered values.
id
false
true
lang
false
true
method
false
true
modelAttribute
false
true
name
false
true
onclick
false
true
ondblclick
false
true
onkeydown
false
true
onkeypress
false
true
onkeyup
false
true
onmousedown
false
true
onmousemove
false
true
onmouseout
false
true
onmouseover
false
true
onmouseup
false
true
onreset
false
true
onsubmit
false
true
target
false
true
title
false
true
Required?
Runtime
Expression?
Description
htmlEscape false
true
id
false
true
path
true
true
Required?
Runtime
Expression?
Description
accesskey
false
true
alt
false
true
autocomplete
false
true
cssClass
false
true
cssErrorClass
false
true
cssStyle
false
true
dir
false
true
disabled
false
true
htmlEscape
false
true
id
false
true
lang
false
true
maxlength
false
true
onblur
false
true
onchange
false
true
onclick
false
true
ondblclick
false
true
onfocus
false
true
onkeydown
false
true
onkeypress
false
true
onkeyup
false
true
onmousedown false
true
onmousemove false
true
onmouseout
false
true
onmouseover
false
true
onmouseup
false
true
onselect
false
true
path
true
true
readonly
false
true
size
false
true
tabindex
false
true
title
false
true
Attribute
Required?
Runtime
Expression?
Description
cssClass
false
true
cssErrorClass
false
true
cssStyle
false
true
dir
false
true
for
false
true
htmlEscape
false
true
id
false
true
lang
false
true
onclick
false
true
ondblclick
false
true
onkeydown
false
true
onkeypress
false
true
onkeyup
false
true
onmousedown false
true
onmousemove false
true
onmouseout
false
true
onmouseover
false
true
onmouseup
false
true
path
true
true
tabindex
false
true
title
false
true
Required?
Runtime
Expression?
Description
cssClass
false
true
cssErrorClass
false
true
cssStyle
false
true
dir
false
true
true
disabled
false
false
true
id
false
true
label
false
true
lang
false
true
onclick
false
true
ondblclick
false
true
onkeydown
false
true
onkeypress
false
true
onkeyup
false
true
onmousedown false
true
onmousemove false
true
onmouseout
false
true
onmouseover
false
true
onmouseup
false
true
tabindex
false
true
title
false
true
value
true
true
Required?
Runtime
Expression?
Description
cssClass
false
true
cssErrorClass
false
true
cssStyle
false
true
dir
false
true
disabled
false
true
htmlEscape
false
true
id
false
true
itemLabel
false
true
items
true
true
items
true
true
itemValue
false
true
lang
false
true
onclick
false
true
ondblclick
false
true
onkeydown
false
true
onkeypress
false
true
onkeyup
false
true
onmousedown false
true
onmousemove false
true
onmouseout
false
true
onmouseover
false
true
onmouseup
false
true
tabindex
false
true
title
false
true
Required?
Runtime
Expression?
Description
accesskey
false
true
alt
false
true
autocomplete
false
true
cssClass
false
true
cssErrorClass
false
true
cssStyle
false
true
dir
false
true
disabled
false
true
htmlEscape
false
true
Enable/disable HTML
escaping of rendered values.
id
false
true
lang
false
true
maxlength
false
true
onblur
false
true
onchange
false
true
onclick
false
true
ondblclick
false
true
onfocus
false
true
onkeydown
false
true
onkeypress
false
true
onkeyup
false
true
onmousedown
false
true
onmousemove
false
true
onmouseout
false
true
onmouseover
false
true
onmouseup
false
true
onselect
false
true
path
true
true
false
true
showPassword false
true
size
false
true
tabindex
false
true
title
false
true
readonly
Required?
Runtime
Expression?
Description
accesskey
false
true
cssClass
false
true
cssErrorClass
false
true
cssStyle
false
true
dir
false
true
disabled
false
true
htmlEscape
false
true
id
false
true
label
false
true
lang
false
true
onblur
false
true
onchange
false
true
onclick
false
true
ondblclick
false
true
onfocus
false
true
onkeydown
false
true
onkeypress
false
true
onkeyup
false
true
onmousedown false
true
onmousemove false
true
onmouseout
false
true
onmouseover
false
true
onmouseup
false
true
path
true
true
tabindex
false
true
title
false
true
value
false
true
Required?
Runtime
Expression?
Description
accesskey
false
true
cssClass
false
true
cssErrorClass
false
true
cssStyle
false
true
delimiter
false
true
dir
false
true
true
disabled
false
element
false
true
htmlEscape
false
true
id
false
true
itemLabel
false
true
items
true
true
itemValue
false
true
lang
false
true
onblur
false
true
onchange
false
true
onclick
false
true
ondblclick
false
true
onfocus
false
true
onkeydown
false
true
onkeypress
false
true
onkeyup
false
true
onmousedown false
true
onmousemove false
true
onmouseout
false
true
onmouseover
false
true
onmouseup
false
true
path
true
true
tabindex
false
true
title
false
true
Required?
Runtime
Expression?
Description
accesskey
false
true
cssClass
false
true
cssErrorClass
false
true
cssStyle
false
true
dir
false
true
disabled
false
true
htmlEscape
false
true
id
false
true
itemLabel
false
true
items
false
true
itemValue
false
true
lang
false
true
multiple
false
true
onblur
false
true
onchange
false
true
onclick
false
true
ondblclick
false
true
onfocus
false
true
onkeydown
false
true
onkeypress
false
true
onkeyup
false
true
onmousedown false
true
onmousemove false
true
onmouseout
false
true
onmouseover
false
true
onmouseup
false
true
path
true
true
size
false
true
tabindex
false
true
title
false
true
Required?
Runtime
Expression?
Description
accesskey
false
true
cols
false
true
cssClass
false
true
cssErrorClass
false
true
cssStyle
false
true
dir
false
true
disabled
false
true
htmlEscape
false
true
id
false
true
lang
false
true
onblur
false
true
onchange
false
true
onclick
false
true
ondblclick
false
true
onfocus
false
true
onkeydown
false
true
onkeypress
false
true
onkeyup
false
true
onmousedown false
true
onmousemove false
true
onmouseout
false
true
onmouseover
false
true
onmouseup
false
true
onselect
false
true
path
true
true
readonly
false
true
rows
false
true
tabindex
false
true
title
false
true