Wiring Stuff Together with Spring Bean Factories

Spring BeanFactories

The BeanFactory is the heart of Spring. BeanFactories are a central registry of beans available to your application. Various beans, services, dependencies, etc. can be wired together, usually in one or more XML files, for use in your application.

The configuration of BeanFactories in XML and simply looks like this:

<beans>
  <bean></bean>
  <bean></bean>
  <bean></bean>

</beans>

These beans are treated like singletons (unless configured otherwise). Beans wired up in a BeanFactory can be any plain old Java object (POJOs). There is no need to implement Spring interfaces or extend any proprietary abstract classes. Having a convenient place to register all services for use in your application is a nice thing.

Spring shows its real power when you have interdependent beans. Spring encourages designing your application using interfaces and dependency injection principles. Spring BeanFactories make it easy to wire an application together that is designed in such a way.

Widgets and the WidgetDAO Interface

Before I get into any details of wiring up a BeanFactory, I’d like to develop a simple example system. For the purpose of these tutorials, I will use an almost trivial POJO named Widget and a simple DAO (data access object) interface to save, insert and retrieve Widgets called WidgetDAO.

Here is the Widget class:

/**
 * Simple bean representing a Widget
 * @author rlambert
 */
public class Widget implements Serializable
{
  private Long id;
  private String name;
  private int size;

  ... standard getters, setters, equals(), hashCode(), toString()

}

and here is the definition of the WidgetDAO interface:

/**
 * DAO interface for Widgets
 * @author rlambert
 */
public interface WidgetDAO
{
  /**
   * Returns a collection of all Widgets in the system.
   * @return java.util.Collection widgets
   */
  public Collection getWidgets();

  /**
   * Get a Widget Object given the id
   * @param id
   * @return Widget
   */
  public Widget getWidgetById(Long id);

  /**
   * Save a Widget Object, if the given Widget is not in
   * the data store, it should insert it, if it is in the
   * data store, it should update it.
   * @param widget
   */
  public Widget saveWidget(Widget widget);
}

Finally, here is an implementation of WidgetDAO. This class simply persists the Widgets in memory in a Map. Later, I will develop several other implementations using JDBC, Hibernate, etc., but for now, here is WidgetDAOMapImpl:

/**
 * Simple WidgetDAO implementation with data only stored internally
 * in memory and not persisted between restarts.
 * @author rlambert
 */
public class WidgetDAOMapImpl implements WidgetDAO
{
  private KeyGenerator keyGenerator;
  private Map widgetMap = new HashMap();

  public void setKeyGenerator(KeyGenerator keyGenerator)
  {
    this.keyGenerator = keyGenerator;
  }
  
  /**
   * returns the in-memory list of widgets
   */
  public Collection getWidgets()
  {
    return widgetMap.values();
  }

  /**
   * Gets the Widget with the given id from the in-memory storage,
   * returns null if it does not exist.
   */
  public Widget getWidgetById(Long id)
  {
    if(widgetMap.containsKey(id))
      return (Widget)widgetMap.get(id);
    else
      return null;
  }

  /**
   * Saves the Widget into the in-memory storage.
   */
  public Widget saveWidget(Widget widget)
  {
    if(widget==null)
      return null;
    if(widget.getId()==null)
    {
      widget.setId(new Long(keyGenerator.getNextKey()));
    }
    widgetMap.put(widget.getId(), widget);
    return widget;
  }
}

Note the setter for a KeyGenerator. The KeyGenerator interface simply requires a method public long getNextKey(). I added the simple key generator as an external dependency to show the concept of dependency injection and how you wire up interrelated Spring beans.

So, now, if we want to use an instance of WidgetDAOMapImpl in an application, we can wire it up in a Spring Bean XML file. Here is a simple XML file defining our instance of WidgetDAO (which, remember, will be treated like a singleton).

<?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="widgetDAO" 
        class="com.zabada.springrecipes.dao.map.WidgetDAOMapImpl">
  </bean>
</beans>

Given this XML file, we could use it to get a handle on our WidgetDAO bean with the key “widgetDAO”. But first, we must wire in the external KeyGenerator dependency. I made an implementation of KeyGenerator named KeyGeneratorImpl that adds a setter method to set an internal setting for the number of keys that each successive new key will be incremented by: public void setIncrement(int increment). (I added this to simply show setting a standard property on an XML bean definition). So now let’s wire in the KeyGenerator and set the increment to 2:

<?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="keyGenerator"
        class="com.zabada.springrecipes.dao.map.KeyGeneratorImpl">
    <property name="increment"><value>2</value></property>

  </bean>

  <bean id="widgetDAO"
        class="com.zabada.springrecipes.dao.map.WidgetDAOMapImpl">
    <property name="keyGenerator">
      <ref bean="keyGenerator"/>
    </property>
  </bean>

</beans>

