http://www.developer.com/

Back to article

A Spring Jump Start


April 13, 2005

It all started with a bean.

In 1996 the Java programming language was still a young, exciting, up-and-coming platform. Many developers flocked to the language because they had seen how to create rich and dynamic web applications using applets. But they soon learned that there was more to this strange new language than animated juggling cartoon characters. Unlike any language before it, Java made it possible to write complex applications made up of discrete parts. They came for the applets, but they stayed for the components.

It was in December of that year that Sun Microsystems published the Java-Beans 1.00-A specification. JavaBeans defined a software component model for Java. This specification defined a set of coding policies that enabled simple Java objects to be reusable and easily composed into more complex applications. Although JavaBeans were intended as a general-purpose means of defining reusable application components, they have been primarily used as a model for building user interface widgets. They seemed too simple to be capable of any "real" work. Enterprise developers wanted more.

Sophisticated applications often require services such as transaction support, security, and distributed computing—services not directly provided by the Java-Beans specification. Therefore, in March 1998, Sun published the 1.0 version of the Enterprise JavaBeans (EJB) specification. This specification extended the notion of Java components to the server side, providing the much-needed enterprise services, but failed to continue the simplicity of the original JavaBeans specification. In fact, except in name, EJB bears very little resemblance to the original JavaBeans specification.

Despite the fact that many successful applications have been built based on EJB, EJB never really achieved its intended purpose: to simplify enterprise application development. Every version of the EJB specification contains the following statement: "Enterprise JavaBeans will make it easy to write applications." It is true that EJB's declarative programming model simplifies many infrastructural aspects of development, such as transactions and security. But EJBs are complicated in a different way by mandating deployment descriptors and plumbing code (home and remote/local interfaces). Over time many developers became disenchanted with EJB. As a result, its popularity has started to wane in recent years, leaving many developers looking for an easier way.

Now Java component development is coming full circle. New programming techniques, including aspect-oriented programming (AOP) and inversion of control (IoC), are giving JavaBeans much of the power of EJB. These techniques furnish JavaBeans with a declarative programming model reminiscent of EJB, but without all of EJB's complexity. No longer must you resort to writing an unwieldy EJB component when a simple JavaBean will suffice.

And that's where Spring steps into the picture.

1.1 Why Spring?

If you are reading this book, you probably want to know why Spring would be good for you. After all, the Java landscape is full of frameworks. What makes Spring any different? To put it simply, Spring makes developing enterprise applications easier. We don't expect that to convince you at face value, so first let's take a look at life without Spring.

1.1.1 A day in the life of a J2EE developer

Alex is a Java developer who has just started on his first enterprise application. Like many Java 2 Enterprise Edition (J2EE) applications, it is a web application that serves many users and accesses an enterprise database. In this case, it is a customer management application that will be used by other employees at his company.

Eager to get to work, Alex fires up his favorite integrated development environment (IDE) and starts to crank out his first component, the CustomerManager component. In the EJB world, to develop this component Alex actually has to write several classes—the home interface, the local interface, and the bean itself. In addition, he has to create a deployment descriptor for this bean.

Seeing that creating each of these files for every bean seems like a lot of effort, Alex incorporates XDoclet into his project. XDoclet is a code generation tool that can generate all of the necessary EJB files from a single source file. Although this adds another step to Alex's development cycle, his coding life is now much simpler.

With XDoclet now handling a lot of the grunt work for him, Alex turns his attention to his real problem—what exactly should the CustomerManager component do? He jumps in with its first method, getPreferredCustomer(). There are several business rules that define exactly what a preferred customer is, and Alex dutifully codes them into his CustomerManager bean.

Wanting to confirm that his logic is correct, Alex now wants to write some tests to validate his code. But then it occurs to him: the code he is testing will be running within the EJB container. Therefore, his tests need to execute within the container as well. To easily accomplish this, he concocts a servlet that will be responsible for executing these tests. Since all J2EE containers support servlets, this will allow him to execute his tests in the same container as his EJB. Problem solved!

So Alex fires up his J2EE container and runs his tests. His tests fail. Alex sees his coding error, fixes it, and runs the tests again. His tests fail again. He sees another error and fixes it. He fires up the container and runs the tests again. As Alex is going through this cycle, he notices something. The fact that he has to start the J2EE container for each batch of testing really slows down his development cycle. The development cycle should go code, test, code, test. This pattern has now been replaced with code, wait, test, code, wait, test, code, wait, get increasingly frustrated...

While waiting for the container to start during another test run, Alex thinks, "Why am I using EJB in the first place?" The answer, of course, is because of the services it provides. But Alex isn't using entity beans, so he is not using persistence services. Alex is also not using the remoting or security services. In fact, the only EJB service Alex is going to use is transaction management. This leads Alex to another question: "Is there an easier way?"

1.1.2 Spring's pledge

The above story was a dramatization based on the current state of J2EE—specifically EJB. In its current state, EJB is complicated. It isn't complicated just to be complicated. It is complicated because EJBs were created to solve complicated things, such as distributed objects and remote transactions.

Unfortunately, a good number of enterprise projects do not have this level of complexity but still take on EJB's burden of multiple Java files and deployment descriptors and heavyweight containers. With EJB, application complexity is high, regardless of the complexity of the problem being solved—even simple applications are unduly complex. With Spring, the complexity of your application is proportional to the complexity of the problem being solved.

However, Spring recognizes that EJB does offer developers valuable services. So Spring strives to deliver these same services while simplifying the programming model. In doing so, it adopts a simple philosophy: J2EE should be easy to use. In keeping with this philosophy, Spring was designed with the following beliefs:

  • Good design is more important than the underlying technology.
  • JavaBeans loosely coupled through interfaces is a good model.
  • Code should be easy to test.

Okay. So how does Spring help you apply this philosophy to your applications?.

Good design is more important than the underlying technology

As a developer, you should always be seeking the best design for your application, regardless of the implementation you choose. Sometimes the complexity of EJB is warranted because of the requirements of the application. Often, this is not the case. Many applications require few, if any, of the services provided by EJB yet are still implemented using this technology for technology's sake. If an application does not require distribution or declarative transaction support, it is unlikely that EJB is the best technology candidate. Yet many Java developers feel compelled to use EJB for every Java enterprise application.

The idea behind Spring is that you can keep your code as simple as it needs to be. If what you want are some plain-vanilla Java objects to perform some services supported by transparent transactions, you've got it. And you don't need an EJB container, and you don't have to implement special interfaces. You just have to write your code.

JavaBeans loosely coupled through interfaces is a good model

If you are relying on EJBs to provide your application services, your components do not just depend on the EJB business interface. They are also responsible for retrieving these EJB objects from a directory, which entails a Java Naming and Directory Interface (JNDI) lookup and communicating with the bean's EJBHome interface. This is not creating a decoupled application. This is tightly coupling your application to a specific implementation, namely EJB.

With Spring, your beans depend on collaborators through interfaces. Since there are no implementation-specific dependencies, Spring applications are very decoupled, testable, and easier to maintain. And because the Spring container is responsible for resolving the dependencies, the active service lookup that is involved in EJB is now out of the picture and the cost of programming to interfaces is minimized. All you need to do is create classes that communicate with each other through interfaces, and Spring takes care of the rest.

Code should be easy to test

Testing J2EE applications can be difficult. If you are testing EJBs within a container, you have to start up a container to execute even the most trivial of test cases. Since starting and stopping a container is expensive, developers may be tempted to skip testing all of their components. Avoiding tests because of the rigidness of a framework is not a good excuse.

Because you develop Spring applications with JavaBeans, testing is cheap. There is no J2EE container to be started since you will be testing a POJO. And. since Spring makes coding to interfaces easy, your objects will be loosely coupled, making testing even easier. A thorough battery of tests should be present in all of your applications; Spring will help you accomplish this.

1.2 What is Spring?

Spring is an open-source framework, created by Rod Johnson and described in his book Expert One-on-One: J2EE Design and Development.1 It was created to address the complexity of enterprise application development. Spring makes it possible to use plain-vanilla JavaBeans to achieve things that were previously only possible with EJBs. However, Spring's usefulness isn't limited to server-side development. Any Java application can benefit from Spring in terms of simplicity, testability, and loose coupling.

Note: To avoid ambiguity, we'll use the term "EJB" when referring to Enterprise JavaBeans. When referring to the original JavaBean, we'll call it "JavaBean," or "bean" for short. Some other terms we may throw around are "POJO" (which stands for "plain old Java object") or "POJI" (which means "plain old Java interface").

Put simply, Spring is a lightweight inversion of control and aspect-oriented container framework. Okay, that's not so simple a description. But it does summarize what Spring does. To make more sense of Spring, let's break this description down:

  • Lightweight—Spring is lightweight in terms of both size and overhead. The entire Spring framework can be distributed in a single JAR file that weighs in at just over 1 MB. And the processing overhead required by Spring is negligible. What's more, Spring is nonintrusive: objects in a Spring-enabled application typically have no dependencies on Spring-specific classes.
  • Inversion of control—Spring promotes loose coupling through a technique known as inversion of control (IoC). When IoC is applied, objects are passively given their dependencies instead of creating or looking for dependent objects for themselves. You can think of IoC as JNDI in reverse—instead of an object looking up dependencies from a container, the container gives the dependencies to the object at instantiation without waiting to be asked.
  • Aspect-oriented—Spring comes with rich support for aspect-oriented programming that enables cohesive development by separating application business logic from system services (such as auditing and transaction management). Application objects do what they're supposed to do—perform business logic—and nothing more. They are not responsible for (or even aware of) other system concerns, such as logging or transactional support.
  • Container—Spring is a container in the sense that it contains and manages the life cycle and configuration of application objects. You can configure how your each of your beans should be created—either create one single instance of your bean or produce a new instance every time one is needed based on a configurable prototype—and how they should be associated with each other. Spring should not, however, be confused with traditionally heavyweight EJB containers, which are often large and cumbersome to work with.
  • Framework—Spring makes it possible to configure and compose complex applications from simpler components. In Spring, application objects are composed declaratively, typically in an XML file. Spring also provides much infrastructure functionality (transaction management, persistence framework integration, etc.), leaving the development of application logic to you.

All of these attributes of Spring enable you to write code that is cleaner, more manageable, and easier to test. They also set the stage for a variety of subframeworks within the greater Spring framework.

1.2.1 Spring modules

The Spring framework is made up of seven well-defined modules (figure 1.1). When taken as a whole, these modules give you everything you need to develop enterprise-ready applications. But you do not have to base your application fully on the Spring framework. You are free to pick and choose the modules that suit your application and ignore the rest.

As you can see, all of Spring's modules are built on top of the core container. The container defines how beans are created, configured, and managed—more of the nuts-and-bolts of Spring. You will implicitly use these classes when you configure your application. But as a developer, you will most likely be interested in the other modules that leverage the services provided by the container. These modules will provide the frameworks with which you will build your application's services, such as AOP and persistence.

Figure 1.1 The Spring framework is composed of several well-defined modules.

The core container

Spring's core container provides the fundamental functionality of the Spring framework. In this module you'll find Spring's BeanFactory, the heart of any Spring-based application. A BeanFactory is an implementation of the factory pattern that applies IoC to separate your application's configuration and dependency specifications from the actual application code.

We discuss the core module (the center of any Spring application) throughout our book, Spring in Action from Manning Publications, starting in chapter 2, when we cover bean wiring using IoC.

Application context module

The core module's BeanFactory makes Spring a container, but the context module is what makes it a framework. This module extends the concept of BeanFactory, adding support for internationalization (I18N) messages, application life cycle events, and validation.

In addition, this module supplies many enterprise services such as e-mail, JNDI access, EJB integration, remoting, and scheduling. Also included is support for integration with templating frameworks such as Velocity and FreeMarker.

