Spring
m
tech facts at your fingertips
dz.co
CONTENTS INCLUDE:
n Core Spring Annotations
n Spring MVC Annotations
r
efcar
Spring Annotations
n AspectJ Annotations
n JSR-250 Annotations
n Testing Annotations
By Craig Walls
n Hot Tips and more...
Autowiring Bean Properties, continued
SprINg ANNOTATIONS
@Autowired
public void setTreasureMap(TreasureMap treasureMap) {
From its beginning, Spring’s most common means of configuration
this.treasureMap = treasureMap;
has been XML-based. But as developers grow weary of navigating
}
through a seemingly endless maze of angle-brackets, some
}
have started looking for other ways to wire the beans in their
…and if you were to configure annotation configuration in Spring
Spring-enabled applications. Spring has responded with several
using the <context:annotation-configuration> element like this…
Subscribe Now for FREE!
annotation-driven configuration options. In this reference card,
<beans ... >
you'll find a guide to all of the annotations supported in Spring 2.5.
<bean id="pirate" class="Pirate">
<constructor-arg value="Long John Silver" />
</bean>
<bean id="treasureMap" class="TreasureMap" />
COrE SprINg ANNOTATIONS
<context:annotation-config />
</beans>
Context Configuration Annotations
…then the “treasureMap” property will be automatically
These annotations are used by Spring to guide creation and
injected with a reference to a bean whose type is assignable to
injection of beans.
TreasureMap (in this case, the bean whose ID is “treasureMap”).
Annotation
Use
Description
Autowiring Without Setter Methods
@Autowired
Constructor, Field,
Declares a constructor, field, setter
Method
method, or configuration method
@Autowired can be used on any method (not just setter methods).
m
to be autowired by type. Items
The wiring can be done through any method, as illustrated here:
annotated with @Autowired do not
have to be public.
@Autowired
e.co
@Configurable
Type
Used with <context:spring-
public void directionsToTreasure(TreasureMap
configured> to declare types whose
treasureMap) {
zon
properties should be injected, even
this.treasureMap = treasureMap;
if they are not instantiated by Spring.
.
d
}
Typically used to inject the properties
w
of domain objects.
And even on member variables:
@Order
Type, Method, Field
Defines ordering, as an alternative
@Autowired
ww
to implementing the org.
private TreasureMap treasureMap;
springframework.core.Ordered
interface.
To resolve any autowiring ambiguity, use the @Qualifier attribute
@Qualifier
Field, Parameter, Type,
Guides autowiring to be performed by
with @Autowired.
Annotation Type
means other than by type.
@Autowired
@Required
Method (setters)
Specifies that a particular property
@Qualifier(“mapToTortuga”)
must be injected or else the
configuration will fail.
private TreasureMap treasureMap;
@Scope
Type
Specifies the scope of a bean, either
singleton, prototype, request, session,
or some custom scope.
Get More Refcardz
(They’re free!)
Autowiring Bean Properties
A typical Spring bean might have its properties wired something
n Authoritative content
like this:
n Designed for developers
<bean id=”pirate” class=”Pirate”>
n Written by top experts
<constructor-arg value=”Long John Silver” />
n
<property name=”treasureMap” ref=”treasureMap” />
Latest tools & technologies
n
</bean>
Hot tips & examples
n
But it’s also possible to have Spring automatically inject a bean’s
Bonus content online
properties from other beans in the context. For example, if the
n New issue every 1-2 weeks
Annotations
Pirate class were annotated with @Autowired like this…
public class Pirate {
Subscribe Now for FREE!
private String name;
private TreasureMap treasureMap;
Refcardz.com
public Pirate(String name) { this.name = name; }
S
pring
DZone, Inc. | www.dzone.com
2
Spring Annotations
tech facts at your fingertips
Ensuring That Required Properties are Set
To ensure that a property is injected with a value, use the
Specifying Scope For Auto-Configured Beans
Hot
@Required annotation:
Tip
By default, all beans in Spring, including auto-con-
@Required
figured beans, are scoped as singleton. But you
public void setTreasureMap(TreasureMap treasureMap) {
can specify the scope using the @Scope annota-
this.treasureMap = treasureMap;
tion. For example:
}
@Component
In this case, the “treasureMap” property must be injected or
@Scope(“prototype”)
else Spring will throw a BeanInitializationException and context
public class Pirate { ... }
creation will fail.
This specifies that the pirate bean be scoped as a
Stereotyping Annotations
prototype bean.
These annotations are used to stereotype classes with
regard to the application tier that they belong to. Classes
Creating Custom Stereotypes
that are annotated with one of these annotations will
Autoregistering beans is a great way to cut back on the amount
automatically be registered in the Spring application context if
of XML required to configure Spring. But it may bother you that
<context:component-scan> is in the Spring XML configuration.
your autoregistered classes are annotated with Spring-specific
In addition, if a PersistenceExceptionTranslationPostProcessor is
annotations. If you’re looking for a more non-intrusive way to
configured in Spring, any bean annotated with @Repository will
autoregister beans, you have two options:
have SQLExceptions thrown from its methods translated into one
1. Create your own custom stereotype annotation. Doing so is as
of Spring’s unchecked DataAccessExceptions.
simple as creating a custom annotation that is itself annotated
with @Component:
Annotation
Use
Description
@Component
@Component
Type
Generic stereotype annotation for any Spring-managed
public @interface MyComponent {
component.
String value() default “”;
@Controller
Type
Stereotypes a component as a Spring MVC controller.
}
@Repository
Type
Stereotypes a component as a repository. Also
indicates that SQLExceptions thrown from the
2. Or add a filter to <context:component-scan> to scan for
component’s methods should be translated into Spring
annotations that it normally would not:
DataAccessExceptions.
<context:component-scan
@Service
Type
Stereotypes a component as a service.
base-package=”com.habuma.pirates”>
Automatically Configuring Beans
<context:include-filter type=”annotation”
expression=”com.habuma.MyComponent” />
In the previous section, you saw how to automatically wire a
<context:exclude-filter type=”annotation”
bean’s properties using the @Autowired annotation. But it is
expression=
possible to take autowiring to a new level by automatically
"org.springframework.stereotype.Component" />
registering beans in Spring. To get started with automatic
</context:component-scan>
registration of beans, first annotate the bean with one of the
In this case, the @MyComponent custom annotation has been
stereotype annotations, such as @Component:
added to the list of annotations that are scanned for, but
@Component
@Component has been excluded (that is, @Component-
public class Pirate {
annotated classes will no longer be autoregistered).
private String name;
Regardless of which option you choose, you should be able to
private TreasureMap treasureMap;
autoregister beans by annotating their classes with the custom
public Pirate(String name) { this.name = name; }
annotation:
@Autowired
@MyComponent
public void setTreasureMap(TreasureMap treasureMap) {
public class Pirate { …}
this.treasureMap = treasureMap;
}
Spring MVC Annotations
}
These annotations were introduced in Spring 2.5 to make it easier
Then add <context:component-scan> to your Spring XML
to create Spring MVC applications with minimal XML configuration
configuration:
and without extending one of the many implementations of the
Controller interface.
<context:component-scan
base-package=”com.habuma.pirates” />
Annotation
Use
Description
@Controller
Type
Stereotypes a component as a Spring
The base-package annotation tells Spring to scan com.habuma.
MVC controller.
pirates and all of its subpackages for beans to automatically
@InitBinder
Method
Annotates a method that customizes
register.
data binding.
@ModelAttribute
Parameter,
When applied to a method, used
You can specify a name for the bean by passing it as the value of
Method
to preload the model with the value
@Component.
returned from the method. When applied
to a parameter, binds a model attribute
@Component(“jackSparrow”)
to the parameter.
public class Pirate { … }
table continues on next page
DZone, Inc. | www.dzone.com
3
Spring Annotations
tech facts at your fingertips
Spring MVC Annotations, continued
Creating a Form-Handling Controller, continued
@Controller
Annotation
Use
Description
@RequestMapping("/addPirate.htm")
@RequestMapping
Method, Type
Maps a URL pattern and/or HTTP method
public class AddPirateFormController {
to a method or controller type.
@RequestParam
Parameter
Binds a request parameter to a method
@RequestMapping(method = RequestMethod.GET)
parameter.
public String setupForm(ModelMap model) {
return "addPirate";
@SessionAttributes
Type
Specifies that a model attribute should be
stored in the session.
}
@ModelAttribute("pirate")
Setting up Spring for Annotated Controllers
public Pirate setupPirate() {
Before we can use annotations on Spring MVC controllers, we’ll
Pirate pirate = new Pirate();
need to add a few lines of XML to tell Spring that our controllers
return pirate;
}
will be annotation-driven. First, so that we won’t have to register
@RequestMapping(method = RequestMethod.POST)
each of our controllers individually as <bean>s, we’ll need a
protected String addPirate(@ModelAttribute("pirate")
<context:component-scan>:
Pirate pirate) {
<context:component-scan
pirateService.addPirate(pirate);
base-package="com.habuma.pirates.mvc"/>
return "pirateAdded";
}
In addition to autoregistering @Component-annotated beans,
@Autowired
<context:component-scan> also autoregisters beans that are
PirateService pirateService;
annotated with @Controller. We’ll see a few examples of
}
@Controller-annotated classes in a moment.
Here the @RequestMapping annotation is applied to two different
But first, we’ll also need to tell Spring to honor the other Spring MVC
methods. The setupForm() method is annotated to handle HTTP
annotations. For that we’ll need <context:annotation-config> :
GET requests while the addPirate() method will handle HTTP POST
<context:annotation-config/>
requests. Meanwhile, the @ModelAttribute is also pulling double
duty by populating the model with a new instance of Pirate before
Use a conventions-based view resolver.
the form is displayed and then pulling the Pirate from the model
Hot
so that it can be given to addPirate() for processing.
Tip
If you use a conventions-based view resolver, such
as Spring's UrlBasedViewResolver or InternalRe-
Transaction Annotations
sourceViewResolver, along with <context:component-scan>
The @Transactional annotation is used along with the
and <context:annotation-config>, you can grow your applica-
<tx:annotation-driven> element to declare transactional
tion indefinitely without ever touching the Spring XML again.
boundaries and rules as class and method metadata in Java.
Annotation
Use
Description
Creating a Simple MVC Controller
@Transactional
Method, Type
Declares transactional boundaries and
rules on a bean and/or its methods.
The following HomePage class is annotated to function as a
Spring MVC controller:
Annotating Transactional Boundaries
@Controller
To use Spring’s support for annotation-declared transactions,
@RequestMapping("/home.htm")
public class HomePage {
you’ll first need to add a small amount of XML to the Spring
@RequestMapping(method = RequestMethod.GET)
configuration:
public String showHomePage(Map model) {
<?xml version=”1.0” encoding=”UTF-8”?>
List<Pirate> pirates = pirateService.
<beans xmlns=”http://www.springframework.org/schema/
getPirateList();
beans”
model.add(“pirateList”, pirates);
xmlns:tx=”http://www.springframework.org/schema/tx”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
return "home";
xsi:schemaLocation=”http://www.springframework.org/
}
schema/beans
@Autowired
http://www.springframework.org/schema/beans/
PirateService pirateService;
springbeans-2.5.xsd
}
http://www.springframework.org/schema/tx
There are several important things to point out here. First, the
http://www.springframework.org/schema/tx/spring-tx-
2.5.xsd”>
HomePage class is annotated with @Controller so that it will be
<tx:annotation-driven />
autoregistered as a bean by <context:component-scan>. It is also
…
annotated with @RequestMapping, indicating that this controller
</beans>
will respond to requests for “/home.htm”.
The <tx:annotation-driven> element tel s Spring to keep an eye
Within the class, the showHomePage() method is also annotated
out for beans that are annotated with @Transactional. In addition,
with @RequestMapping. In this case, @RequestMapping indicates
you’l also need a platform transaction manager bean declared in
that HTTP GET requests to “/home.htm” will be handled by the
the Spring context. For example, if your application uses Hibernate,
showHomePage() method.
you’ll want to include the HibernateTransactionManager:
Creating a Form-Handling Controller
<bean id=”transactionManager”
In a pre-2.5 Spring MVC application, form-processing control ers
class=”org.springframework.orm.hibernate3.
would typically extend SimpleFormController (or some similar
HibernateTransactionManager”>
<property name=”sessionFactory” ref=”sessionFactory”
base class). But with Spring 2.5, a form-processing controller just
/>
has a method that is annotated to handle the HTTP POST request:
</bean>
DZone, Inc. | www.dzone.com
4
Spring Annotations
tech facts at your fingertips
Annotating Transactional Boundaries, continued
Aspect J Annotations, continued
With the basic plumbing in place, you’re ready to start annotating
Annotation
Use
Description
the transactional boundaries:
@AfterReturning
Method
Declares a method to be called after a
@Transactional(propagation=Propagation.SUPPORTS,
pointcut returns successfully.
readOnly=true)
@AfterThrowing
Method
Declares a method to be called after a
public class TreasureRepositoryImpl implements
pointcut throws an exception.
TreasureRepository {
@Around
Method
Declares a method that will wrap the
…
pointcut.
@Transactional(propagation=Propagation.REQUIRED,
@Before
Method
Declares a method to be called before
readOnly=false)
proceeding to the pointcut.
public void storeTreasure(Treasure treasure) { …}
…
@DeclareParents
Static Field
Declares that matching types should be
given new parents—that is, it introduces new
}
functionality into matching types.
At the class level, @Transactional is declaring that all methods
@Pointcut
Method
Declares an empty method as a pointcut
should support transactions and be read-only. But, at the
placeholder method.
method-level, @Transactional declares that the storeTreasure()
What’s important to note, however, is that while you can use
method requires a transaction and is not read-only.
AspectJ annotations to define Spring aspects, those aspects will
Note that for transactions to be applied to @Transactional-
be defined in the context of Spring AOP and will not be handled
annotated classes, those classes must be wired as beans in Spring.
by the AspectJ runtime. This is significant because Spring AOP
JMX Annotations
is limited to proxying method invocations and does not provide
for the more exotic pointcuts (constructor interception, field
These annotations, used with the <context:mbean-export>
interception, etc.) offered by AspectJ.
element, declare bean methods and properties as MBean
operations and attributes.
Annotating Aspects
Annotations
Use
Description
To use AspectJ annotations to create Spring aspects, you’ll first
@ManagedAttribute
Method
Used on a setter or getter method
need to provide a bit of Spring XML plumbing:
to indicate that the bean’s property
should be exposed as a MBean
<beans xmlns="http://www.springframework.org/schema/
attribute.
beans"
@ManagedNotification
Type
Indicates a JMX notification emitted
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
by a bean.
xmlns:aop="http://www.springframework.org/schema/aop"
@ManagedNotifications
Type
Indicates the JMX notifications
xsi:schemaLocation="http://www.springframework.org/
emitted by a bean.
schema/beans
@ManagedOperation
Method
Specifies that a method should be
http://www.springframework.org/schema/beans/
exposed as a MBean operation.
spring-beans-2.5.xsd
@ManagedOperationParameter
Method
Used to provide a description for an
http://www.springframework.org/schema/aop
operation parameter.
http://www.springframework.org/schema/aop/spring-
@ManagedOperationParameters
Method
Provides descriptions for one or
aop-2.5.xsd">
more operation parameters.
…
@ManagedResource
Type
Specifies that all instances of a class
<aop:aspectj-autoproxy/>
should be exposed a MBeans.
…
Exposing a Spring Bean as a MBean
</beans>
To get started with Spring-annotated MBeans, you’ll need to
The <aop:aspectj-autoproxy> element tells Spring to watch for
include <context:mbean-export> in the Spring XML configuration:
beans annotated with AspectJ annotations and, if it finds any, to
<context:mbean-export/>
use them to create aspects. Then you can annotate bean classes
Then, you can annotate any of your Spring-managed beans to be
to be aspects:
exported as MBeans:
@Aspect
public class ChantySinger {
@ManagedResource(objectName="pirates:name=PirateService")
@Pointcut(“execution(* Pirate.plunder(..))”)
public interface PirateService {
public void plunderPC() {}
@ManagedOperation(
description="Get the pirate list")
@Before(“plunderPC()”)
public List<Pirate> getPirateList();
public void singYoHo() {
}
…
Here, the PirateService has been annotated to be exported as a
}
MBean and its getPirateList() method is a managed operation.
@AfterReturning(“plunderPC()”)
public void singAPiratesLifeForMe() {
ASpECTj ANNOTATIONS
…
}
}
For defining aspects, Spring leverages the set of annotations
provided by AspectJ.
This simple annotation-based aspect has a pointcut that is
triggered by the execution of a plunder() method on the Pirate
Annotation
Use
Description
@Aspect
Type
Declares a class to be an aspect.
class. Before the Pirate.plunder() method is executed, the
@After
Method
Declares a method to be called after a
singYoHo() method is called. Then, after the Pirate.plunder()
pointcut completes.
method returns successfully, the singAPiratesLifeForMe()
DZone, Inc. | www.dzone.com
5
Spring Annotations
tech facts at your fingertips
Annotating Aspects, continued
TESTINg ANNOTATIONS
method is invoked. (For more advanced examples of AspectJ
annotations, see the AspectJ documentation at http://www.
These annotations are useful for creating unit tests in the JUnit 4
eclipse.org/aspectj/docs.php.)
style that depend on Spring beans and/or require a transactional
Note the rather odd looking plunderPC() method. It is annotated
context.
with @Pointcut to indicate that this method is a pointcut
Annotation
Use
Description
placeholder. The key thing here is that the most interesting stuff
@AfterTransaction
Method
Used to identify a method to be
happens in the annotation itself and not in the method. In fact,
invoked after a transaction has
completed.
pointcut placeholder methods must be empty methods and
@BeforeTransaction
Method
Used to identify a method to be
return void.
invoked before a transaction starts.
@ContextConfiguration
Type
Configures a Spring application
context for a test.
jSr-250 ANNOTATIONS
@DirtiesContext
Method
Indicates that a method dirties the
Spring container and thus it must
In addition to Spring’s own set of annotations, Spring also
be rebuilt after the test completes.
supports a few of the annotations defined by JSR-250, which is
@ExpectedException
Method
Indicates that the test method
is expected to throw a specific
the basis for the annotations used in EJB 3.
exception. The test will fail if the
exception is not thrown.
Annotation
Use
Description
@IfProfileValue
Type,
Indicates that the test class or
Method
method is enabled for a specific
@PostConstruct
Method
Indicates a method to be invoked after a
profile configuration.
bean has been created and dependency
injection is complete. Used to perform any
@NotTransactional
Method
Indicates that a test method must
initialization work necessary.
not execute in a transactional
context.
@PreDestroy
Method
Indicates a method to be invoked just
@ProfileValueSourceConfiguration
Type
Identifies an implementation of a
before a bean is removed from the Spring
profile value source. The absence
context. Used to perform any cleanup work
of this annotation will cause profile
necessary.
values to be loaded from system
@Resource
Method, Field
Indicates that a method or field should be
properties.
injected with a named resource (by default,
@Repeat
Method
Indicates that the test method must
another bean).
be repeated a specific number of
times.
Wiring Bean Properties with @Resource
@Rollback
Method
Specifies whether or not the
transaction for the annotated
Using @Resource, you can wire a bean property by name:
method should be rolled back
public class Pirate {
or not.
@Resource
@TestExecutionListeners
Type
Identifies zero or more test
execution listeners for a test class.
private TreasureMap treasureMap;
@Timed
Method
Specifies a time limit for the test
}
method. If the test does not
In this case, Spring will attempt to wire the “treasureMap”
complete before the time has
expired, the test will fail.
property with a reference to a bean whose ID is “treasureMap”.
@TransactionConfiguration
Type
Configures test classes for
If you’d rather explicitly choose another bean to wire into the
transactions, specifying the
property, specify it to the name attribute:
transaction manager and/or the
default rollback rule for all test
public class Pirate {
methods in a test class.
@Resource(name=”mapToSkullIsland”)
private TreasureMap treasureMap;
Writing a Spring-Aware Test
}
The key to writing a Spring-aware test is to annotate the test class
Initialization and Destruction Methods
with @RunWith, specifying SpringJUnit4ClassRunner as the class
runner behind the test:
Using JSR-250’s @PostConstruct and @PreDestroy methods,
you can declare methods that hook into a bean’s lifecycle. For
@RunWith(SpringJUnit4ClassRunner.class)
example, consider the following methods added to the Pirate
public class PirateTest {
…
class:
}
public class Pirate {
…
In this case, the Spring test runner will try to load a Spring
@PostConstruct
application context from a file named PirateTest-context.xml. If
public void wakeUp() {
you’d rather specify one or more XML files to load the application
System.out.println(“Yo ho!”);
}
context from, you can do that with @ContextConfiguration:
@PreDestroy
@RunWith(SpringJUnit4ClassRunner.class)
public void goAway() {
@ContextConfiguration(locations = { "pirates.xml" })
System.out.println(“Yar!”);
public class PirateTest {
}
…
}
}
As annotated, the wakeUp() method will be invoked just after
With test configured to load a Spring application context, you
Spring instantiates the bean and goAway() will be invoked just
now may request that Spring autowire properties of the test class
before the bean is removed from the Spring container.
with beans from the Spring context:
DZone, Inc. | www.dzone.com
6
Spring Annotations
tech facts at your fingertips
Writing a Spring-Aware Test, continued
Accessing the Spring Context in a Test
@RunWith(SpringJUnit4ClassRunner.class)
If you need the Spring application context itself in a test, you can
@ContextConfiguration(locations = { "pirates.xml" })
autowire it into the test the same as if it were a bean in the context:
public class PirateTest {
@RunWith(SpringJUnit4ClassRunner.class)
@Autowired
@ContextConfiguration(locations = { "pirates.xml" })
private Pirate pirate;
public class PirateTest {
@Autowired
@Autowired
private TreasureMap treasureMap;
private Pirate pirate;
@Test
@Autowired
public void annotatedPropertyShouldBeAutowired() {
private ApplicationContext applicationContext;
assertNotNull(pirate.getTreasureMap());
@Test
assertEquals(treasureMap, pirate.getTreasureMap());
public void annotatedPropertyShouldBeAutowired() {
}
assertNotNull(pirate.getTreasureMap());
}
assertEquals(applicationContext.
getBean("treasureMap"), pirate
In this case, the pirate and treasureMap properties will be wired
.getTreasureMap());
with the beans whose ID are “pirate” and “treasureMap”,
}
respectively.
}
A B O U T T H E A U T H O r
r E C O M M E N D E D B O O K
Spring in Action, 2nd Edition is
Craig Walls
Craig Walls is a Texas-based software developer with more than 13 years experi-
a practical and comprehensive
ence working in the telecommunication, financial, retail, educational, and software
guide to the Spring Frame-
industries. He’s a zealous promoter of the Spring Framework, speaking frequently
work, the framework that for-
at local user groups and conferences and writing about Spring on his blog. When
ever changed enterprise Java
he’s not slinging code, Craig spends as much time as he can with his wife, two
development. What’s more, it’s
daughters, six birds, three dogs, and an ever-fluctuating number of tropical fish.
also the first book to cover the
Publications
Projects
new features and capabilities in
n Spring in Action, 2nd Edition, 2007
n Committer to XDoclet project;
Spring 2.
Originator of Portlet and Spring modules for XDoclet
n XDoclet in Action, 2003
Blog
BUY NOW
n http://www.springinaction.com
books.dzone.com/books/spring-in-action
Want More? Download Now. Subscribe at refcardz.com
Upcoming Refcardz:
Available:
n
Core CSS: Part II
Published September 2008
Published June 2008
n
n
Getting Started with JPA
jQuerySelectors
n
Core CSS: Part III
n
Core CSS: Part I
n
Flexible Rails: Flex 3 on Rails 2
n
SOA Patterns
n
Struts 2
Published May 2008
FrEE
n
Scalability and High
Published August 2008
n
Windows PowerShell
n
Very First Steps in Flex
n
Agile Methodologies
n
Dependency Injection in EJB 3
n
C#
n
Getting Started with PHP
n
Groovy
n
Visit http://refcardz.dzone.com
Core .NET
n
Core Java
for a complete listing of
Published July 2008
n
JUnit
n
available Refcardz.
NetBeans IDE 6.1 Java Editor
n
MySQL
n
RSS and Atom
n
Design Patterns
GlassFish Application Server
n
Seam
Published June 2008
n
Silverlight 2
n
IntelliJ IDEA
DZone, Inc.
ISBN-13: 978-1-934238-29-5
1251 NW Maynard
ISBN-10: 1-934238-29-5
Cary, NC 27513
5 0 7 9 5
888.678.0399
DZone communities deliver over 3.5 million pages per month to
919.678.0300
more than 1.5 million software developers, architects and designers.
Refcardz Feedback Welcome
DZone offers something for every developer, including news,
refcardz@dzone.com
tutorials, blogs, cheatsheets, feature articles, source code and more.
Sponsorship Opportunities
9 781934 238295
$7.95
“DZone is a developer’s dream,” says PC Magazine.
sales@dzone.com
Copyright © 2008 DZone, Inc. All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by means electronic, mechanical,
Version 1.0
photocopying, or otherwise, without prior written permission of the publisher. Reference: Spring in Action, 2nd Edition, Craig Walls, Manning Publications, 2007.