Spring 3 Prart 4: Lifecycle Management

This is the 4th part of the Spring 3 Series.

Regardless of bean scope, initialization lifecycle callback methods are called on objects in Spring. There are 3 ways to achieve this

  1. interface based
  2. method based
  3. annotation based

Depend on your application requirements, you need to evaluate which mechanism is best. To achieve more portability third is the best because it is based on the JSR-250. If you are not concern of portability and in an application and needs lifecycle notification for many beans of the same type, then best is interface mechanism. When you share the bean among multiple spring projects , then interface mechanism is the best because interface mechanism based beans are self-contained.

spring lifecycle callback

Above diagram shows a high-level overview of how Spring manages the life cycle of the beans within its container(Harrop, Rob; Ho, Clarence (2012-04-18). Pro Spring 3 (Professional Apress) (p. 115). Apress. Kindle Edition).

It is important to remember that initialization callback in Spring is called after Spring finishes providing the dependencies, therefore in the initialization hook, you can perform the dependency check. If you are expecting to run schedule task, initialization hook is the best.

Method based mechanism

First start with the method based approach.

package com.blogspot.ojitha.spring32.example.tut2;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;

public class XMLBaseSimpleBean {

static Logger logger = Logger.getLogger(XMLBaseSimpleBean.class);
static {logger.setLevel(Level.INFO);}
public XMLBaseSimpleBean(){

}

public void init(){
logger.info("Initialize the bean");
}

public void shutdown(){
logger.info("Destroy the bean");
}

}

As shown in the above code, XMLBaseSimpleBean has two methods, init for initialization and shutdown for destroy method to execute when stop the application. This has been configured in the following Spring configuration file.

<?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.2.xsd"
default-lazy-init="true">

<bean id="simpleBean"
class="com.blogspot.ojitha.spring32.example.tut2.XMLBaseSimpleBean"
init-method="init" destroy-method="shutdown"/>

</beans>

As shown in the line 9, initialize and destroy methods are defined. Client application is as follows:

package com.blogspot.ojitha.spring32.example.tut2;

import org.springframework.context.support.GenericXmlApplicationContext;

/**
* Application Client
*
*/
public class App
{
public static void main( String[] args )
{
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:spring\\lifecycle-xmlbased.xml");
ctx.refresh(); //this is important.
XMLBaseSimpleBean bean = (XMLBaseSimpleBean)ctx.getBean("simpleBean");
System.out.println(bean);
ctx.close(); //without this XMLBaseSimpleBean.shutdown() never work.
}
}

Interface based mechanism

Next consider the interface based mechanism.

package com.blogspot.ojitha.spring32.example.tut2;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

public class InterfaceBaseSimpleBean implements InitializingBean, DisposableBean {

Logger log = Logger.getLogger(InterfaceBaseSimpleBean.class);
@Override
public void afterPropertiesSet() throws Exception {
log.info("Initialize the bean");
}

@Override
public void destroy() throws Exception {
log.info("Destroy the bean");
}

}

In the above code, two interfaces defined, afterPropertiesSet() from the InitializingBean and the destroy() method from the DisposableBean.

<?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.2.xsd"
default-lazy-init="true">

<bean id="simpleBean"
class="com.blogspot.ojitha.spring32.example.tut2.InterfaceBaseSimpleBean" />

</beans>

In the above code, not need either init-method or destroy-method because this requirement is fill by the interfaces.

//interface based mechanism
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:spring\\lifecycle-interfacebased.xml");
ctx.refresh(); //this is important.
InterfaceBaseSimpleBean bean = (InterfaceBaseSimpleBean)ctx.getBean("simpleBean");
System.out.println(bean);
ctx.close(); //without this XMLBaseSimpleBean.shutdown() never work.
To run this you need to change the client code as above.

Annotation based mechanism

This mechanism is based on the JSR-250.

package com.blogspot.ojitha.spring32.example.tut2;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;

public class AnnotationBaseSimpleBean {

static Logger logger = Logger.getLogger(AnnotationBaseSimpleBean.class);
static {logger.setLevel(Level.INFO);}
public AnnotationBaseSimpleBean(){

}

@PostConstruct
public void init(){
logger.info("Initialize the bean");
}

@PreDestroy
public void shutdown(){
logger.info("Destroy the bean");
}

}

However, in the Spring context you have to introduce the <context:annotation-config/> for annotations.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">

<bean id="simpleBean" class="com.blogspot.ojitha.spring32.example.tut2.AnnotationBaseSimpleBean"/>
<context:annotation-config/>

</beans>

Here the client code

//annotation based mechanism
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:spring\\lifecycle-annotationbased.xml");
ctx.refresh(); //this is important.
AnnotationBaseSimpleBean bean = (AnnotationBaseSimpleBean)ctx.getBean("simpleBean");
System.out.println(bean);
ctx.close(); //without this XMLBaseSimpleBean.shutdown() never work.

In the above code, instead of ctx.close(), you can use  ctx.getDefaultListableBeanFactory().destroySingletons(). There is another elegant solution to use the ctx.registerShutdownHook() very early(insert before the ctx.refresh() method) in the context in the Spring standard alone applications.

Source available to download for this blog.

Comments

Popular posts from this blog

How To: GitHub projects in Spring Tool Suite

Spring 3 Part 7: Spring with Databases

Parse the namespace based XML using Python