Spring's AOP module

Spring provides rich support for aspect-oriented programming in its AOP module. This module serves as the basis for developing your own aspects for your Spring-enabled application.

To ensure interoperability between Spring and other AOP frameworks, much of Spring's AOP support is based on the API defined by the AOP Alliance. The AOP Alliance is an open-source project whose goal is to promote adoption of AOP and interoperability among different AOP implementations by defining a common set of interfaces and components. You can find out more about the AOP Alliance by visiting their website at http://aopalliance.sourceforge.net.

The Spring AOP module also introduces metadata programming to Spring. Using Spring's metadata support, you are able to add annotations to your source code that instruct Spring on where and how to apply aspects.

JDBC abstraction and the DAO module

Working with JDBC often results in a lot of boilerplate code that gets a connection, creates a statement, processes a result set, and then closes the connection. Spring's JDBC and Data Access Objects (DAO) module abstracts away the boilerplate code so that you can keep your database code clean and simple, and prevents problems that result from a failure to close database resources. This module also builds a layer of meaningful exceptions on top of the error messages given by several database servers. No more trying to decipher cryptic and proprietary SQL error messages!

In addition, this module uses Spring's AOP module to provide transaction management services for objects in a Spring application.

Object/relational mapping integration module

For those who prefer using an object/relational mapping (ORM) tool over straight JDBC, Spring provides the ORM module. Spring doesn't attempt to implement its own ORM solution, but does provide hooks into several popular ORM frameworks, including Hibernate, JDO, and iBATIS SQL Maps. Spring's transaction management supports each of these ORM frameworks as well as JDBC.

Spring's web module

The web context module builds on the application context module, providing a context that is appropriate for web-based applications. In addition, this module contains support for several web-oriented tasks such as transparently handling multipart requests for file uploads and programmatic binding of request parameters to your business objects. It also cotains integration support with Jakarta Struts.

The Spring MVC framework

Spring comes with a full-featured Model/View/Controller (MVC) framework for building web applications. Although Spring can easily be integrated with other MVC frameworks, such as Struts, Spring's MVC framework uses IoC to provide for a clean separation of controller logic from business objects. It also allows you to declaratively bind request parameters to your business objects, What's more, Spring's MVC framework can take advantage of any of Spring's other services, such as I18N messaging and validation.

Now that you know what Spring is all about, let's jump right into writing Spring applications, starting with the simplest possible example that we could come up with.

1.3 Spring jump start

In the grand tradition of programming books, we'll start by showing you how Spring works with the proverbial "Hello World" example. Unlike the original Hello World program, however, our example will be modified a bit to demonstrate the basics of Spring.

Note: To find out how to download Spring and plug it into your project's build routine, refer to appendix A.

Spring-enabled applications are like any Java application. They are made up of several classes, each performing a specific purpose within the application. What makes Spring-enabled applications different, however, is how these classes are configured and introduced to each other. Typically, a Spring application has an XML file that describes how to configure the classes, known as the Spring configuration file.

The first class that our Springified Hello World example needs is a service class whose purpose is to print the infamous greeting. Listing 1.1 shows GreetingService.java, an interface that defines the contract for our service class.

Listing 1.1 The GreetingService interface separates the service's implementation from its interface.

package com.springinaction.chapter01.hello;

public interface GreetingService {
   public void sayGreeting();
}

GreetingServiceImpl.java (listing 1.2) implements the GreetingService interface. Although it's not necessary to hide the implementation behind an interface, it's highly recommended as a way to separate the implementation from its contract.

Listing 1.2 GreetingServiceImpl.java: Responsible for printing the greeting

package com.springinaction.chapter01.hello;

public class GreetingServiceImpl implements GreetingService {
   private String greeting;

   public GreetingServiceImpl() {}

   public GreetingServiceImpl(String greeting) {
      this.greeting = greeting;
   }

   public void sayGreeting() {
      System.out.println(greeting);
   }

   public void setGreeting(String greeting) {
      this.greeting = greeting;
   }
}

The GreetingServiceImpl class has a single property: the greeting property. This property is simply a String that holds the text that is the message that will be printed when the sayGreeting() method is called. You may have noticed that the greeting can be set in two different ways: by the constructor or by the property's setter method.

What's not apparent just yet is who will make the call to either the constructor or the setGreeting() method to set the property. As it turns out, we're going to let the Spring container set the greeting property. The Spring configuration file (hello.xml) in listing 1.3 tells the container how to configure the greeting service.

Listing 1.3 Configuring Hello World in Spring

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
   "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
   <bean id="greetingService"
         class="com.springinaction.chapter01.hello.GreetingServiceImpl">
      <property name="greeting">
         <value>Buenos Dias!</value>
      </property>
   </bean>
</beans>

The XML file in listing 1.3 declares an instance of a GreetingServiceImpl in the Spring container and configures its greeting property with a value of "Buenos Dias!" Let's dig into the details of this XML file a bit to understand how it works.

At the root of this simple XML file is the <beans> element, which is the root element of any Spring configuration file. The <bean> element is used to tell the Spring container about a class and how it should be configured. Here, the id attribute is used to name the bean greetingService and the class attribute specifies the bean's fully qualified class name.

Within the <bean> element, the <property> element is used to set a property, in this case the greeting property. By using <property>, we're telling the Spring container to call setGreeting() when setting the property.

The value of the greeting is defined within the <value> element. Here we've given the example a Spanish flair by choosing "Buenos Dias" instead of the traditional "Hello World."

The following snippet of code illustrates roughly what the container does when instantiating the greeting service based on the XML definition in listing 1.3:2

GreetingServiceImpl greetingService = new GreetingServiceImpl();
greetingService.setGreeting("Buenos Dias!");

Similarly, we may choose to have Spring set the greeting property through GreetingServiceImpl's single argument constructor. For example:

<bean id="greetingService"
      class="com.springinaction.chapter01.hello.GreetingServiceImpl">
   <constructor-arg>
      <value>Buenos Dias!</value>
   </constructor-arg>
</bean>

The following code illustrates how the container will instantiate the greeting service when using the <constructor-arg> element:

GreetingServiceImpl greetingService =
   new GreetingServiceImpl("Buenos Dias");

The last piece of the puzzle is the class that loads the Spring container and uses it to retrieve the greeting service. Listing 1.4 shows this class.

Listing 1.4 The Hello World main class

package com.springinaction.chapter01.hello;

import java.io.FileInputStream;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;

public class HelloApp {
   public static void main(String[] args) throws Exception {
      BeanFactory factory =
         new XmlBeanFactory(new FileInputStream("hello.xml"));

      GreetingService greetingService =
         (GreetingService) factory.getBean("greetingService");

      greetingService.sayGreeting();
   }
}

The BeanFactory class used here is the Spring container. After loading the hello.xml file into the container, the main() method calls the getBean() method on the BeanFactory to retrieve a reference to the greeting service. With this reference in hand, it finally calls the sayGreeting() method. When we run the Hello application, it prints (not surprisingly)

Buenos Dias!

This is about as simple a Spring-enabled application as we can come up with. But it does illustrate the basics of configuring and using a class in Spring. Unfortunately, it is perhaps too simple because it only illustrates how to configure a bean by injecting a String value into a property. The real power of Spring lies in how beans can be injected into other beans using IoC.

1.4 Understanding inversion of control

Inversion of control is at the heart of the Spring framework. It may sound a bit intimidating, conjuring up notions of a complex programming technique or design pattern. But as it turns out, IoC is not nearly as complex as it sounds. In fact, by applying IoC in your projects, you'll find that your code will become significantly simpler, easier to understand, and easier to test.

But what does "inversion of control" mean?

1.4.1 Injecting dependencies

In an article written in early 2004, Martin Fowler asked what aspect of control is being inverted. He concluded that it is the acquisition of dependent objects that is being inverted. Based on that revelation, he coined a better name for inversion of control: dependency injection.3

Any nontrivial application (pretty much anything more complex than HelloWorld.java) is made up of two or more classes that collaborate with each other to perform some business logic. Traditionally, each object is responsible for obtaining its own references to the objects it collaborates with (its dependencies). As you'll see, this can lead to highly coupled and hard-to-test code.

Applying IoC, objects are given their dependencies at creation time by some external entity that coordinates each object in the system. That is, dependencies are injected into objects. So, IoC means an inversion of responsibility with regard to how an object obtains references to collaborating objects.

1.4.2 IoC in action

If you're like us, then you're probably anxious to see how this works in code. We aim to please, so without further delay...

Suppose that your company's crack marketing team culled together the results of their expert market analysis and research and determined that what your customers need is a knight. That is, they need a Java class that represents a knight. After probing them for requirements, you learn that what they specifically want is for you to implement a class that represents an Arthurian knight of the Round Table that embarks on brave and noble quests to find the Holy Grail.

This is an odd request, but you've become accustomed to the strange notions and whims of the marketing team. So, without hesitation, you fire up your favorite IDE and bang out the class in listing 1.5.

Listing 1.5 KnightOfTheRoundTable.java

In listing 1.5 the knight is given a name as a parameter of its constructor. Its constructor sets the knight's quest by instantiating a HolyGrailQuest. The implementation of HolyGrailQuest is fairly trivial, as shown in listing 1.6.

Listing 1.6 HolyGrailQuest.java

package com.springinaction.chapter01.knight;
public class HolyGrailQuest {
   public HolyGrailQuest() {}

   public HolyGrail embark() throws GrailNotFoundException {
      HolyGrail grail = null;
      // Look for grail
      ...
      return grail;
   }
}

Satisfied with your work, you proudly check the code into version control. You want to show it to the marketing team, but deep down something doesn't feel right. You almost dismiss it as the burrito you had for lunch when you realize the problem: you haven't written any unit tests.

Knightly testing

Unit testing is an important part of development. It not only ensures that each individual unit functions as expected, but it also serves to document each unit in the most accurate way possible. Seeking to rectify your failure to write unit tests, you put together the test case (listing 1.7) for your knight class.

Listing 1.7 Testing the KnightOfTheRoundTable

package com.springinaction.chapter01.knight;

import junit.framework.TestCase;

public class KnightOfTheRoundTableTest extends TestCase {

   public void testEmbarkOnQuest() {
      KnightOfTheRoundTable knight =
         new KnightOfTheRoundTable("Bedivere");

      try {
         HolyGrail grail = knight.embarkOnQuest();

         assertNotNull(grail);

         assertTrue(grail.isHoly());
      } catch (GrailNotFoundException e) {
         fail();
      }
   }
}

After writing this test case, you set out to write a test case for HolyGrailQuest. But before you even get started, you realize that the KnightOfTheRoundTableTest test case indirectly tests HolyGrailQuest. You also wonder if you are testing all contingencies. What would happen if HolyGrailQuest's embark() method returned null? Or what if it were to throw a GrailNotFoundException?

Who's calling who?

The main problem so far with KnightOfTheRoundTable is with how it obtains a HolyGrailQuest. Whether it is instantiating a new HolyGrail instance or obtaining one via JNDI, each knight is responsible for getting its own quest (as shown in figure 1.2). Therefore, there is no way to test the knight class in isolation. As it stands, every time you test KnightOfTheRoundTable, you will also indirectly test HolyGrailQuest.

Figure 1.2 A knight is responsible for getting its own quest, through instantiation or some other means.

What's more, you have no way of telling HolyGrailQuest to behave differently (e.g., return null or throw a GrailNotFoundException) for different tests. What would help is if you could create a mock implementation of HolyGrailQuest that lets you decide how it behaves. But even if you were to create a mock implementation, KnightOfTheRoundTable still retrieves its own HolyGrailQuest, meaning you would have to make a change to KnightOfTheRoundTable to retrieve the mock quest for testing purposes (and then change it back for production).

Decoupling with interfaces

The problem, in a word, is coupling. At this point, KnightOfTheRoundTable is statically coupled to HolyGrailQuest. They're handcuffed together in such a way that you can't have a KnightOfTheRoundTable without also having a HolyGrailQuest.

Coupling is a two-headed beast. On one hand, tightly coupled code is difficult to test, difficult to reuse, difficult to understand, and typically exhibits "whack-a-mole" bugs (i.e., fixing one bug results in the creation of one or more new bugs). On the other hand, completely uncoupled code doesn't do anything. In order to do anything useful, classes need to know about each other somehow. Coupling is necessary, but it should be managed very carefully.

A common technique used to reduce coupling is to hide implementation details behind interfaces so that the actual implementation class can be swapped out without impacting the client class. For example, suppose you were to create a Quest interface:

package com.springinaction.chapter01.knight;

public interface Quest {
   public abstract Object embark() throws QuestException;
}

Then, you change HolyGrailQuest to implement this interface. Also, notice that embark now returns an Object and throws a QuestException.

package com.springinaction.chapter01.knight;

public class HolyGrailQuest implements Quest {
   public HolyGrailQuest() {}

   public Object embark() throws QuestException {
      // Do whatever it means to embark on a quest
      return new HolyGrail();
   }
}

Also, the following method must also change in KnightOfTheRoundTable to be compatible with these Quest types:

private Quest quest;
...
public Object embarkOnQuest() throws QuestException {
   return quest.embark();
}

Likewise, you could also have KnightOfTheRoundTable implement the following Knight interface:

public interface Knight {
   public Object embarkOnQuest() throws QuestException;
}

Hiding your class's implementation behind interfaces is certainly a step in the right direction. But where many developers fall short is in how they retrieve a Quest instance. For example, consider this possible change to KnightOfTheRoundTable:

public class KnightOfTheRoundTable implements Knight {

   private Quest quest;
   ...

   public KnightOfTheRoundTable(String name) {
      quest = new HolyGrailQuest();
   ...
   }

   public Object embarkOnQuest() throws QuestException {
      return quest.embark();
   }
}

Here the KnightOfTheRoundTable class embarks on a quest through the Quest interface. But, the knight still retrieves a specific type of Quest (here a HolyGrailQuest). This isn't much better than before. A KnightOfTheRoundTable is stuck going only on quests for the Holy Grail and no other types of quest.

Giving and taking

The question you should be asking at this point is whether or not a knight should be responsible for obtaining a quest. Or, should a knight be given a quest to embark upon?

Consider the following change to KnightOfTheRoundTable:

public class KnightOfTheRoundTable implements Knight {
   private Quest quest;
   ...

   public KnightOfTheRoundTable(String name) {
      ...
   }

   public HolyGrail embarkOnQuest() throws QuestException {
      ...
      return quest.embark();
   }

   public void setQuest(Quest quest) {
      this.quest = quest;
   }
}

Notice the difference? Compare figure 1.3 with figure 1.2 to see the difference in how a knight obtains its quest. Now the knight is given a quest instead of retrieving one itself. KnightOfTheRoundTable is no longer responsible for retrieving its own quests. And because it only knows about a quest through the Quest interface, you could give a knight any implementation of Quest you want. In a production system, maybe you would give it a HolyGrailQuest, but in a test case you would give it a mock implementation of Quest.

In a nutshell, that is what inversion of control is all about: the responsibility of coordinating collaboration between dependent objects is transferred away from the objects themselves. And that's where lightweight container frameworks, such as Spring, come into play.

Assigning a quest to a knight

Now that you've written your KnightOfTheRoundTable class to be given any arbitrary Quest object, how can you specify which Quest it should be given?

Figure 1.3 A knight is given a quest through its setQuest() method.

The act of creating associations between application components is referred to as wiring. In Spring, there are many ways to wire components together, but the most common approach is via XML. Listing 1.8 shows a simple Spring configuration file, knight.xml, that gives a quest (specifically, a HolyGrailQuest) to a KnightOfTheRoundTable.

