Introduction
In this article, we'll explore the lifecycle of a Spring bean through hands-on coding examples. Understanding bean lifecycle is crucial in Spring framework as it helps in managing bean initialization, configuration, and destruction effective.
Implementing Lifecycle Interfaces
We'll create a class that implements several Spring lifecycle interfaces to observe the execution sequence of each method.
package com.example.spring.service;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class BeanLifecycle implements BeanFactoryAware, BeanNameAware,
InitializingBean, DisposableBean, ApplicationContextAware {
private String name;
public String getName() {
System.out.println("getName name=" + name);
return name;
}
public void setName(String name) {
System.out.println("setName name=" + name);
this.name = name;
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean.afterPropertiesSet()");
}
@Override
public void setBeanName(String beanName) {
System.out.println("BeanNameAware.setBeanName");
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("BeanFactoryAware.setBeanFactory");
}
@Override
public void destroy() throws Exception {
System.out.println("DisposableBean.destroy");
}
public void customInit() {
System.out.println("Custom init method specified in XML");
}
public void customDestroy() {
System.out.println("Custom destroy method specified in XML");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("ApplicationContextAware.setApplicationContext");
}
}
Implementing InstantiationAwareBeanPostProcessor
This interface extends BeanPostProcessor and provides additional hooks during bean instantiation process.
package com.example.spring.service;
import java.beans.PropertyDescriptor;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
public class CustomInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class> beanClass, String beanName) throws BeansException {
System.out.println("postProcessBeforeInstantiation");
return null;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInstantiation");
return true;
}
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
System.out.println("postProcessPropertyValues");
return pvs;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization");
return bean;
}
}
Impleemnting BeanPostProcessor
package com.example.spring.service;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class CustomBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeanPostProcessor - before initialization");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeanPostProcessor - after initialization");
return bean;
}
}
Implementing BeanFactoryPostProcessor
package com.example.spring.service;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("BeanFactoryPostProcessor.postProcessBeanFactory");
}
}
Spring Configuration
We'll define our beans in XML 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.xsd">
<bean id="beanPostProcessor" class="com.example.spring.service.CustomBeanPostProcessor"/>
<bean id="instantiationAwareProcessor" class="com.example.spring.service.CustomInstantiationAwareBeanPostProcessor"/>
<bean id="beanFactoryPostProcessor" class="com.example.spring.service.CustomBeanFactoryPostProcessor"/>
<bean id="lifecycleBean" class="com.example.spring.service.BeanLifecycle"
init-method="customInit" destroy-method="customDestroy">
<property name="name" value="initialValue"/>
</bean>
</beans>
Main Application
Finally, we'll run our application to observe the lifecycle methods in action:
package com.example.spring.app;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.example.spring.service.BeanLifecycle;
public class SpringLifecycleApp {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BeanLifecycle bean = context.getBean("lifecycleBean", BeanLifecycle.class);
bean.setName("newValue");
System.out.println("Current name: " + bean.getName());
((ClassPathXmlApplicationContext) context).registerShutdownHook();
}
}