The interesting thing here is the injection of the KeyGenerator on the WidgetDAOImpl.
When the Application Context is initialized, behind the scenes what really happens is something like this:

KeyGeneratorImpl keyGenerator = new KeyGeneratorImpl();
keyGenerator.setIncrement(2);
// put keyGenerator in the Context with under "keyGenerator"

WidgetDAOMapImpl widgetDAO = new WidgetDAOMapImpl();
//here comes the magic...
widgetDAO.setKeyGenerator(keyGenerator);
// put widgetDAO in the Context with under "widgetDAO"

Please note that the order of the definition of the beans does not matter. We could have put the “keyGenerator” bean after the the “widgetDAO” bean.

Getting a Handle on the BeanFactory

There are several ways to get a hold of a BeanFactory. I will discuss two of the most common ways (each are implementations of the ApplicationContext interface):

  • ClassPathXmlApplicationContext – loads a context from one or more XML files in the classpath.
  • XmlWebApplicationContext – loads a context from an XML file from within a webapp and configured via the web.xml

ClassPathXmlApplicationContext

One approach is to use the ClassPathXmlApplicationContext. In an application, if the above XML is defined in a file called applicationContext.xml and the file is in our classpath, we can get a hold of our WidgetDAO like this:

  ApplicationContext context = 
      new ClassPathXmlApplicationContext("/applicationContext.xml");
  WidgetDAO widgetDAO = (WidgetDAO) context.getBean("widgetDAO");

Typically you would want to structure your application to only call new ClassPathXmlApplicationContext(“/applicationContext.xml”) once.

Note that you can have your BeanFactory span many XML files, and then load the files using wildcards in the file parameter, i.e. new ClassPathXmlApplicationContext(“/zabada-*.xml”) will load up all files in the classpath named zabada-*.xml. If you wire up beans accross many XML files, you can still reference beans defined in other files via the <ref bean=”KEY”/> syntax.

Wiring a Bean Factory Into a Webapp

The easiest and most typical thing to do for a webapp is to name the config file applicationContext.xml, place it in your WEB-INF/ directory and then add the following to your web.xml:

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
     http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
     version="2.4">
...
<!--
- Loads the root application context of this web app at startup,
- by default from "/WEB-INF/applicationContext.xml". Use
- WebApplicationContextUtils.
-     getWebApplicationContext(servletContext)
- to access it anywhere in the web application, 
-    outside of the framework.
-
- The root context is the parent of all servlet-specific contexts.
- This means that its beans are automatically available in 
- these child contexts,
- both for getBean(name) calls and (external) bean references.
-->
    <listener>
      <listener-class>
        org.springframework.web.context.ContextLoaderListener
      </listener-class>

    </listener>
...
</webapp>

When you do this, if you are using Spring MVC (discussed in a separate tutorial), you can define your controllers in the applicationContext.xml and then inject the dependencies of the controllers into them. There is also a mechanism to wire in dependencies into Struts Actions using proxies (this is also discussed in a latter tutorial). If you have wired in all of the controllers or Actions into your config, you probably won’t need to get a handle directly on the the ApplicationContext. But if you do, you can use WebApplicationContextUtils which has convenience methods to retrieve the root WebApplicationContext for a given ServletContext.

If you do not want to name the configuration file “applicationContext.xml” you can do something like this:

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
         http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
         version="2.4">
  <!--
  - Location of the XML file that defines the root context
  - Applied by ContextLoaderListener.
  -->
  <context-param>
    <param-name>contextConfigLocation</param-name>

    <!--
    THE classpath: INDICATES TO LOOK IN THE CLASSPATH,
    SO IN A WEBAPP YOU COULD PLACE THE CONFIG FILE IN 
    context/WEB-INF/classes/
    -->
    <param-value>
      classpath:/zabada-config.xml
    </param-value>
    <!--
    ALTERNATIVELY, W/O THE "classpath:", SPRING WILL LOOK
    FOR THE CONFIG RELATIVE TO THE CONTEXT OF THE WEBAPP, 
    SO YOU COULD DO THIS:
    <param-value>
      /WEB-INF/zabada-config.xml
    </param-value>

    -->
  </context-param>

<!--
- Loads the root application context of this web app at startup,
- by default from "/WEB-INF/applicationContext.xml". Use
- WebApplicationContextUtils.
-   getWebApplicationContext(servletContext)
- to access it anywhere in the web application, outside of 
- the framework.
- The root context is the parent of all servlet-specific contexts.
- This means that its beans are automatically available in these 
- child contexts, both for getBean(name) calls and (external) 
- bean references.
-->
    <listener>
      <listener-class>
       org.springframework.web.context.ContextLoaderListener
      </listener-class>

    </listener>

...

</webapp>

Summary

Wiring up all dependencies of an application is easy with Spring beans. Spring encourages using interfaces and dependency injection to design your application.

Further Reading

Next: Spring MVC Basics