Listing 1.8 Wiring a quest to a knight in knight.xml



Click here for a larger image.

This is just a simple approach to wiring beans. Don't worry too much about the details of it right now. In chapter 2 we'll explain more about what is going on here, as well as show you even more ways you can wire your beans in Spring.

Now that we've declared the relationship between a knight and a quest, we need to load up the XML file and kick off the application.

Seeing it work

In a Spring application, a BeanFactory loads the bean definitions and wires the beans together. Because the beans in the knight example are declared in an XML file, an XmlBeanFactory is the appropriate factory for this example. The main() method in listing 1.9 uses an XmlBeanFactory to load knight.xml and to get a reference to the "knight" object.

Listing 1.9 Running the knight example



Click here for a larger image.

Once the application has a reference to the KnightOfTheRoundTable object, it simply calls the embarkOnQuest() method to kick off the knight's adventure. Notice that this class knows nothing about the quest the knight will take. Again, the only thing that knows which type of quest will be given to the knight is the knight.xml file.

It's been a lot of fun sending knights on quests using inversion of control, but now let's see how you can use IoC in your real-world enterprise applications.4

1.4.3 IoC in enterprise applications

Suppose that you've been tasked with writing an online shopping application. Included in the application is an OrderServiceBean, implemented as a stateless session bean. Now you want to have a class that creates an Order object from user input (likely an HTML form) and call the createOrder() method on your OrderServiceBean, as shown in listing 1.10.

Listing 1.10 Creating an order using EJB



Click here for a larger image.

Notice that it took five lines of code just to get your OrderService object. Now imagine having to do this everywhere you need an OrderService object. Now imagine you have ten other EJBs in your application. That is a lot of code! But duplicating this code everywhere would be ridiculous, so a ServiceLocator is typically used instead. A ServiceLocator acts as a central point for obtaining and caching EJBHome references:

private OrderService getOrderService() {
   OrderServiceHome home =
      ServiceLocator.locate(OrderServiceHome);
   OrderService orderService = home.create();
}

While this removes the need to duplicate the lookup code everywhere in the application, one problem still remains: we always have to explicitly look up our services in our code.

Now let's see how this would be implemented in Spring:

private OrderService orderService;

public void doRequest(HttpServletRequest request) {
   Order order = createOrder(request);
   orderService.createOrder(order);
}

public void setOrderService(OrderService orderService) {
   this.orderService = orderService;
}

No lookup code! The reference to OrderService is given to our class by the Spring container through the setOrderService() method. With Spring, we never have to trouble ourselves with fetching our dependencies. Instead, our code can focus on the task at hand.

But inversion of control is only one of the techniques that Spring offers to JavaBeans. There's another side to Spring that makes it a viable framework for enterprise development. Let's take a quick look at Spring's support for aspect-oriented programming.

End Notes

1 In this book, Spring was originally called "interface21."

2 The container actually performs other activities involving the life cycle of the bean. But for illustrative purposes, these two lines are sufficient.

3 Although we agree that "dependency injection" is a more accurate name than "inversion of control," we're likely to use both terms interchangeably in this book.

4 This assumes that your real-world applications do not involve knights and quests. In the event that your current project does involve knights and quests, you may disregard the next section.

More to Come
The rest of this sample chapter will appear on our Web site starting April 27th.

About the Authors

Craig Walls is a software developer with over 10 years' experience and co-author of XDoclet in Action. He has sucessfully implemented a number of Spring applications. Craig lives in Denton, Texas.

An avid supporter of open source Java technologies, Ryan Breidenbach has been developing Java web applications for the past five years. He lives in Coppell, Texas.

About the Book

Spring in Action by Craig Walls and Ryan Breidenbach

Published February 2005, Softbound, 472 pages
Published by Manning Publications Co.
ISBN 1932394354
Retail price: $44.95
Ebook price: $22.50. To purchase the ebook go to http://www.manning.com/walls2.
This material is from Chapter 1 of the book.

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date