Dependency Injection with Spring

763608fe4b09e466e0398762d27396a8

In previous posts, we’ve discussed a important programming model known as Dependency Injection, and promised that the Spring Framework is an excellent tool for implement it.  Here’s how.

Spring

The Spring Framework is a fairly expansive set of libraries, processes, and techniques design to accelerate the development and maintenance of modern enterprise software systems.  Spring is often considered an alternative to traditional Java Enterprise Edition (JEE) Enterprise Java Beans (EJBs).

Spring supports a variety of functions required for enterprise class applications.  These include:

  • Core containers to support Dependency Injection (DI), Aspect Oriented Programming (AOP), and context management.
  • Facilities for user authentication and authorization.
  • Data access for relational, NoSQL, and Graph databases.
  • Web-based Model View Controller (MVC) servlets.
  • SOAP and RESTful Web Services.

For this post, we’ll focus on the core contains for DI and context management.

Hello World

In our post on DI, we introduced a simple example to illustrate the design and motivation of Dependency Injection.  We started with the traditional first application, shown in figure 1.

/**
 * Figure 1:  HelloWorld.java
 * 
 * Simple application.
 */

package net.proloquor.learning.hello1;

public class HelloWorld {
   public static void main(String[] args) {
      System.out.println("Hello, World.");
   }
}

After a few iterations, we created separate Java interfaces and classes to 1) provide a distinct message and 2) render it to arbitrary destinations.  Our HelloWorld application then instantiated the 2 required classes, using a custom Factory class, and ran the required function.  Our new HelloWorld application then looked like that shown in figure 2.

/**
 *  Figure 2: HelloWorld.java
 *
 *  HelloWorld application using class factory.
 */
package net.proloquor.learning.hello4;

import net.proloquor.learning.hello3.MessageProvider;
import net.proloquor.learning.hello3.MessageRenderer;

public class HelloWorld {

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

The MessageSupportFactory used here is custom created for the HelloWorld app, but pulls configuration data from a java.utils.Properties file to allow future changes without recompilation.  This illustrated the core characteristics of DI.

Hello World, using Spring

Figure 3 shows a HelloWorld application using a Spring ApplicationContext to manage its classes.

/**
 *  Figure 3: HelloWorld.java
 *
 *  Dependency Injection using Spring.
 */
package net.proloquor.learning.hello5;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import net.proloquor.learning.hello3.StandardOutMessageRenderer;
import net.proloquor.learning.hello3.MessageRenderer;

public class HelloWorld {

   public static void main(String[] args) {
 
   ApplicationContext context = new   
      ClassPathXmlApplicationContext("Beans.xml");
   MessageRenderer renderer = 
      (StandardOutMessageRenderer)context.getBean("renderer");
 
   renderer.render();
 }

}

Our Spring-based HelloWorld app isn’t much different that before.  Instead of using a custom factory, it creates a Spring ApplicationContext that configures the same MessageProvider and MessageRenderer class used before.  The context is then used to retrieve any class and call its methods.

Also like our custom factory, Spring’s ApplicationContext is configured by an external file that can be modified to change the behavior of the application without recompilation.  The file used for our HelloWorld app is shown in figure 4.

<!-- Figure 4: Beans.xml -->

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://www.springframework.org/schema/beans   
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id="renderer" 
      class="net.proloquor.learning.hello3.StandardOutMessageRenderer">
      <property name="MessageProvider" ref="provider"></property>
   </bean>
 
   <bean id="provider" 
      class="net.proloquor.learning.hello3.HelloWorldMessageProvider">   
   </bean>
</beans>

The Beans.xml file defines two classes needed for this application.  The first one, “renderer”, has a “provider” as a property, and calls the providers setter to configure it automatically.  This is known as DI by getters and setters, as opposed to constructors.  There are many more configuration options available for the Beans.xml file, consult the Spring documentation for more information.

What’s Next?

We’ll cover many more aspects of Spring in subsequent posts, including security, data access, and Web support.

Leave a Reply

Your email address will not be published. Required fields are marked *