Sunday, October 21, 2007

Introduction to the Spring Framework

What is the Spring Framework?

According to SpringFramework.org:

Spring provides a light-weight solution for building enterprise-ready applications, while still supporting the possibility of using declarative transaction management, remote access to your logic using RMI or web services, and various options for persisting your data to a database [1].

More specifically Spring is a way of using regular Java Beans as Enterprise JavaBeans without involving the complexity of J2EE. JavaBeans encapsulate many objects into a single object (the bean), so that the bean can be passed around rather than the individual objects [2]. The Enterprise JavaBean (EJB) is a managed, server-side component architecture for modular construction of enterprise applications [3], which requires a J2EE container/application server. Java 2 Enterprise Edition (J2EE) is a combination of libraries and useful technologies for the Java programming language, that are used to develop and deploy enterprise applications using modular components using a Java application server.

Spring is more than just JavaBeans though, it is a framework that contains other frameworks, which are designed to independently work well with other frameworks. These frameworks or modules are typically divided into the following:

  • Inversion of Control Container (Core Container)
  • Context Module
  • Aspect Oriented Programming (AOP) Module
  • Data Access Object (DAO) Module
  • Object-Relational Mapping (ORM) Module
  • Web Module
  • Model-View-Controller (MVC) Framework

For the purposes of introduction though, it is best to start with the basics of the Inversion Control Container. Central in the Spring Framework is its Inversion of Control Container that provides a consistent means of configuring and managing Java objects. This container is also known as BeanFactory, ApplicationContext or Core container [4]. Inversion of Control is a concept in which the control flow is inverted compared to the traditional interaction model expressed in imperative style by a series of procedure calls. Thus, instead of the programmer specifying, by the means of function calls, a series of events to happen during the lifetime of a programme, they would rather register desired responses to particular happenings, and then let some external entities take over the control over the precise order and set of events to happen [5].

Where do I get the Spring Framework and how do I install it?

The framework is a series of JAR files, which can be downloaded from http://www.springframework.org/download for fee. To install it all you really have to do is extract the downloaded compressed file to some location on your computer, and then reference the appropriate JARs in a Java project. If you download the full distribution you will get the following directories, which are specified "RELEASE INFO" section of the "readme.txt" included with the distribution:

  • dist -  contains the Spring distribution jar files, as well as a zip of all Java source files
  • docs -  contains the Spring reference documentation in PDF and HTML format, as well as the complete API javadocs
  • lib -  contains all third-party libraries needed for building the framework and/or running the samples
  • src -  contains the general Java source files for the framework
  • mock -  contains the general Java source files for Spring's mock and test classes
  • test -  contains the general Java source files for Spring's test suite
  • tiger/src - contains the JDK-1.5-specific Java source files for the framework
  • tiger/test -  contains the JDK-1.5-specific Java source files for Spring's test suite
  • aspectj/src -  contains the AspectJ-specific source files for the framework
  • aspectj/test - contains the AspectJ-specific source files for Spring's test suite
  • samples - contains various demo applications and showcases

How do I use the Spring Framework?

Considering that there are many sub-frameworks in Spring, it is easiest to start with an example that demonstrates the core basics of the Inversion of Control Container. There are many available Spring Tutorials that can be found in books and on the internet. So far the best example that I have been able to find is the Inversion of Control example from DevelopersBook.com, in which you don't directly connect your components and services together in code but describe which services are needed by which components in a configuration file [6]. I have taken the basic example and modified it to include comments and a few other properties, with the intention for later use in an Aspect Oriented Programming example. Consider a simple application framework that provides JavaBean that is used to greet as specified person using a "Greeting Service," and say good-bye to that person using a "Leaving Service." This requires the following classes, interfaces, and XML configuration:

  • HelloBean.java - This is the bean that is used to encapsulate the "Greeting Service" and "Leaving Service."
  • HelloBean.xml - This is the Spring XML configuration file that is used to specify the instance and relationships of the involved object.
  • GreetingService.java (implementing GreetingInterface.java) - This is the service that is used to generate the greeting message.
  • LeavingService.java (implementing LeavingInterface.java) - This is the service that is used to generate the leaving message.
  • HelloClient.java - This is the main class that uses the Inversion of Control Container with the Spring XML configuration file to get the specified instance of the HelloBean.

The following is the project directory structure, which shows the location of the Java source code files, the related class files, and the Spring XML configuration file:

  • bin
    • springapp
      • service
        • interfaces
          • GreetingInterface.class
          • LeavingInterface.class
        • GreetingService.class
        • LeavingService.class
      • bean
        • HelloBean.class
      • HelloClient.class
    • HelloBean.xml
  • src
    • springapp
      • service
        • interfaces
          • GreetingInterface.java
          • LeavingInterface.java
        • GreetingService.java
        • LeavingService.java
      • bean
        • HelloBean.java
      • HelloClient.java

Architecturally the following class diagram shows how all of the objects relate to one another within the "springapp" package:

The "HelloClient" uses the Spring XML configuration file "HelloBean.xml" with  the Inversion of Control Container to create the specified instance of the "HelloBean." The "HelloBean" encapsulates the objects and functionality of the "GreetingService" and "LeavingService."

For this particular application, the following libraries from the Spring Framework are required:

  • <spring-install>\lib\jakarta-commons\*.jar
  • <spring-install>\lib\log4j\lg4j-1.2.14.jar
  • <spring-install>\dist\spring.jar

GreetingService.java

This is an object that is instantiated by the "HelloBean" in order to generate the greeting message. The actual instantiation though is specified in the "HelloBean.xml" file, which is handled by the Inversion of Control Container or BeanFactory. This class only has one property, which is the variable "greetingMessage." In order for the BeanFactory to be able to allow the setting of the value of this variable the class must provide a "setter" method. In the case of the "GreetingService," it has a "setGreetingMessage" method that can used by the BeanFactory to set the value of the "greetingMessage" variable.

package springapp.service;

import springapp.service.interfaces.GreetingInterface;

/**
 * <p>Title: Greeting Service</p>
 * 
 * <p>Description: This is the service that is used to generate
 * the greeting message.</p>
 * <p>Taken and modified from Code Listing 1:
 * http://www.developersbook.com/spring/spring-tutorials/</p>
 *
 * @author John Valentino II
 */
public class GreetingService implements GreetingInterface {

 /** This is greeting message that is displayed.*/
 private String greetingMessage;

 /**
  * Returns the "Hello" message for the person of the given name.
  * @param name
  * @return String
  */
 public String sayHello(String name) {
  return greetingMessage + " " + name + ".";
 }

 /**
  * Sets the greeting message
  * @param message
  */
 public void setGreetingMessage(String message) {
  this.greetingMessage = message;
 }

}

GreetingInterface.java

The methods required to be implemented by the "GreetingService" that are public and are not "getter" or "setter" methods are specified in this interface. This is because it is considered good practice to separately specify those methods in an implemented interface.

package springapp.service.interfaces;

/**
 * <p>Title: Greeting Interface</p>
 * 
 * <p>Description: Representing the methods of the Greeting Service.</p>
 * <p>Taken and modified from Code Listing 1:
 * http://www.developersbook.com/spring/spring-tutorials/</p>
 *
 * @author John Valentino II
 */
public interface GreetingInterface {

 /**
  * Returns the "Hello" message for the person of the given name.
  * @param name
  * @return String
  */
 public String sayHello(String name);
}

LeavingService.java

This is an object that is instantiated by the "HelloBean" in order to generate the leaving message. The actual instantiation though is specified in the "HelloBean.xml" file, which is handled by the Inversion of Control Container or BeanFactory. This class only has one property, which is the variable "leavingMessage." In order for the BeanFactory to be able to allow the setting of the value of this variable the class must provide a "setter" method. In the case of the "LeavingService," it has a "setLeavingMessage" method that can used by the BeanFactory to set the value of the "leavingMessage" variable.

package springapp.service;

import springapp.service.interfaces.LeavingInterface;

/**
 * <p>Title: Leaving Service</p>
 * 
 * <p>Description: This is the service that is used to generate
 * the leaving message.</p>
 * <p>Taken and modified from Code Listing 2:
 * http://www.developersbook.com/spring/spring-tutorials/</p>
 *
 * @author John Valentino II
 */
public class LeavingService implements LeavingInterface {

 /** The good-bye message to be displayed. */
 private String leavingMessage;

 /**
  * Returns the "Good-Bye" message for the person of the given name
  * @param name
  * @return String
  */
 public String sayGoodBye(String name) {
  return leavingMessage + " " + name + ".";
 }

 /**
  * Sets the good-bye message
  * @param message
  */
 public void setLeavingMessage(String message) {
  this.leavingMessage = message;
 }

}

LeavingInterface.java

The methods required to be implemented by the "LeavingService" that are public and are not "getter" or "setter" methods are specified in this interface.

package springapp.service.interfaces;

/**
 * <p>Title: Leaving Interface</p>
 * 
 * <p>Required methods for the Leaving Service.</p>
 * <p>Taken and modified from Code Listing 2:
 * http://www.developersbook.com/spring/spring-tutorials/</p>
 * 
 * @author John Valentino II
 *
 */
public interface LeavingInterface {

 /**
  * Returns the "Good-Bye" message for the person of the given name
  * @param name
  * @return String
  */
 public String sayGoodBye(String name);

}

HelloBean.java

This is the JavaBean that is used to encapsulate the services of this example application. Since this class has three properties, it specifies three "setter" methods to allow the setting of instances or values by the BeanFactory or other parent classes.

package springapp.bean;

import springapp.service.GreetingService;
import springapp.service.LeavingService;

/**
 * <p>Title: Hello Bean</p>
 * 
 * <p>Description: Represents the Hello Bean.</p>
 * <p>Taken and modified from Code Listing 4:
 * http://www.developersbook.com/spring/spring-tutorials/</p>
 *
 * @author John Valentino II
 */
public class HelloBean {

 /** Represents the service used to generate a greeting */
 private GreetingService greetingService;
 /** Represents the service used to generate a good-bye message */
 private LeavingService leavingService;
 /** Represents the name of the person to meet or leave */
 private String personName;

 /**
  * Sets the name of the person
  * @param name
  */
 public void setPersonName(String name) {
  this.personName = name;
 }

 /**
  * Sets the instance of the greeting service
  * @param service
  */
 public void setGreetingService(GreetingService service) {
  this.greetingService = service;
 }

 /**
  * Set the instance of the leaving service
  * @param service
  */
 public void setLeavingService(LeavingService service) {
  this.leavingService = service;
 }

 /**
  * Generates the greeting message
  * @return
  */
 public String greet() {
  return greetingService.sayHello(personName);
 }

 /**
  * Generates the leaving message
  * @return
  */
 public String leave() {
  return leavingService.sayGoodBye(personName);
 }

}

HelloClient.java

This is the main class of the application that uses the "HelloBean.xml" with the Inversion of Control Container to create the instance of the "HelloBean" and call is available methods.

package springapp;

import springapp.bean.HelloBean;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * <p>Title: Hello Client</p>
 * 
 * <p>Description: Represents a program that uses the HelloBean.</p>
 * <p>Taken and modified from Code Listing 5:
 * http://www.developersbook.com/spring/spring-tutorials/</p>
 *
 * @author John Valentino II
 */
public class HelloClient {

 /**
  * @param args
  */
 public static void main(String[] args) {

  //Get the instance of the HelloBean as specified in HelloBean.xml
  ClassPathXmlApplicationContext appContext = 
   new ClassPathXmlApplicationContext(new String[] { "HelloBean.xml" });
  HelloBean helloBean = (HelloBean) appContext.getBean("helloBean");

  System.out.println(helloBean.greet());
  System.out.println(helloBean.leave());

 }

}

HelloBean.xml

This is the Spring XML configuration file that is used to specify the instances and properties of the bean classes within the application.

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

<beans>
 <!-- Creates an instance of the "HelloBean" class -->
 <bean id="helloBean" class="springapp.bean.HelloBean">
  <!-- Sets the value of "personName" by
       calling "setPersonName" -->
  <property name="personName">
   <value>Sarah</value>
  </property>
  <!-- Sets the instance of "greetingService" by
       calling "setGreetingService" -->
  <property name="greetingService"> 
   <ref bean="greetingService" />
  </property>
  <!-- Sets the instance of "leavingService" by
       calling "setLeavingService" -->
  <property name="leavingService">
   <ref bean="leavingService" /> 
  </property> 
 </bean>
 <!-- Creates an instance of the "GreetingService" -->
 <bean id="greetingService" class="springapp.service.GreetingService">
  <!-- Sets the value of "greetingMessage" by 
         calling "setGreetingMessage" -->
  <property name="greetingMessage">
   <value>Hello</value>
  </property>
 </bean>
 <!-- Creates an instance of the "LeavingService" -->
 <bean id="leavingService" class="springapp.service.LeavingService">
  <!-- Sets the value of "leavingMessage" by
       calling "setLeavingMessage" -->
  <property name="leavingMessage">
   <value>Good-bye</value>
  </property>
 </bean>
</beans>

Output

The program runs and generates the following output:

Hello Sarah.
Good-bye Sarah.

This output is to be expected as the Spring XML configuration file specifies that the "HelloBean" instance has the specified "personName," an instance of the "GreetingService," and an instance of the "LeavingService." Both service instances are also given specified "greetingMessage" and "leavingMessage" values.

Links

References

  1. SpringFramework.org, Documentation Preface, http://static.springframework.org/spring/docs/2.0.x/reference/preface.html
  2. Wikipedia, JavaBean, http://en.wikipedia.org/wiki/JavaBeans
  3. Wikipedia, Enterprise JavaBean, http://en.wikipedia.org/wiki/Ejb
  4. Wikipedia, Spring Framework, http://en.wikipedia.org/wiki/Spring_framework
  5. Wikipedia, Inversion of Control, http://en.wikipedia.org/wiki/Inversion_of_Control
  6. DevlopersBook.com, Spring Framework Tutorial, http://www.developersbook.com/spring/spring-tutorials/spring-tutorials.php

No comments: