Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (5.49 MB, 753 trang )
9799ch01.qxd
18
4/17/08
9:35 AM
Page 18
CHAPTER 1 ■ INVERSION OF CONTROL AND CONTAINERS
To change the preceding programming configuration to properties-based configuration,
you create the components.properties file with the following content:
# Define a new component "reportGenerator"
reportGenerator=com.apress.springrecipes.report.PdfReportGenerator
# Define a new component "reportService"
reportService=com.apress.springrecipes.report.ReportService
# Inject the component "reportGenerator" into property "reportGenerator"
reportService.reportGenerator=reportGenerator
Then your container has to read this configuration file and interpret its contents as component and dependency definitions. It also has to create component instances and inject
dependencies as specified in the configuration file.
When implementing the container, you will have to manipulate component properties
via reflection. To simplify matters, you can take advantage of a third-party library called Commons BeanUtils. This is part of the Apache Commons (http://commons.apache.org/) project
that provides a set of tools for manipulating the properties of a class. The BeanUtils library
requires another library from the same project, called Commons Logging.
■Note You can download Commons BeanUtils and Commons Logging from the Apache Commons web
site. Then include the downloaded JAR files commons-beanutils.jar and commons-logging.jar in your
classpath.
Now you are ready to reimplement Container with this new idea. The first step is to load
the properties file into a java.util.Properties object to get a list of properties. Then iterate
over each property entry, which is made up of a key and a value. As mentioned before, there
are two possible kinds of configuration:
• If there’s no dot in the entry key, it is a new component definition. For this kind of configuration, you instantiate the specified class via reflection and then put the component
into the map.
• Otherwise, the entry must be a dependency injection. You split its key into two parts,
before and after the dot. The first part of the key is the component name and the second part is the property to set. With the help of the PropertyUtils class provided by
Commons BeanUtils, you can refer that property to another component by the name
specified in the entry value.
package com.apress.springrecipes.report;
...
import org.apache.commons.beanutils.PropertyUtils;
public class Container {
private Map
9799ch01.qxd
4/17/08
9:35 AM
Page 19
CHAPTER 1 ■ INVERSION OF CONTROL AND CONTAINERS
public Container() {
components = new HashMap
try {
Properties properties = new Properties();
properties.load(new FileInputStream("components.properties"));
for (Map.Entry entry : properties.entrySet()) {
String key = (String) entry.getKey();
String value = (String) entry.getValue();
processEntry(key, value);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private void processEntry(String key, String value) throws Exception {
String[] parts = key.split("\\.");
if (parts.length == 1) {
// New component definition
Object component = Class.forName(value).newInstance();
components.put(parts[0], component);
} else {
// Dependency injection
Object component = components.get(parts[0]);
Object reference = components.get(value);
PropertyUtils.setProperty(component, parts[1], reference);
}
}
public Object getComponent(String id) {
return components.get(id);
}
}
Note that in the processEntry() method, you have to split the entry key with a dot. In regular expressions, a single dot matches any character, so you have to quote it with a slash.
Again, a slash has to be quoted in a Java string, which results in two slashes.
With these enhancements, your container has become highly reusable, as it reads a textbased configuration file for component definition. Now not even a single line of Java code has
to be modified when you change your component definition. Although this container is not
powerful enough for production use, it has fulfilled its purpose by demonstrating the core
principle and mechanism of an IoC container.
19
9799ch01.qxd
20
4/17/08
9:35 AM
Page 20
CHAPTER 1 ■ INVERSION OF CONTROL AND CONTAINERS
1-6. Summary
In this chapter, you have learned to use a container to manage your components. This can
help reduce coupling between different components. A component can look up other
dependent components through the container. However, direct lookup will bind your components to the container with complex code. You can write a service locator to encapsulate the
lookup logic and delegate the lookup requests to it.
Active lookup is a direct and sensible approach for resource retrieval. However, it requires
your components to know about resource retrieval. When using the IoC principle, your component has only to choose a way of accepting resources and the container will deliver
resources to your components. DI is a concrete design pattern that conforms to the principle
of IoC. There are three main types of DI: setter injection, constructor injection, and interface
injection.
You can configure your container using Java code or a text-based configuration file. The
latter is more flexible because there’s no need to recompile your source code each time you
change it.
You have written a simple IoC container to read a properties file. This container is conceptually similar to the Spring IoC container.
In the next chapter, you will get an overview of the Spring framework’s architecture and
how to set it up.
9799ch02.qxd
5/5/08
4:42 PM
CHAPTER
Page 21
2
Introduction to Spring
I
n this chapter, you will have an overview of the Spring framework. Spring’s architecture is
divided into multiple modules in a hierarchical fashion. You will learn about the major functions of each module and see a summary of the highlights of Spring 2.0 and 2.5. Spring is not
just an application framework but also a platform that hosts several related projects, which
are called the Spring Portfolio projects. This chapter will give you an outline of their features.
Before you start with Spring, you have to install it on your local development machine.
The Spring framework’s installation is very simple. However, to get the most out of Spring, you
have to understand the structure of its installation directory and what’s contained in each
subdirectory.
The Spring development team has created an Eclipse plug-in called Spring IDE to make
developing Spring applications easier. You will learn about how to install this IDE and use its
bean-supporting features.
Upon finishing this chapter, you will have a solid understanding of Spring’s overall architecture and major features. You will also be able to install the Spring framework and Spring
IDE on your machine.
2-1. Introducing the Spring Framework
The Spring framework (http://www.springframework.org/) is a comprehensive Java/Java EE
application framework hosted by SpringSource (http://www.springsource.com/), which was
formerly known as Interface21. Spring addresses many aspects of Java/Java EE application
development, and it can help you to build high-quality, high-performance applications more
quickly.
The heart of the Spring framework is a lightweight IoC container that is able to add enterprise services to simple Java objects declaratively. Spring makes extensive use of an excellent
programming methodology—AOP (aspect-oriented programming)—to provide these services
to its components. Within the Spring IoC container’s scope, components are also called beans.
The Spring framework itself incorporates many design patterns, including the GoF (Gang
of Four) object-oriented patterns and Sun’s core Java EE patterns. By using the Spring framework, you will be lead to use industry best practices to design and implement your
applications.
Spring is not designed to compete with existing technologies in particular areas. On the
contrary, it integrates with many leading technologies to make them easier to use. That makes
Spring an appropriate solution in many usage scenarios.
21
9799ch02.qxd
22
5/5/08
4:42 PM
Page 22
CHAPTER 2 ■ INTRODUCTION TO SPRING
Introducing Spring’s Modules
The architecture of the Spring framework is divided into modules, as shown in Figure 2-1.
Spring’s module assembling is so flexible that your applications can build on top of their different subsets in different usage scenarios.
Figure 2-1. An overview of the Spring framework’s modules
In Figure 2-1, the modules are organized in hierarchical fashion, with the upper modules
depending on the lower ones. As you can see, the Core module lies at the very bottom since it’s
the foundation of the Spring framework.
Core: This module provides core functions of the Spring framework. It provides a basic
Spring IoC container implementation called BeanFactory. The basic IoC container features will be introduced in Chapter 3.
Context: This module builds on top of the Core module. It extends the Core module’s
functions and provides an advanced Spring IoC container implementation called
ApplicationContext, which adds features such as internationalization (I18N) support,
event-based communication, and resource loading. These advanced IoC container features will be covered in Chapter 4.
AOP: This module establishes an aspect-oriented programming framework, which is
referred to as Spring AOP. AOP is another of Spring’s fundamental concepts besides IoC.
Chapters 5 and 6 will cover both the classic and new Spring AOP approaches, and also
integrating AspectJ with Spring.