Bean Scopes in Spring
When the Spring IoC container starts, it reads bean definitions from configuration files (e.g., XML) and converts each <bean> element into a BeanDefinition object. The scope attribute within BeanDefinition determines the bean's scope. Spring provides five built-in scopes, three of which are only available in a web-aware ApplicationContext. Developers can also define custom scopes.
| Scope | Description |
|---|---|
| singleton | (Default) A single instance per Spring IoC container. |
| prototype | Any number of object instances per bean definition. |
| request | One bean instance per HTTP request. Only available in web-aware Spring ApplicationContext. |
| session | One bean instance per HTTP session. Available only in web-aware ApplicationContext. |
| globalSession | One bean instance per global HTTP session (typically used in portlet environments). Only available in web-aware ApplicationContext. |
To demonstrate the difference between singleton and prototype, consider a simple class XMLInstance. The following snippet retrieves the bean twice via BeanFactory.getBean():
XMLInstance instance = (XMLInstance) factory.getBean("xmlinstance");
instance.setName("123");
instance.Breath();
instance = (XMLInstance) factory.getBean("xmlinstance");
instance.Breath();
With the default singleton scope (configuration below), both calls return the same object instance:
<bean id="xmlinstance" class="com.demo.model.XMLInstance" scope="singleton">
<property name="air" ref="CleanAir"/>
<property name="name" value="abc"/>
</bean>
Output:
Name:123;Air:CleanAir
Name:123;Air:CleanAir
If the scope is changed to prototype, each getBean() call creates a new instance:
<bean id="xmlinstance" class="com.demo.model.XMLInstance" scope="prototype">
<property name="air" ref="CleanAir"/>
<property name="name" value="abc"/>
</bean>
Output:
Name:123;Air:CleanAir
Name:abc;Air:CleanAir
Bean Lifecycle in Spring
Understanding the lifecycle of a bean helps clarify how Spring creates, configures, and destroys beans. The following steps outline the full lifecycle within an ApplicationContext:
- The container instantiates beans (singleton, non-lazy by default).
- Properties and dependencies are injected as per bean definition.
- If the bean implements
BeanNameAware, Spring callssetBeanName()with the bean's id. - If the bean implements
BeanFactoryAware, Spring callssetBeanFactory()with the owning factory. - If the bean implements
ApplicationContextAware, Spring callssetApplicationContext()with the context. - Any registered
BeanPostProcessorbeans are invoked withpostProcessBeforeInitialization(). - If the bean implements
InitializingBean, Spring callsafterPropertiesSet(). - If a custom
init-methodis defined, its invoked. - Any registered
BeanPostProcessorbeans are invoked withpostProcessAfterInitialization(). - The bean is now ready for use. Singleton beans are cached; prototype beans are handed over to the caller and not managed by the container thereafter.
- When the container shuts down, if the bean implements
DisposableBean, Spring callsdestroy(). - If a custom
destroy-methodis defined, it is invoked.
The following example demonstrates the lifecycle methods using a custom bean UserBean which implements several aware interfaces and lifecycle interfaces.
package com.demo.model;
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 UserBean implements BeanNameAware, BeanFactoryAware,
InitializingBean, DisposableBean, ApplicationContextAware {
private String userName;
public UserBean() {
System.out.println("Constructor of UserBean");
}
public void setUserName(String userName) {
this.userName = userName;
System.out.println("Setter called");
}
public String getUserName() {
return userName;
}
@Override
public void setBeanName(String name) {
System.out.println("BeanNameAware.setBeanName()");
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("BeanFactoryAware.setBeanFactory()");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("ApplicationContextAware.setApplicationContext()");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean.afterPropertiesSet()");
}
// Custom init method
public void customInit() {
System.out.println("Custom init-method called");
}
@Override
public void destroy() throws Exception {
System.out.println("DisposableBean.destroy()");
}
// Custom destroy method
public void customDestroy() {
System.out.println("Custom destroy-method called");
}
}
Additionally, a custom BeanPostProcessor implementation is defined:
package com.demo.model;
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("PostProcessBeforeInitialization");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("PostProcessAfterInitialization");
return bean;
}
}
The XML configuration registers the bean with custom init and destroy methods, and also registers the post-processor:
<bean id="user" class="com.demo.model.UserBean" init-method="customInit" destroy-method="customDestroy">
<property name="userName" value="abc"/>
</bean>
<bean id="customPostProcessor" class="com.demo.model.CustomBeanPostProcessor"/>
Finally, a test program loads the context, retrieves the bean, and closes the context:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserBean user = context.getBean("user", UserBean.class);
((ClassPathXmlApplicationContext) context).close();
The output shows the order of lifecycle callbacks:
Constructor of UserBean
Setter called
BeanNameAware.setBeanName()
BeanFactoryAware.setBeanFactory()
ApplicationContextAware.setApplicationContext()
PostProcessBeforeInitialization
InitializingBean.afterPropertiesSet()
Custom init-method called
PostProcessAfterInitialization
DisposableBean.destroy()
Custom destroy-method called