All available methods to Hack Spring’s Bean Lifecycle

There are three ways to intercept Spring’s Bean lifecycle just after initializing and moments before being destroyed. Namely (and given chronological order of appearance) this can be done via interfaces, via bean definition methods and finally via annotations.

I’ve put a sample trivial application to showcase all these three methods.

The POM looks like so:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.dimitrisli.spring</groupId>
  <artifactId>SpringBeanInitializationDestruction</artifactId>
  <version>1.0</version>
  <properties>
  	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  <dependencies>
  	<dependency>
  		<groupId>org.springframework</groupId>
  		<artifactId>spring-context</artifactId>
  		<version>3.1.0.RELEASE</version>
  	</dependency>
  	<dependency>
  		<groupId>org.jboss.spec.javax.annotation</groupId>
  		<artifactId>jboss-annotations-api_1.1_spec</artifactId>
  		<version>1.0.0.Final</version>
  	</dependency>
  </dependencies>
  <build>
  	<plugins>
  		<plugin>
  			<groupId>org.apache.maven.plugins</groupId>
  			<artifactId>maven-compiler-plugin</artifactId>
  			<version>2.3.2</version>
  			<configuration>
  				<source>1.6</source>
  				<target>1.6</target>
  				<encoding>${project.build.sourceEncoding}</encoding>
  			</configuration>
  		</plugin>
  	</plugins>
  </build>
</project>

The first way involves calling Spring’s marker interfaces: InitializingBean and DisposableBean. The POJO bean looks like this:

package app.withinterface;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

public class InterfaceBeanInitializationDestructionPojo implements InitializingBean, DisposableBean{

	private String text;

	public String getText(){
		return this.text;
	}

	public void setText(String text){
		this.text = text;
	}

	public void destroy() throws Exception {
		System.out.println("During bean destruction, wired by the DisposableBean interface...");
	}

	public void afterPropertiesSet() throws Exception {
		System.out.println("During bean initialization, wired by the InitializingBean interface...");
	}

}

The equivalent definition on the context config file looks like this:

<bean id="interfaceBeanInitializationDestructionPojo"
		class="app.withinterface.InterfaceBeanInitializationDestructionPojo"
		scope="singleton">
		<property name="text" value="withInterfaces-DuringBeanBigTimeInContextLife..."></property>
	</bean>

which is basically nothing special other than specifying the bean in the config file. The marker interfaces do all the hard work during runtime being invoked by the Spring framework.

Secondly, we have the XML config method definition. The POJO bean in this case looks like this:

package app.xml;

public class XMLBeanInitializationDestructionPojo {

	private String text;

	public String getText() {
		return text;
	}

	public void setText(String text){
		this.text = text;
	}

	public void myInitBeanMethod(){
		System.out.println("During init of the bean, wired by XML...");
	}

	public void myDestroyBeanMethod(){
		System.out.println("During destruction of the bean, wired by XML... ");
	}
}

and its corresponding context config entry:

<bean id="xmlBeanInitializationDestructionPojo"
		class="app.xml.XMLBeanInitializationDestructionPojo"
		init-method="myInitBeanMethod" destroy-method="myDestroyBeanMethod"
		scope="singleton">
		<property name="text" value="withXML-DuringBeanBigTimeInContextLife..."></property>
	</bean>

Please note the explicitely defined init-method and destroy-method

Finally the annotation driven definition happens (surprisingly) using JSR-250 @PreDestroy and @PostConstruct annotations.

Here’s the POJO:

package app.annotation;

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

public class AnnotationsBeanInitializationDestructionPojo {

	private String text;

	public void setText(String text){
		this.text=text;
	}
	public String getText(){
		return this.text;
	}

	@PostConstruct
	public void myInitMethod(){
		System.out.println("During bean initialization, wired by the Annotations...");
	}

	@PreDestroy
	public void myDestroyMethod(){
		System.out.println("During bean destruction, wired by the Annotations...");
	}
}

and in order to make these annotations being scanned by the Spring framework during runtime all we need is the definition of the context component-scan:


Having a simple main method demonstration:

package app;

import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import app.annotation.AnnotationsBeanInitializationDestructionPojo;
import app.withinterface.InterfaceBeanInitializationDestructionPojo;
import app.xml.XMLBeanInitializationDestructionPojo;

public class Main {

	public static void main(String[] args) {
		ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("application-config.xml");

		AnnotationsBeanInitializationDestructionPojo viaAnnotations = (AnnotationsBeanInitializationDestructionPojo) context.getBean("annotationsBeanInitializationDestructionPojo");
		InterfaceBeanInitializationDestructionPojo viaInterface = (InterfaceBeanInitializationDestructionPojo) context.getBean("interfaceBeanInitializationDestructionPojo");
		XMLBeanInitializationDestructionPojo viaXML = (XMLBeanInitializationDestructionPojo) context.getBean("xmlBeanInitializationDestructionPojo");

		System.out.println(viaAnnotations.getText());
		System.out.println(viaInterface.getText());
		System.out.println(viaXML.getText());

		context.close();
	}
}

produces the output:


...
During bean initialization, wired by the InitializingBean interface...
During init of the bean, wired by XML...
During bean initialization, wired by the Annotations...
withAnnotations-DuringBeanBigTimeInContextLife...
withInterfaces-DuringBeanBigTimeInContextLife...
withXML-DuringBeanBigTimeInContextLife...
During bean destruction, wired by the Annotations...
During destruction of the bean, wired by XML...
During bean destruction, wired by the DisposableBean interface...
...

The code can be found in this Github repository.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s