Software developers have always pursued code reuse -- and for obvious reasons. The means of this pursuit have changed over time, from functions in Fortran through object-oriented programming (OOP) and inheritance toward interfaces. At each step, we've found techniques better than the previous to let us decouple code from hard dependencies. One of the best ways to promote code reuse is to decouple interfaces from implementation. In the book Art of UNIX Programming, Eric Raymond makes this point in several of the UNIX® philosophies:
- Rule of Modularity: Write simple parts connected by clean interfaces.
- Rule of Separation: Separate policy from mechanism; separate interfaces from engines.
- Rule of Representation: Fold knowledge into data so that program logic can be stupid and robust.
While these ideas are old, we keep finding new ways to realize them in Java™ technology. The latest round of decoupling, dependency injection, reflects the ideals stated above. Like many new concepts implemented in different ways in different places, a lot of confusion has arisen between the concept and the implementation. In this two-part article series, I discuss the concepts of DI (also known as Inversion of Control, or IoC), then demonstrate how it's implemented in Apache Geronimo.
One aspect of DI frameworks that causes confusion is the terminology used to describe them. You hear both Inversion of Control and dependency injection used almost interchangeably. However, they don't mean the same thing.
IoC is a general term that encompasses most frameworks. Literally, it means inverting the controlling element to what is traditionally the element it controls (the controllee). In other words, what is typically the controlling part of the framework becomes the thing controlled. For example, in the Model-View-Controller (MVC) design pattern, the controller invokes methods. In event-driven environments, the view invokes code through event handlers. Thus, the view (that is, the controllee) is taking the role of the controller.
I find the term Inversion of Control too all-encompassing. It's like lumping Java 2 Platform, Enterprise Edition (J2EE) development into software development. Yes, J2EE is software development, but it's a highly specialized version of it.
Fortunately, Martin Fowler has come to the rescue and, in collaboration with several framework builders, named this style of decoupling dependency injection. This term is much better, because it specifically describes what developers are doing. Thus, throughout this article and the next, I refer to this style of coding as dependency injection. If you read other sources that use IoC, make sure you know what the author means.
Software components that rely on one another to perform work are said to be coupled together. Some level of coupling is inevitable in software development. However, you should try to keep coupling to a bare minimum. For example, when building library code, it's better to define types as interfaces rather than as concrete classes. In this way, you can change the concrete class later without changing the library code, which relies solely on the definition you created in the interface. DI provides yet another way to eliminate high coupling between components, because the container can inject a component at run time into a component that relies on it. Consider the example shown in Figure 1.
Figure 1. Simple, naive customer persistence framework
In this example, the Customer Workflow class is hopelessly
coupled to the Customer Persistence class, which in turn is tied to
a database. The technical term for this architecture is yikes! Fortunately, developers in
the Java world avoid this type of high coupling. In fact, avoiding this style of coupling was one
of the motivating factors behind the creation of Enterprise JavaBeans (EJB) technology.
You can achieve some code separation if you represent the concrete
Customer Persistence class as an interface instead. Figure 2
shows an improved version of the same structure.
Figure 2. Using interfaces to decouple relationships
Forcing the dependencies on interfaces allows you to provide a variety of implementation
classes that implement the interface's contract. In this case, you could have one
Customer Persistence class that reads from an XML document and another that uses a relational database. The workflow class doesn't know (or care) which mechanism you use.
Fast-forward some logical conclusions later, and you arrive at code reuse by means of DI through interfaces, factories, and pooled (proxied) objects, otherwise known as EJB technology. Figure 3 shows the same relationship depicted in a typical EJB relationship.
Figure 3. EJB's version of decoupling with interfaces
Do you really need all that? EJB technology certainly provided a level of decoupling, but at what price? The authors of the EJB specification used the tools that were in vogue at the time: inheritance, interfaces, and design patterns. And they tried to solve every problem that a developer would face when writing an enterprise application by baking it into the framework. What you don't see in Figure 3 is object pooling, automatic transaction processing, security, and all the other good things that EJB technology provides. The only problem is that I didn't ask for those facilities -- the EJB framework just included them. Consequently, my simple decoupling problem is now a big problem.
You can see why there's a backlash against this style of decoupling. As Bruce Tate so eloquently stated in a blog entry, to create a simple application, "I don't want to have to eat the whole elephant." Prescriptive approaches that force you to implement elements that you don't need never work. They tend to drag a lot of complexity along with their benefit; sooner or later, the complexity outweighs the benefit you thought you were getting from the framework.
With the perspective of hindsight, EJB 2.0 is not the correct way to solve these problems. There must be a simpler way to decouple applications without adding needless bulk and complexity. The current thinking on how to do this lies with DI. In fact, EJB 3 takes this approach, as does Geronimo, which eschews all the heavyweight framework in favor of a cleaner technique.
Before looking at Geronimo and how it implements DI, take a look at a simpler container. The following examples use PicoContainer, an open source container developed by ThoughtWorks that performs DI and nothing else. This container shows how injection works in isolation, which leads to how Geronimo works and the second article in this series.
Constructor injection and PicoContainer
Two major schools of thought revolve around how to perform DI: constructor injection
and setter injection. Constructor injection uses a constructor to determine what type of
concrete object to return. Setter injection injects types through set()
methods.
In PicoContainer, you inject dependencies through the constructor. For example, Figure 2 shows
a Workflow class that needed to create customer
objects by means of a persistence mechanism. For this example, there are two different finder
classes: FinderFromFile, which uses an XML file for its searching,
and FinderFromDb, which uses a relational database. Even though
this example is small, it uses several files, which are summarized in Table 1.
| File | Type | Purpose |
|---|---|---|
CustomerLister | Class | Class that uses one of the finder types to locate customers by name |
FinderFromFile | Class | Implementation of a CustomerFinder interface, which looks
for customers in a text file |
CustomerFinder | Interface | Interface that defines the semantics of something that can find
Customer objects |
Customer | Class | The subject of this search; encapsulates customer information |
CustomerWorkflow | Class | Controller class for the application; initializes the container |
TestCustomerListing | Class | Unit test to exercise the customer finder |
Figure 4 illustrates the relationships between these classes.
Figure 4. Relationship between PicoContainer example classes
The following code listings show how DI works in PicoContainer.
The CustomerFinder interface makes DI possible. For DI to
work, you must have an interface whose concrete class you can inject into the consumer of
the behavior you desire. In this case, the CustomerFinder
interface defines the method find(String name), as shown
in Listing 1.
Listing 1. Interface defining how to find customers
public interface CustomerFinder {
Customer find(String name);
}
|
This interface defines the semantics of how you find customers without exposing the details of performing the actual search. (The details are different depending on whether you use an XML file or a database.)
The FinderFromFile concrete class implements the
FinderFromFile interface. This class, shown in Listing 2,
is responsible for finding a customer by name from within a flat file.
Listing 2. Class implementing
find(String name) for flat filespublic class FinderFromFile implements CustomerFinder {
private String fileName;
public FinderFromFile(String fileName) {
this.fileName = fileName;
}
public Customer find(String name) {
// . . . details omitted
}
}
|
Next, you define the class that is responsible for calling the finder class -- CustomerLister, shown in Listing 3. This is the class whose
dependency (that is, which implementation of the CustomerFinder
interface to use) is injected.
Listing 3. Class whose finder behavior the container injects
public class CustomerLister {
private CustomerFinder finder;
public CustomerLister(CustomerFinder finder) {
this.finder = finder;
}
public Customer findCustomerByName(String name) {
return finder.find(name);
}
}
|
In Listing 3, you can see that the CustomerLister constructor
accepts an instance of a class that implements the CustomerFinder
interface. The container injects this instance to this CustomerLister.
This behavior is referred to in the DI world as constructor injection, because the instance
is passed through one of the constructors.
The alternative (and more widely used) behavior is setter injection, where dependent
classes are injected through set() methods. PicoContainer supports
both types of injection, and the only real difference is whether you allow the construction of a class
with explicit dependencies when those dependent classes may not be available. The theory here is
that if you can't inject the dependency, you can't construct the dependent class. Theory
aside, functionally there is no difference between these two styles of injection.
Listing 4 shows what the CustomerFinder interface would look like
if setter injection were used instead.
Listing 4.
CustomerFinder with setter injectionpublic class CustomerLister {
private CustomerFinder finder;
public CustomerLister() {
}
public void setFinder(CustomerFinder finder) {
this.finder = finder;
}
}
|
The next class of interest is the CustomerWorkflow class, which
acts as the controller in this example. This class configures PicoContainer in its
configureContainer() method. This method in turn creates the
container (which acts as a singleton) and registers components and their parameters. The
CustomerWorkflow class is shown in Listing 5.
Listing 5. Controller for this example (CustomerWorkflow configures the container)
public class CustomerWorkflow {
public MutablePicoContainer configureContainer() {
MutablePicoContainer pico = new DefaultPicoContainer();
Parameter[] finderParams =
{new ConstantParameter("customerListing.xml")};
pico.registerComponentImplementation(CustomerFinder.class,
FinderFromFile.class, finderParams);
pico.registerComponentImplementation(CustomerLister.class);
return pico;
}
}
|
Notice that the configuration of PicoContainer allows you to specify parameters to the components you inject. (In Geronimo, these components are referred to as GBeans.) Note also that the configuration is done in Java code, not in an XML document (like the Spring container). If you prefer to work in XML, consider using NanoContainer, which is an open source container similar to PicoContainer. In either case, you have now set up your dependencies for injection. Now you need merely to call the code that needs those dependencies and allow the container to perform its work.
The last piece of the puzzle is the class that drives the process. This example uses a unit
test to verify that everything works as expected. The TestCustomerListing
class (shown in Listing 6) ties everything together.
Listing 6. Test class that demonstrates injection
public class TestCustomerListing extends TestCase {
private CustomerWorkflow workflow;
public void setup() {
workflow = new CustomerWorkflow();
}
public void teardown() {
workflow = null;
}
public void testCustomerFinder() {
MutablePicoContainer pico = workflow.configureContainer();
CustomerLister lister = (CustomerLister)
pico.getComponentInstance(CustomerLister.class);
Customer foundCustomer =
lister.findCustomerByName("Homer");
assertEquals("Homer", foundCustomer.getName());
}
}
|
The TestCustomerListing class creates an instance of the
Workflow class in the setup()
method, then invokes the configureContainer() method. The
class then uses PicoContainer to deliver the CustomerLister
class that has the correct dependency (in this case, the FinderFromFile
finder class) to the lister object, which in turn gets a reference to the named customer.
Despite the number of moving parts, this example demonstrates the decoupling power of DI. To create a completely new way to persist customers, you can still locate a customer just by extending the interface and adding configuration code to the container. In this way, you get a level of decoupling that you can't achieve using just OOP primitives built into the language.
One of the difficulties in understanding a topic like DI is the amount of coupling this topic has with other, unrelated topics. For example, studying Geronimo to learn about DI is difficult, because Geronimo contains a lot of moving parts that have nothing to do with DI. In this article, I decoupled the topic away from the implementation, choosing the smallest software stack available to investigate the characteristics of DI. I discussed the motivation and definition of DI and showed an example of how a container can inject dependencies from one component into another.
In Part 2 of this series, I step away from PicoContainer and move to Geronimo, demonstrating how the same principles at work in this simple example are applicable to something as complex as a J2EE application server. Geronimo gives you the same level of decoupling as PicoContainer but comes with a host of predefined service hooks to allow you to inject much more complex behaviors.
Learn
- Find out more about DI in this fantastic article by Martin Fowler,
"Inversion of Control Containers and the
Dependency Injection pattern."
- Read Bruce Tate's "Secrets of lightweight development success, Part 4: A comparison of lightweight containers" (developerWorks, August 2005) for more information about the various lightweight containers that are available.
- Visit the developerWorks Open source zone for extensive how-to information, tools, and project updates to help you develop with open source technologies and use them with IBM's products.
- Check out the developerWorks Apache Geronimo project area for articles, tutorials, and other resources to help you get started developing with Geronimo today.
- Check out the IBM Support for Apache Geronimo offering, which lets you develop Geronimo applications backed by world-class IBM support.
- Find helpful resources for beginners and experienced users at the Get started now with Apache Geronimo section of developerWorks.
- Browse all the Apache articles and free Apache tutorials available in the developerWorks Open source zone.
Get products and technologies
- Download and experiment with PicoContainer.
- Download NanoContainer to create the examples in this article. NanoContainer is related to PicoContainer (written by some of the same developers) but has a slightly different philosophy and more out-of-the-box capabilities.
- Innovate your next open source development project with IBM trial software, available for download or on DVD.
- Download Apache Geronimo, Version 1.0.
- Download your free copy of IBM WebSphere® Application Server Community Edition V1.0 -- a lightweight J2EE application server built on Apache Geronimo open source technology that is designed to help you accelerate your development and deployment efforts.
Discuss
- Participate in the discussion forum.
- Get involved in the developerWorks community by participating in developerWorks blogs.

Neal Ford is an application architect at ThoughtWorks, a global IT consultancy with an exclusive focus on end-to-end software development and delivery. He is the author of Developing with Delphi: Object-Oriented Techniques, JBuilder 3 Unleashed, and Art of Java Web Development. His primary consulting focus is on building large-scale enterprise applications. You can reach Neal through his Web site at www.nealford.com or at nford@thoughtworks.com.





