JavaWiring Java Applications with Spring

Wiring Java Applications with Spring

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

The Spring Framework

In 2002, J2EE expert Rod Johnson published an influential book entitled Expert One-on-One J2EE Design and Development. This book encouraged readers to take a more pragmatic approach to developing J2EE applications, rather than just assuming standard technology, such as Enterprise JavaBeans (EJBs), were always the best solution to the problem. Rod suggested that there was a rather wide gap between the promise of technology such as EJBs (simpler development, improved performance, and so forth) and what the technology was actually delivering. To demonstrate solutions to common J2EE programming problems, the book introduced code examples using a framework that Rod Johnson had authored based upon his own experiences. The Spring framework is essentially the product of improvements made to this framework first presented in the book, along with additional features inspired by ideas from existing frameworks. A vibrant developer community and subsequent book releases have followed, resulting in a new way of thinking about J2EE.

This article is intended for those who are new to the Spring framework, but would like to know more about it. The Spring framework addresses a variety of topics. This article will focus on what is perhaps the most important, and useful, aspect of the framework: Inversion of Control.

Spring, the IOC Container

Spring is often called an ‘IOC Container.’ IOC stands for Inversion of Control. IOC is a design pattern that alleviates application objects from the responsibility of creating, and managing their dependencies. Instead, these application objects are free to concentrate solely on fulfilling their business purpose. Martin Fowler, respected J2EE author, coined the phrase ‘Dependency Injection’ as a more descriptive title to describe this behavior. ‘Inversion of Control’ and ‘Dependency Injection’ are often used interchangeably when talking about Spring. With Spring, classes no longer need to look up, then create, their own dependencies. Instead, the container does it for you. Consider the problems associated with objects assembling themselves, through code like the following:

public interface Drive {
    public void read();
    ...
}
public class HardDrive extends Drive {
    public void read();
    ...
}

public class Computer {
   private Drive drive;

   //Other properties...
   ...

   //Constructor
   Computer() {
        drive = new HardDrive();
        drive.read();
   }
}

This approach is far from ideal because it couples you to a specific implementation. What if you wanted to swap out the current drive for another type? You would have to modify the Computer class. It is therefore always a good idea to mask such implementation details, preferably coding to interfaces. In the past, several methods have emerged to avoid hard coding an implementation. These approaches usually involve using design patterns such as Service Locator and Java Naming and Directory Interface (JNDI) lookups (which you’ll learn about in a bit).

In addition to coding to interfaces rather than a specific implementation, it’s a good idea to limit the number of object instances as well as who is responsible for creating those instances. Developers often turn to the Singleton design pattern, and custom object factories to address these issues.

As we proceed, I hope to convince you that a Spring ‘ApplicationContext’ offers a superior approach to all of the aforementioned solutions, making it easy for you to develop applications with less code, less coupling, and, in general, less problems!

Wiring Dependencies with an ApplicationContext

If you work with Spring, you will most surely meet the ApplicationContext. A Spring ApplicationContext is essentially a registry of application objects. The ApplicationContext object actually extends a Spring class called BeanFactory. In reality, BeanFactory provides a good deal of the functionality developers often associate with an ApplicationContext. A BeanFactory reads configuration data from a file typically, but not always, formatted in XML, and creates the types of objects desired. It manages dependencies between objects and provides a mechanism to control their lifecycles. Spring is an ‘interface-driven’ framework and ApplicationContext (which includes BeanFactory) implements numerous interfaces that define its behavior.

In trivial applications, a BeanFactory may fulfill your needs. However, ApplicationContext adds a rich layer of functionality above and beyond BeanFactory, including support for Aspect Oriented Programming (AOP), internationalization, transaction support, and event handling. The feature set is pretty extensive. Most of the behavior you will explore comes from BeanFactory. However, most applications will use ApplicationContext to take advantage of its extended functionality.

As a means of introduction, what follows are a series of examples designed to highlight the use of Spring’s ApplicationContext. The examples will involve a sample program that manages client/sales representative relationships. There will be little in the way of functionality, just enough to get the point across.

First, consider two domain objects: SalesRep and Client. These objects represent a sales person and a client assigned to a specific sales person:

public class SalesRep {
   private Integer id;
   private String name;

   //Clients assigned to SalesRep
   private Set clientSet;

   //getter/setter methods....
}

public class Client {
   private Integer id;
   private Integer id companyId;
   private String contactName;
   ...

   //Which rep is assigned to the client?
   private SalesRep salesRep;

   //getter/setter methods....
}

As you might expect, SalesRep contains a Set of clients, and Client contains a reference to a SalesRep. Typically, these types of objects represent data from a database and are created as needed by the application’s users. In other words, there can be numerous instances floating around the system at any time.

Along with these objects, however, there is a need for objects to manage the business functions that operate on the domain instances. Two commonly used objects include the Session Facade and Data Access Object (often simply referred to as DAO). Basically, a Facade consolidates all the business services your application provides to its users. It serves as a gateway to business logic. A Data Access Object conceals the complexities of dealing with a data source. A primary goal of both is to avoid dependencies upon a specific implementation. In a typical scenario, a user invokes a facade method, and the facade in turn will call upon a data access object to perform some of the work that involves the database. As you will see, it is these types of objects that you will most likely want a Spring ApplicationContext to manage. Here are snippets of your Facade and DAO, including interfaces and their implementations.

//Session Facade Interface
public class SalesManagerFacade {
   SalesManagerDAO salesManagerDAO;

   public void assignClientToSalesRep(SalesRep salesRep,
                                      Client newClient);
   ...
}

//Facade Implementation
public class SalesManagerDefaultImpl(SalesManagerDAO) {

   private SalesManagerDAO salesManagerDAO;

   public void SalesManagerDefaultImpl(SalesManagerDAO
                                       salesManagerDAO) {
       this.salesManagerDAO = salesManagerDAO;
   }

   public void assignClientToSalesRep(SalesRep salesRep,
                                      Client newClient) {
       this.salesManagerDAO.addClient(SalesRep salesRep,
                                      Client newClient);
   }
   ...
}

//DAO Interface
public class SalesManagerDAO {
   public String setImplType();
   public void addClient(salesRep, newClient);
   ...
}
//DAO Implementation using JDBC API
public class SalesManagerJdbcDAO {

   private String implType;
   private Map dbProperties;

   public String setImplType(String implType) {
      this.implType = implType;
      return this.implType;
   }

   public String setDbProperties(Map dbProperties) {
      this.dbProperties = dbProperties;
   }

   public void addClient(salesRep, newClient) {
      Connection conn = DbUtils.getConn();
      //perform database work via JDBC...
   }
   ...
}

Note that the Facade implementation contains a reference to the DAO so that it may invoke DAO methods. Also, there is no reason why all application users can’t share a single instance of each of these objects. The DAO implementation contains a Java Collection to hold connection properties and a Java String to specify the current implementation type. Keep in mind that this is purely for purposes of the demonstration and not to suggest this is the ideal way to store this information.

As mentioned, interfaces help to keep your design flexible. You may use JDBC today, and later move to an object-relational mapping (ORM) tool later. Likewise, you may use a different implementation approach for your facade. The impact of such changes to your system should be minimal. So, a common problem is how can you designate your implementation for the interfaces you have defined? I mentioned commonly used options at the beginning of this article, with JNDI often playing a role. With JNDI, you can specify an implementation object’s name in a <resource-ref> in a descriptor file. This way, implementation changes should not require code changes. Here’s an example of what looking up a DAO implementation via JNDI might look like:

try {
   Context initContext = new InitialContext();
   Context envContext  = (Context)initContext.lookup("java:/comp/env");
   SalesManagerDAO sm  =
      (SalesManagerDAO)envContext.lookup("test/salesManagerJdbcDAO");
}
catch (Exception e) { 
  throw new Exception(e); 
}

You could put this type of code in a ServiceLocator class to avoid repeating yourself every time you need an object. By doing this, you are gaining some flexibility, but you are still required to write code to obtain (as opposed to having the container retrieve it automatically for you) the instance. Also, this type of code tends to be a bit verbose. By using an ApplicationContext for the same purpose, the code would look something like this:

ApplicationContext ctx =
   new ApplicationContext(new FileInputStream("application-context.xml");
   SalesManagerDAO sm = (SalesManagerDAO)ctx.getBean
                        ("salesManagerJdbcDAO");

File applicationContext.xml is the Spring configuration file that feeds an ApplicationContext its dependency information. In the preceding example, you created an instance of the Application Context to retrieve a SalesManagerDAO bean. This is not something you would normally do because Spring provides utilities to enable you to retrieve an existing context in your code. You will look at this later. For now, move on to some ApplicationContext examples.

ApplicationContext Examples

To review, you have two domain objects: SalesRep and Client, as well as two singleton objects that implement the Facade and DAO design patterns. In applicationContext.xml, here are the entries for your facade and DAO objects:

   <!-- facade implementation -->
   <bean id="salesManager" class="examples.SalesManagerDefaultImpl">
      <!--dao member of facade-->
         <constructor-arg><ref bean="salesManagerDAO"/>
         </constructor-arg>
   </bean>

   <!--dao implementation -->
   <bean id="salesManagerDAO" class="examples.SalesManagerJdbcDAO">

      <!--dao implementation type -->
      <property name="implType" value="JDBC"/>

         <!--our Map property-->
         <property name="dbProperties">
            <map>
               <entry key="driverClass">
                  <value>org.hsqldb.jdbcDriver</value>
               </entry>
               <entry key="url">
                  <value>jdbc:hsqldb:hsql://localhost:9002</value>
               </entry>
               <entry key="username">
                  <value>sa</value>
               </entry>
               <entry key="password">
                  <value><null/></value>
               </entry>
            </map>
         </property>
   </bean>

This markup results in the creation of facade and DAO instances when the Spring ApplicationContext is created at runtime. By default, classes are created as singletons, meaning there is a single instance shared by all users. There is an attribute called ‘singleton’ that could have been explicitly set to “true”, but it’s not necessary. For each bean, properties can have initial values assigned via the configuration file, as is the case for property implType. Spring knows how to convert values specified in the markup for basic types like int, float, String, and so on. The <null/> element can be used to give an object an initial value of null.

You also can create your own custom PropertyEditors to convert initial values, specified as text in the configuration file, for more complex objects. Spring gives you the ability to initialize Java Collections as well. In the above markup, you are populating a Map, called dbProperties, with data. It should be noted that Spring gives you a more flexible alternative than what is shown here for specifying properties by reading an external properties file.

A Spring ApplicationContext can assign a bean a dependency using another object in the same file. Dependent objects defined elsewhere in the document are referenced with the <ref-bean> tag. In this example, an instance of SalesManagerJdbcDAO is created. Then, an instance of SalesManagerDefaultImpl is created and has its salesManagerDAO property assigned the SalesManagerJdbcDAO instance (<ref bean=”salesManagerDAO”/>).

Essentially, there are two ways to ‘inject’ dependencies in Spring: through a constructor or a setter method. These mechanisms are often termed ‘constructor-based dependency injection’ and ‘setter-based dependency injection’ respectively. The setter approach seems to be the more popular as the latter can result in ugly and complex constructors. But both are equally viable options and I use both examples here. The facade class you are using is assigned a DAO in its constructor, whereas the DAO bean has properties that are set via setter methods:

//**Facade instance**
//Constructor for constructor-based dependency injection 
public setSalesManagerDAO(SalesManagerDAO salesManagerDAO) {
   this.salesManagerDAO = salesManagerDAO;
}


//**DAO instance**
//Setter Methods for setter-based dependency injection 
public void setImplType(String implType) {
   this.ImplType = implType;
}
public void setDbProperties(Map dbProperties) {
   this.dbProperties = dbProperties;
}

There are a number of global attributes that you can set in your configuration file that will apply to all beans (and then can be overridden by individual beans). Often, these properties are simply left to their defaults, and thus not specified at all. First among these is the ‘dependency-check’ element that will force Spring to ensure all dependencies are set when beans are created. Another global attribute is ‘lazy-init’, which you can use if you do not actually want create an instance of a bean, keeping it ‘abstract’. Finally, there is an attribute called ‘autowire’. Autowire tells Spring to attempt to resolve dependencies on its own, without specific <ref-bean> directives. There are different ways to accomplish this. For example, if auto wiring by type, if object A has a property of type Object B, and Spring has an object B listed in its configuration file, it will assume that this is the object that A needs. Autowire is not a recommended feature because it may help eliminate some code but can cause real issues for all but trivial applications.

The remainder of the applicationContext configuration file creates domain objects.

<!-- a Client instance-->
<bean id="client" class="examples.Client" singleton="false"/>

<!-- a SalesRep instance-->
<bean id="salesRep" class="examples.SalesRep" singleton="false"/>

Here, you create a SalesRep and Client bean. Their singleton attributes are specified to “false”; this means that every time you request a bean of that type, you are effectively calling ‘ new() ‘ on that object. Now that you’ve wired your dependencies, you can use your ApplicationContext as a ‘registry’ to retrieve application objects as needed:

SalesManagerFacade sm = (SalesManagerFacade)ctx.getBean("salesManager");

SalesRep salesRepBob  = (SalesRep)ctx.getBean("salesRep");
Client clientJoe      = (Client)ctx.getBean("client");

sm.assignClientToSalesRep(salesRepBob,clientJoe);

The assignClientToSalesRep facade method will in turn invoke a DAO method on the SalesManagerDAO instance that the ApplicationContext assigned to it. In practice, there is less value in having Spring manage domain objects like SalesRep and Client (and most developers opt not to), but it can be useful in some situations. For instance, it would give you the opportunity to set some default values for instance variables.

If you are not building an application from scratch, but must bow to the constraints of an existing code base, you can wire dependencies using existing factory objects with Spring’s MethodInvokingFactoryBean. To do this, you simply define properties called “targetMethod” and “targetClass” to specify the name of the class and the static method to invoke to retrieve an instance.

A key benefit to creating beans via an ApplicationContext is that you have the ability to invoke ‘lifecycle’ methods on the objects. ApplicationContext (by way of extending BeanFactory) implements two lifecycle interfaces: InitializingBean and DisposableBean. So, suppose you wanted to setup a connection pool in SalesManagerJdbcDAO using the dbProperties map we specified in the configuration file. You could do this by coding an init() method on this object, and then add the following markup for the bean:

<bean id="salesManagerDAO"
      class="examples.SalesManagerJdbcDAO"
      init-method="init">

After the bean has been instantiated, meaning all properties have been set, Spring automatically invokes the init-method ‘init()’ for you. Likewise, if you wanted to dispose of the resources by invoking a destroy() method, you could do so by adding an additional element:

<bean id="salesManagerDAO"
      class="examples.SalesManagerJdbcDAO"
      init-method="init"
      destroy-method="destroy">

Building on the connection pool scenario, suppose you decided that you would rather not add these lifecycle methods directly to salesManagerDAO, but prefer to externalize those services as a separate class. You first write this Java class:

//Initialize and Destroy the DAO
public class DaoConfigurer() {

   public void init() {
      SalesManagerDAO salesManagerDAO =
         (SalesManagerDAO)ctx.getBean("salesManagerDAO");
       Map dbProperties = salesManagerDAO.getDbProperties();
      //perform initialization work...
      ...
   }

   public void destroy() {
      ...
   }
}

As you’ve seen, Spring automatically detects and coordinates the initialization of dependencies specified with <ref-bean>. However, DaoConfigurer does not have a reference to the DAO instance. Rather, it obtains a reference from the ApplicationContext inside the init method. Unless something is done to prevent it, an error may result if the ApplicationContext attempts to create DaoConfigurer before it creates the DAO bean. Spring’s solution to this problem is the <depends-on> tag. Essentially, this tag tells Spring to stop what it is doing and instantiate the dependant object first. Here’s the correct entry for this in applicationContext.xml:

<bean id="daoConfigurer"
      class="examples.DaoConfigurer"
      <depends-on="salesManagerDAO"/>
      init-method="init"
      destroy-method="destroy">

Although it’s beyond the scope of this article, the ApplicationContext provides many other features. One of these is the capability to specify bean ‘post processors’ to provide a callback mechanism to Spring-managed beans, after they have been created. These callbacks enable you to do various things, such as perform additional ‘initialization’ tasks after a bean’s instantiation. One example of a bean post processor is the PropertyPlaceHolderConfigurer that allows you to replace bean values with those specified in a properties file.

Last, it was mentioned that Spring provides utilities for obtaining the ApplicationContext singleton for use in your code. Unlike JNDI, Spring doesn’t tie you to J2EE. You can use Spring in just about any Java-related project. However, if you are writing a J2EE application, you can make use of Spring’s ContextLoader to access your ApplicationContext registry. This can be achieved by adding a listener, ContextLoaderListener, to a web.xml file:

<listener>
   <listener-class>
      org.springframework.web.context.ContextLoaderListener
   </listener-class>
</listener>

An additional <context-param>, named contextConfigLocation, may be added to specify the location of your ApplicationContext’s configuration file. It is only necessary if the file is somewhere other than /WEB-INF/applicationContext.xml, which is where it looks by default. You also split may your configuration data among multiple files. In this case, simply delimit the list of files in contextConfigLocation. Once you have configured web.xml, there are a number of ways to obtain the context after application startup. For example, if you are using the Struts framework, Spring provides an ActionSupport class that extends Struts Action. ActionSupport contains a method called getWebApplicationContext() that returns the ApplicationContext for your use.

Conclusion

This article provided an introduction to the Spring Framework. More specifically, an introduction to Spring’s most powerful feature—its ability to wire applications through Inversion of Control. With Spring, it is easy to create an application that is both robust and flexible to future changes. Please keep in mind that Spring is much more than just an Inversion of Control container and offers a wide array of features to support enterprise development. You will find extensive documentation at the Spring Web site to assist you in your work.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories