Sunday, 12 June 2011

Using Spring's DisposableBean Interface and a Shutdown Hook in Life-Cycle Management

A few days ago I demonstrated the Runtime class and covered the concept of shutdown hooks to ensure that you can cleanly tidy up external resources when your JVM closes down.

As part of the Spring context life-cycle, it’s pretty important to ensure that your Spring beans close down correctly, especially if they access external resources, and this is where the JDK’s shutdown hooks comes in handy.

There are at least two methods of ensuring that your Spring beans shutdown correctly: the method based mechanism and the interface base mechanism. This blog demonstrates how to use a shutdown hook together with the interface based mechanism.

To implement the Interface based mechanism, you need to write a Spring bean that implements the DisposableBean interface. This interface has one method: destroy(), which is called when the Spring context is closing.

To demonstrate this, we first need to write a Spring bean that implements the DisposableBean interface. In this case all we’re doing is printing out a message rather than closing some resource or other.

public class ImplementDisposableBean implements MyDisposableBeanExample, DisposableBean {

 
public void businessMethod() {

   
System.out.println("Inside - ImplementDisposableBean");
 
}

 
/**
   * This is the only method of the DisposableBean interface - called when the the bean is
   * destroyed.
   *
   * This is where you put code that closes your resources: close files, database clear-up
   * stuff etc.
   */
 
public void destroy() {

   
System.out.println("Inside destroy() - destroying the bean..");
 
}
}

…which implements the following tiny business interface:

public interface MyDisposableBeanExample {

 
/** a business method */
 
public void businessMethod();
}

The destroy() method of the code above is called when Spring’s bean factory calls its destroySingletons() method:

      factory.destroySingletons();

… and this method is called from the ShutDownClass:

  public class ShutDownClass extends Thread {

   
/** this run method is used to initiate the bean shutdown */
   
@Override
   
public void run() {

     
System.out.println("About to destroy singletons");
      factory.destroySingletons
();
      System.out.println
("Singletons destroyed");
   
}
  }

...so you can see that we're wiring together a chain of events starting with the construction of shutdown hook and ending with the destruction of your Spring bean using the DisposableBean interface.

Having picked out a few salient points from my example code, I think that the next step is to include the whole listing for clarity:

public class DisposableBeanExampleMain {

 
private static ConfigurableListableBeanFactory factory;

 
public DisposableBeanExampleMain() {

   
factory = createFactory();

    Runtime.getRuntime
().addShutdownHook(new ShutDownClass());
 
}

 
private ConfigurableListableBeanFactory createFactory() {

   
FileSystemResource resource = new FileSystemResource(Constants.PATH_TO_RESOURCES
        +
"example2-b.xml");
   
return new XmlBeanFactory(resource);
 
}

 
public void run() {

   
MyDisposableBeanExample instance = factory.getBean(MyDisposableBeanExample.class);
    instance.businessMethod
();
 
}

 
/**
   * This is the main method - here we do three things, the main thing being to use the
   * XmlBeanFactory to load the xml. Once we have a fully loaded BeanFactory, then we
   * need to get the bean and call the methods.
   */
 
public static void main(String[] args) {

   
DisposableBeanExampleMain example = new DisposableBeanExampleMain();
    example.run
();
 
}

 
/**
   * This is a simple class that is called using a Shutdown Hook - that this a thread which
   * only runs as the system is shutting down.
   */
 
public class ShutDownClass extends Thread {

   
/** this run method is used to initiate the bean shutdown */
   
@Override
   
public void run() {

     
System.out.println("About to destroy singletons");
      factory.destroySingletons
();
      System.out.println
("Singletons destroyed");
   
}
  }
}

I’ve configured this using straight forward 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="implementDisposableBean" class="example_2_lifecycle_management.interface_based_disposable.ImplementDisposableBean"/>
</beans>

This approach is most applicable when you’re writing a standalone application that uses external resources.

No comments: