Sunday, 10 April 2011

Spring's Java Based Dependency Injection

One of the new features of Spring 3 is the ability to configure your good old POJOS using a new Java based dependency injection (DI) feature. This was formerly known as Spring JavaConfig and, since Spring 3 now only supports JSE 5 and above, it’s been incorporated into the core Spring Framework. This is an annotation based DI where the beans or POJOs that you’re linking together remain untouched by annotations and, being Java based, you get a lot more programmatic control over object instantiation.

The big-idea behind all this is the notion that you write your own factory class instead of configuring a whole bunch of XML, which should save you time as gluing together objects using XML is always error prone through typos.

This code sample demonstrates how to use Java based DI using a simple example of linking together two objects (Object_A and Object_B) via their respective interfaces (Interface_A and Interface_B).

The first thing to do is to create a factory class:

@Configuration
public class AppConfig {

 
private final Interface_B commonBean = new Object_B();

 
/**
   * Factory method that creates a new Object_A and returns its interface after wiring A and
   * B together.
   *
   *
@return A new object
   */
 
@Bean
 
public Interface_A interfaceAService() {
   
return new Object_A(commonBean);
 
}

 
/**
   * Factory method that creates a new Object_B and returns its interface.
   *
   *
@return A new object
   */
 
@Bean
 
public Interface_B interfaceBService() {
   
return commonBean;
 
}

}

I’m not going to show the code for objects A and B as it’s straight forward and UNTOUCHED by Spring.

In order to load and use this factory, you need to use the new AnnotationConfigApplicationContext.

public class JavaBasedDIMain {

 
/**
   * This is the main method - here we do two things, the main thing being to use the
   * AnnotationConfigApplicationContext to load AppConfig.class. Next we need to get the bean
   * and call the methods.
   *
   *
@param args
   *            not Used
   */
 
public static void main(String[] args) {

   
// Create the appropriate type of application context
   
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);

   
// Get the bean by type as there's only one
   
Interface_A serviceA = ctx.getBean(Interface_A.class);
   
// got the bean - so call our business method.
   
serviceA.businessMethod();

   
// Get hold of a B service
   
Interface_B serviceB = ctx.getBean(Interface_B.class);
    serviceB.businessMethod_B
();

 
}

}

If you’re used to using the older <bean /> XML style of dependency injection, then the XML config below is equivalent to our factory class.
<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="interfaceA" class="Object_A">
  <property name="interfaceB">
   <ref local="interfaceB"/>
  </property>
 </bean>

 <bean id="interfaceB" class="Object_B"/>

</beans>
There are some advantages to using Java based DI:

  • It allows you to use compile time type checking.
  • It’s quicker to setup. For example, if you mis-spell a class name you’ll know about it long before you run your application - which means that you use the compiler to spot wiring errors
  • It’s more flexible than using XML: after all the AppConfig.class is just Java, so you can do what you want with it.
  • IDEs can handle Java more easily than XML, so finding an modifying your factory code is easier than trawling through pages of XML.

On the down-side of this you should consider that:

  • As of now (Spring 3.0), you still need XML files for configuring certain Spring features, such as transactions - although this should change in Spring 3.1 or 3.2
  • In certain circumstances, Java DI may be more verbose that XML.

Note that in this example objects A and B are wired together using their Java types, but you can use string identifiers to cope with those few cases where you have more than one instance of a particular class. If your project needs to instantiate lots of instances of a class, or several instances of all your classes, then XML config is the appropriate choice of DI.

As a rule of thumb: “if you own a class, annotate it”.

No comments: