附录
一、英语原文
Spring Framework Fundamentals
The Spring Framework evolved from the code written for Expert One-on-One J2EE
Design and Development by Rod Johnson (Wrox, 2002). The framework combines best
practices for Java Enterprise Edition (JEE) development
from the industry and
integration with the best-of-breed third-party frameworks.
It also provides easy
extension points to write your own integration if you need one that doesn’t yet exist.
The framework was designed with developer productivity in mind, and it makes it
easier to work with the existing, sometimes cumbersome Java and JEE APIs.
Before we start our journey into Spring MVC and Spring Web Flow, we will
provide a quick refresher
course on Spring Core (formerly known as the Spring Framework). Spring is now a
longtime de-facto
standard for Java enterprise software development. It introduced many of us to concepts
such as dependency injection, aspect-oriented programming (AOP), and programming
with plain-old-Java-objects (POJOs).
In this chapter, we will cover dependency injection and AOP. Specifically, we will
cover how the Spring Framework helps us implement dependency injection and how to
use programming to our advantage. To be able to do the things mentioned here, we will
explore the Inversion of Control (IoC) container; the application context.
We will only touch on the necessary basics of the Spring Framework here. If you
want more in-depth information about it, we suggest the excellent Spring Reference
guide (www.springsource.org) or books such as Pro Spring 3 (Apress, 2012) or Spring
Recipes, 2nd Edition (Apress, 2011).
Let’s begin by taking a quick look at the Spring Framework and the modules that
comprise it.
Spring Framework
In the introduction, we mentioned that the Spring Framework evolved from code written
for the book Expert One-on-One J2EE Design and Development by Rod Johnson. This
book was written to explain some of the complexities in JEE and how to overcome them.
And while many of the complexities and problems in JEE have been solved in the
附录
newer JEE specifications (especially since JEE 6), the Spring Framework remains very
popular.
It remains popular due to its simple (not simplistic!) approach to building
applications. It also offers a consistent programming model for different kinds of
technologies, be they for data access or messaging infrastructure. The framework allows
developers to target discrete problems and build solutions specifically for them.
The framework consists of several modules (see Figure 2-1) that work together and
build on each other. We can pretty much cherry pick the modules we want to use.
Figure 2-1. Overview of the Spring Framework
All of the modules from Figure 2-1 are represented as jar files that we can include
on the classpath if we need a specific technology. In Table 2-1, we list all the modules
coming with Spring 3.1 and give a brief description of the content of each module, as
well as any artifact names that might be used for dependency management. The name of
the actual
jar file might differ, depending on how one obtains the module. The
downloadable distribution contains jars in this form: org.springframework.[module-
name]-[version].jar. Jars that come from the maven repositories use this form:
spring-[artifact].jar. See table 2-1.
附录
Table 2-1. The Spring Framework Module Overview
Most of the modules have a dependency on some other module in the Spring
Framework. The core module is an exception to this rule. Figure 2-2 gives an overview
of the commonly used modules and their dependencies on other modules. Notice that
附录
the instrumentation, aspect, and test modules are missing from the figure; this is because
their dependencies depend on the project and what other modules are used. The Spring
Framework has only one required dependency: commons-logging, a logging abstraction
framework. The other dependencies differ based on the needs of the project.
Dependency Injection
The concept of dependency injection (DI), objects are given their dependencies at
construction time, is one of the foundations of the Spring Framework. You have also
probably heard of Inversion of Control (IoC). IoC is a broader, more general concept
that can be addressed in different ways. IoC lets developers decouple and focus on what
is important for a given part of an enterprise application, but without having to think
about what other parts of the system do. Programming to interfaces is one way to think
about decoupling.
Almost every enterprise application consists of multiple components that need to
work together. In the early days of Java enterprise development, we simply put all the
logic of constructing those objects (and the objects those objects needed) in the
constructor (see Listing 2-1). At first sight, there is nothing wrong with that approach;
however, as time progressed, object construction became slow, and objects had a lot of
knowledge they shouldn ’t have had (see the Single Responsibility Principle). Those
附录
classes became hard to maintain, and they were also quite hard to unit and/or integration
test.
The class from Listing 2-1 programs to interfaces, but it still needs to know about
the concrete implementation of an interface simply to do object construction. Applying
IoC by decoupling the construction logic (collaborating objects) makes the application
easier to maintain and increases testability. There are seven ways to decouple this
dependency construction logic:
1. Factory pattern
2. Service locator pattern
3. Dependency injection
a. Constructor based
b. Setter based
c. Interface based
附录
d. Annotation driven
4. Contextualized lookup
When using the factory pattern, service locator pattern, or contextualized lookup,
the class that needs the dependencies still has some knowledge about how to obtain the
dependencies. This can make things easier to maintain, but it can still be hard to test.
Listing 2-2 shows a contextualized lookup from JNDI (Java Naming and Directory
Interface). The constructor code would need to know how to do the lookup and handle
exceptions.
The immediately preceding code isn’t particularly clean; for example, imagine if
there were multiple dependencies from different contexts. The code would quickly
become messy and increasingly hard, if not impossible, to unit test (see Chapter 9 for
more information on testing).
To solve the problem of the construction/lookup logic in the constructor of an
object, we can use dependency injection. We simply pass the object the dependencies it
needs to do its work. This makes our code clean, decoupled, and easy to test (see Listing
2-3). Dependency injection is a process where objects specify the dependencies they
work with. The IoC container uses that specification; when it constructs an object, it
also injects its dependencies. This way our code is cleaner, and we no longer burden our
class with construction logic. It is easier to maintain and also easier to unit and/or
附录
integration test. Testing is easier because we could inject a stub or mock object to verify
the behavior of our object.
It
has
a
as
constructor
As the name implies, constructor-based dependency injection uses the constructor
to inject the dependencies in the object. Listing 2-3 uses constructor-based dependency
injection.
arguments:
objects
and
com.apress.prospringmvc.moneytransfer.repository.AccountRepository
com.apress.prospringmvc.moneytransfer.repository.TransactionRepository.When
we
instance
construct
of
com.apress.prospringmvc.moneytransfer.constructor
.MoneyTransferServiceImpl, we
need to hand it the needed dependencies.
two
that
takes
an
Setter-based dependency injection uses a setter method to inject the dependency.
The JavaBeans specification defines both setter and getter methods. If we have a
method named setAccountService,
then we set a property with the name,
accountService. The property name is created using the name ofthe method, minus the
“set ” and with the first letter lowercased (the full specification can be found inthe
JavaBeans specification). Listing 2-4 shows an example of setter-based dependency
injection.
附录
Finally, there is annotation-based dependency injection (see Listing 2-5). For this
to work, we do not need to specify a constructor argument or a setter method to set the
dependencies. We begin by defining a class-level field that can hold the dependency.
Next, we put an annotation on that field to express our intent to have that dependency
injected into our object. Spring accepts several different annotations: @Autowired,
@Resource, and @Inject. All these annotations more or less work in the same way. It
isn’t within the scope of this book to explain the differences among these annotations in
depth, so we suggest the Spring Reference Guide or Pro Spring 3 (Apress, 2012) if you
want to learn more. The main difference among them is that the @Autowired annotation
is from the Spring Framework, whereas @Resource and @Inject are Java standard
annotations.