Monday, 6 June 2011

Using Spring's ApplicationContextAware Interface

I’ve been trying to think of reasons why you shouldn’t widely use Spring’s ApplicationContextAware interface when constructing your Spring beans. On the surface it seems like rather a bad idea, but with the release of Spring 3, my last reservation has disappeared.

For example, making your bean ApplicationContextAware simplifies setting up complex beans with multiple injection dependencies because it removes the need specify a long list of constructor arguments or setter methods. Furthermore, Spring 3.x’s use of generics means that when using this technique type compile time type checking is done.
MyBean myBean = ctx.getBean(MyBean.class);
The same can’t be said about Spring 2.x as that required lots of casting and only provided run-time type checking:
MyBean myBean = (MyBean)ctx.getBean(“MyBean”);
Using ApplicationContextAware adds a dependency between your POJO and the Spring classes, but is this a bad thing? If you’re using Spring to build your context, then why not use it simplify your dependency injection. If you plan to re-use your class without Spring then don’t use ApplicationContextAware.

Using ApplicationContextAware also means that if, in time, your bean needs enhancing to reference a new bean then you don’t need to change any of your bean’s method signatures or external configuration; hence, making your code-base more robust.

On the downside, I had thought that this technique may complicate Unit Testing, but I’m now really not sure that that’s true,

Implementing ApplicationContextAware is simple and follows the same pattern used by BeanNameAware in that during the loading of your Spring context, Spring will reflectively test your bean and if if implements ApplicationContextAware then it’ll call your bean’s setApplicationContext(ApplicationContext ctx) method. When it does, all you need to do is to store that method’s input argument in an instance variable and you’ll have a reference to the ApplicationContext for your bean’s lifetime.

The code below demonstrates how to implement ApplicationContextAware: note that the simple business method implementation demonstrates its usefulness in referencing additional Spring beans or by using the ApplicationContext’s event functionality.

public class ApplicationContextAwareBean implements ApplicationContextAware {

 
private ApplicationContext ctx;

 
/**
   *
@see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
   */
 
@Override
 
public void setApplicationContext(ApplicationContext ctx) throws BeansException {

   
this.ctx = ctx;
 
}

 
public void doBusinessMethod(String arg) {

   
System.out.println("In doBusinessMethod() with arg: " + arg);

   
// Use the context within your business methods
   
String str = ctx.getBean(String.class);
    System.out.println
("Loaded bean of type String with value: " + str);

   
// This is a better use of the context from within your bean
   
ctx.publishEvent(new MyDummyEvent("My Event"));
 
}
}

The XML config for the above bean is:

<?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">
    
     <!-- Create an application context aware bean -->
 <bean id="myBean" class="example_3_spring_aware.application_context_aware.ApplicationContextAwareBean"/>

 <!-- Any old other bean -->
 <bean id="myStringBean" class="java.lang.String">
  <constructor-arg value="Hello World"/>
 </bean>
</beans>

…and a sample test main() code is:

  public static void main(String[] args) {

   
ApplicationContext ctx = new FileSystemXmlApplicationContext(
       
Constants.PATH_TO_RESOURCES + "example3_ApplicationContextAware.xml");

    ApplicationContextAwareBean myBean = ctx.getBean
(ApplicationContextAwareBean.class);
    myBean.doBusinessMethod
("Hello Freddie");
 
}

1 comment:

Kavita Gupta said...

Nice Post....
In our application we have implemented ApplicationContextAware, but now we are moving from spring configuration to blueprint.
Is there an alternative of InitializingBean, DisposableBean, ApplicationContextAware, BeanNameAware interfaces in blueprint