Refactoring Hello World Application using Spring Framework

Sang Shin, sang.shin@sun.com, www.javapassion.com/j2ee



This lab explores the motivation of Spring framework by exploring step-by-step refactoring processes for the good ol' "Hello World" sample application.  It is highly recommended you do read and study the presentation slides of the "Refactoring HelloWorld Application using Spring Framework" along with this hands-on lab.


Expected duration: 200 minutes (excluding homework)



Software Needed

Before you begin, you need to install the following software on your computer. 


OS platforms you can use

Change Log


Things to do (by Sang Shin)


Lab Exercises


Exercise 1: Build and run "HelloWorld" sample application

In this exercise, you are going to build the good ol' HelloWorld application you typically do.  This sample application will be the base for the several refactorings you will do in the subsequent exercises initially without using Spring framework's Dependency Injection (DI) - Exercises from 2 to 5 -  and then with DI - exercises from 6 to 10.

(1.1) Open, build, and run "HelloWorld" sample application

0. Start NetBeans IDE. 
1. Open HelloWorld NetBeans project. 



2. Build and run HelloWorld project. 



Figure-1.11: Result

(1.2) Look under the hood of the "HelloWorld" sample application

1. Open and study HelloWorld.java.

public class HelloWorld {

    public static void main(String[] args) {
        System.out.println("Hello World!");
    }
}
Code-1.21: HelloWorld.java

Summary

In this exercise,  you have built and run "HelloWorld" sample application in the simplest possible way.

                                                                                                                        return to the top




Exercise 2: Build and run "HelloWorldWithCommandLineArguments" sample application

You are going to do your first but still obvious refactoring, in which you are going to pass command line arguments to the program.


(2.1) Open, build, and run "HelloWorldWithCommandLineArguments" sample application

1. Open HelloWorldWithCommandLineArguments NetBeans project. 

2. Build and run HelloWorldWithCommandLineArguments project. 


(2.2) Look under the hood of the "HelloWorldWithCommandLineArguments" sample application


1. Study HelloWorldWithCommandLineArguments.java

public class HelloWorldWithCommandLineArguments {

    public static void main(String[] args) {
        if(args.length > 0) {
            System.out.println(args[0]);
        } else {
            System.out.println("Hello World!");
        }
    }
}
Code-2.21: HelloWorldWithCommandLineArguments.java

2. Observe that the project passes an argument.


Figure-2.22: Runtime argument

Summary

In this exercise,  you have built and run a ready-to-build-and-run sample application.

                                                                                                                        return to the top


Exercise 3: Build and run "HelloWorldDecoupled" sample application



(3.1) Open, build, and run "HelloWorldDecoupled" sample application

1. Open HelloWorldDecoupled NetBeans project. 

2. Build and run HelloWorldDecoupled project. 


(3.2) Look under the hood of the "HelloWorldDecoupled" sample application


1.Study HelloWorldDecoupled.java.

public class HelloWorldDecoupled {

    public static void main(String[] args) {
        StandardOutMessageRenderer mr = new StandardOutMessageRenderer();
        HelloWorldMessageProvider mp = new HelloWorldMessageProvider();
        mr.setMessageProvider(mp);       
        mr.render();
    }
}

2. StandardOutMessageRenderer.java

public class StandardOutMessageRenderer {
   
    private HelloWorldMessageProvider messageProvider = null;
   
    public void render() {
        if (messageProvider == null) {
            throw new RuntimeException(
                    "You must set the property messageProvider of class:"
                    + StandardOutMessageRenderer.class.getName());
        }
       
        System.out.println(messageProvider.getMessage());
    }
   
    public void setMessageProvider(HelloWorldMessageProvider provider) {
        this.messageProvider = provider;
    }
   
    public HelloWorldMessageProvider getMessageProvider() {
        return this.messageProvider;
    }
   
}

3. HelloWorldMessageProvider.java

public class HelloWorldMessageProvider  {

    public String getMessage() {

        return "Hello World!";
    }

}



Exercise 4: Build and run "HelloWorldDecoupledInterface" sample application



(4.1) Open, build, and run "HelloWorldDecoupledInterface" sample application

1. Open HelloWorldDecoupledInterface NetBeans project. 

2. Build and run HelloWorldDecoupledInterface project. 


(4.2) Look under the hood of the "HelloWorldDecoupledInterface" sample application


1. HelloWorldDecoupledInterface.java

public class HelloWorldDecoupledInterface {

    public static void main(String[] args) {
        MessageRenderer mr = new StandardOutMessageRenderer();
        MessageProvider mp = new HelloWorldMessageProvider();
        mr.setMessageProvider(mp);       
        mr.render();
    }
}

2. StandardOutMessageRenderer.java

public class StandardOutMessageRenderer implements MessageRenderer {
   
    private MessageProvider messageProvider = null;
   
    public void render() {
        if (messageProvider == null) {
            throw new RuntimeException(
                    "You must set the property messageProvider of class:"
                    + StandardOutMessageRenderer.class.getName());
        }
       
        System.out.println(messageProvider.getMessage());
    }
   
    public void setMessageProvider(MessageProvider provider) {
        this.messageProvider = provider;
    }
   
    public MessageProvider getMessageProvider() {
        return this.messageProvider;
    }
}

3. MessageRenderer.java

public interface MessageRenderer {

    public void render();
   
    public void setMessageProvider(MessageProvider provider);
    public MessageProvider getMessageProvider();
}

4. HelloWorldMessageProvider.java

public class HelloWorldMessageProvider implements MessageProvider {

    public String getMessage() {

        return "Hello World!";
    }

}

5. MessageProvider.java

public interface MessageProvider {

    public String getMessage();
}


Summary

In this exercise,  you have built and run a ready-to-build-and-run "HelloWorldDecoupledInterface" sample application.

                                                                                                                        return to the top


Exercise 5: Build and run "HelloWorldDecoupledInterfaceWithFactory" sample application



(5.1) Open, build, and run "HelloWorldDecoupledInterfaceWithFactory" sample application

1. Open HelloWorldDecoupledInterfaceWithFactory NetBeans project. 

2. Build and run HelloWorldDecoupledInterfaceWithFactory project. 


(5.2) Look under the hood of the "HelloWorldDecoupledInterface" sample application


1. HelloWorldDecoupledWithFactory.java

public class HelloWorldDecoupledWithFactory {

    public static void main(String[] args) {
        MessageRenderer mr = MessageSupportFactory.getInstance().getMessageRenderer();
        MessageProvider mp = MessageSupportFactory.getInstance().getMessageProvider();
        mr.setMessageProvider(mp);
        mr.render();
    }
}

2. MessageSupportFactory.java

import java.io.FileInputStream;
import java.util.Properties;

public class MessageSupportFactory {
   
    private static MessageSupportFactory instance = null;  
    private Properties props = null;
    private MessageRenderer renderer = null;
    private MessageProvider provider = null;
   
    private MessageSupportFactory() {
        props = new Properties();
       
        try {
            props.load(new FileInputStream("msf.properties"));
           
            // get the implementation classes
            String rendererClass = props.getProperty("renderer.class");
            String providerClass = props.getProperty("provider.class");
           
            renderer = (MessageRenderer) Class.forName(rendererClass).newInstance();
            provider = (MessageProvider) Class.forName(providerClass).newInstance();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
   
    static {
        instance = new MessageSupportFactory();
    }
   
    public static MessageSupportFactory getInstance() {
        return instance;
    }
   
    public MessageRenderer getMessageRenderer() {
        return renderer;
    }
   
    public MessageProvider getMessageProvider() {
        return provider;
    }
   
}

3. msf.properties

# msf.properties
renderer.class=StandardOutMessageRenderer
provider.class=HelloWorldMessageProvider



Summary

In this exercise,  you have built and run a ready-to-build-and-run "HelloWorldDecoupledInterfaceWithFactory" sample application.

                                                                                                                        return to the top


Exercise 6: Build and run "HelloWorldSpring" sample application

This exercise is the first time you are going to do refactoring using Dependency Injection (DI) feature of the Spring framework.


(6.1) Open, build, and run "HelloWorldSpring" sample application

 
1. Open HelloWorldSpring NetBeans project. 



2. Add Spring framework library jar files and commons logging library files to the project.




Figure-6.10: Remove broken references

Figure-6.11: Add jar files to the project


Figure-6.12: Add Spring jar files.

Figure-6.13: Add commons logging jar files
Note that you don't need all these jar files for this simple application but for the sake of simplifying this exercise, you are adding them all to the project's classpath.

3. Build and run HelloWorldSpring project. 


(6.2) Look under the hood of the "HelloWorldSpring" sample application


1. HelloWorldSpring.java

import java.io.FileInputStream;
import java.util.Properties;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.PropertiesBeanDefinitionReader;

public class HelloWorldSpring {
   
    public static void main(String[] args) throws Exception {
       
        // get the bean factory
        BeanFactory factory = getBeanFactory();
       
        MessageRenderer mr = (MessageRenderer) factory.getBean("renderer");
        MessageProvider mp = (MessageProvider) factory.getBean("provider");
       
        mr.setMessageProvider(mp);
        mr.render();
    }
   
    private static BeanFactory getBeanFactory() throws Exception {
        // get the bean factory
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
       
        // create a definition reader
        PropertiesBeanDefinitionReader rdr = new PropertiesBeanDefinitionReader(
                factory);
       
        // load the configuration options
        Properties props = new Properties();
        props.load(new FileInputStream("beans.properties"));
       
        rdr.registerBeanDefinitions(props);
       
        return factory;
    }
}

2. beans.properties

# beans.properties
renderer.class=StandardOutMessageRenderer
provider.class=HelloWorldMessageProvider

Summary

In this exercise,  you have built and run a ready-to-build-and-run "HelloWorldSpring" sample application.

                                                                                                                        return to the top


Exercise 7: Build and run "HelloWorldSpringWithDI" sample application



(7.1) Open, build, and run "HelloWorldSpringWithDI" sample application

 
1. Open HelloWorldSpringWithDI NetBeans project. 

2. Add Spring framework library files as described above.

3. Build and run HelloWorldSpringWithDI project. 


(7.2) Look under the hood of the "HelloWorldSpringWithDI" sample application


1. HelloWorldSpringWithDI.java

import java.io.FileInputStream;
import java.util.Properties;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.PropertiesBeanDefinitionReader;

public class HelloWorldSpringWithDI {
   
    public static void main(String[] args) throws Exception {
       
        // get the bean factory
        BeanFactory factory = getBeanFactory();
       
        MessageRenderer mr = (MessageRenderer) factory.getBean("renderer");
        mr.render();
    }
   
    private static BeanFactory getBeanFactory() throws Exception {
        // get the bean factory
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
       
        // create a definition reader
        PropertiesBeanDefinitionReader rdr = new PropertiesBeanDefinitionReader(
                factory);
       
        // load the configuration options
        Properties props = new Properties();
        props.load(new FileInputStream("beans.properties"));
       
        rdr.registerBeanDefinitions(props);
       
        return factory;
    }
}

2. beans.properties

#Message renderer
renderer.class=StandardOutMessageRenderer
#  Ask Spring to assign provider bean to the MessageProvider property
#  of the Message renderer bean
renderer.messageProvider(ref)=provider

#Message provider
provider.class=HelloWorldMessageProvider

Summary

In this exercise,  you have built and run a ready-to-build-and-run "HelloWorldSpringWithDI" sample application.

                                                                                                                        return to the top


Exercise 8: Build and run "HelloWorldSpringWithDIXMLFile" sample application

.


(8.1) Open, build, and run "HelloWorldSpringWithDIXMLFile" sample application

 
1. Open HelloWorldSpringWithDIXMLFile NetBeans project. 

2. Add Spring framework library files as described above.
3. Build and run HelloWorldSpringWithDIXMLFile project. 


(8.2) Look under the hood of the "HelloWorldSpringWithDIXMLFile" sample application


1. HelloWorldSpringWithDIXMLFile.java

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.FileSystemResource;

public class HelloWorldSpringWithDIXMLFile {

    public static void main(String[] args) throws Exception {

        // get the bean factory
        BeanFactory factory = getBeanFactory();
        MessageRenderer mr = (MessageRenderer) factory.getBean("renderer");
        mr.render();
    }

    private static BeanFactory getBeanFactory() throws Exception {
        // get the bean factory
        BeanFactory factory = new XmlBeanFactory(new FileSystemResource(
                "beans.xml"));

        return factory;
    }
}

2. beans.xml

<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <bean id="renderer" class="StandardOutMessageRenderer">
        <property name="messageProvider">
            <ref local="provider"/>
        </property>
    </bean>
    <bean id="provider" class="HelloWorldMessageProvider"/>
</beans>

Summary

In this exercise,  you have built and run a ready-to-build-and-run "HelloWorldSpringWithDIXMLFile" sample application.

                                                                                                                        return to the top


Exercise 9: Build and run "HelloWorldSpringWithDIXMLFileConstructorArgument" sample application



(9.1) Open, build, and run "HelloWorldSpringWithDIXMLFileConstructorArgument" sample application

 
1. Open HelloWorldSpringWithDIXMLFileConstructorArgument NetBeans project. 

2. Add Spring framework library files as described above.

3. Build and run HelloWorldSpringWithDIXMLFileConstructorArgument project. 


(9.2) Look under the hood of the "HelloWorldSpringWithDIXMLFileConstructorArgument" sample application


1. HelloWorldSpringWithDIXMLFileConstructorArgument.java

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.FileSystemResource;

public class HelloWorldSpringWithDIXMLFileConstructorArgument {

    public static void main(String[] args) throws Exception {

        // get the bean factory
        BeanFactory factory = getBeanFactory();
        MessageRenderer mr = (MessageRenderer) factory.getBean("renderer");
        mr.render();
    }

    private static BeanFactory getBeanFactory() throws Exception {
        // get the bean factory
        BeanFactory factory = new XmlBeanFactory(new FileSystemResource(
                "beans.xml"));

        return factory;
    }
}

2. beans.xml

<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <bean id="renderer" class="StandardOutMessageRenderer">
        <property name="messageProvider">
            <ref local="provider"/>
        </property>
    </bean>
    <bean id="provider" class="ConfigurableMessageProvider">
        <constructor-arg>
            <value>This is a configurable message</value>
        </constructor-arg>
    </bean>
</beans>

3. ConfigurableMessageProvider.java

public class ConfigurableMessageProvider implements MessageProvider {

    private String message;

    public ConfigurableMessageProvider(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

}

Summary

In this exercise,  you have built and run a ready-to-build-and-run "HelloWorldSpringWithDIXMLFileConstructorArgument" sample application.

                                                                                                                        return to the top



Homework Exercise (for people who are taking Sang Shin's "Java EE Programming online course")


1. The homework is to modify the HelloWorldSpringWithDIXMLFile project as described below.  (You might want to create a new project by copying the HelloWorldSpringWithDIXMLFile project.  You can name the homework project in any way you want but here I am going to call it MyHelloWorldSpringWithDIXMLFile.)
2. Send the following files to j2eehomeworks@sun.com with Subject as J2EEHomework-springhelloworld.

                                                                                                                    return to the top