Spring Singleton vs Prototype

                            Bean scopes will be specified by the scope attribute of the <bean/> element. We will see the example as we go down to this article. Spring bean has 5 different scopes which we listed below,
  1. Singleton
  2. Prototype 
  3. Global
  4. Session
  5. Application
When it comes to standalone application, we don’t have the last three scopes that are applicable only for web applications. Here, In this article, we’ll just look at the first two, singleton and the prototype.
                            Singleton beans are created by the spring container only once which means you will have only one instance of the bean through out our application. Prototype beans are right opposite to this. It’s a multiton bean which means more than one instance can be created. When we call the getBean method of ApplicationContext or inject in other beans, we will get a new instance of it. Let’s see this by an example,
ApplicationContext.xml
 <?xml version="1.0" encoding="UTF-8"?>  
<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="student" class="com.studentact.model.Student" scope="prototype" destroy-method="destroy" init-method="init"/>

<bean id="studentDao" class="com.studentact.dao.StudentDaoImpl" destroy-method="destroy" init-method="init">
<property name="student" ref="student"/>
</bean>

<bean id="studentServiceProxy" class="com.studentact.proxy.StudentServiceProxy" init-method="init" destroy-method="destroy">
<property name="student" ref="student"/>
</bean>

<bean id="studentService" class="com.studentact.service.StudentService" destroy-method="destroy" init-method="init">
<property name="studentServiceProxy" ref="studentServiceProxy"/>
<property name="studentDao" ref="studentDao"/>
</bean>

</beans>

We can see that the scope of student bean is specified as prototype and other beans don’t have this scope attribute which means they are all singleton.
Let’s say StudentServiceProxy’s method getVOCTopStudent gets student data from some web service and assign them in student object. Likewise StudentDaoImpl’s method getGovtStudent gets the from DB and assign them in student object. StudentService will call these methods and store the return student object in a list as below,

StudentService.java
 public class StudentService implements IStudentService {  
private IStudentDao studentDao;
private IStudentServiceProxy studentServiceProxy;
public IStudentDao getStudentDao() {
return studentDao;
}
public void setStudentDao(IStudentDao studentDao) {
this.studentDao = studentDao;
}
public IStudentServiceProxy getStudentServiceProxy() {
return studentServiceProxy;
}
public void setStudentServiceProxy(IStudentServiceProxy studentServiceProxy) {
this.studentServiceProxy = studentServiceProxy;
}
@Override
public List<Student> getTopStudents() {
List<Student> topStudents = new ArrayList<Student>();
topStudents.add(studentDao.getGovtStudent());
topStudents.add(studentServiceProxy.getVOCTopStudent());
return topStudents;
}
public void destroy(){
System.out.println("detroy method of StudentService");
}
public void init(){
System.out.println("init method of StudentService");
}
//Other operations go here
}

We can use the below code to test whether the list has same student object or different objects.

 StudentService studentService = (StudentService) applicationContext.getBean("studentService");  
List<Student> students = studentService.getTopStudents();
System.out.println(students);
Student aStudent = null;
for(Student student:students){
if(null == aStudent){
aStudent = student;
} else if(student == aStudent) {
Assert.assertFalse(true);
}
}

We mentioned student bean scope as prototype and injected it in other beans like studentDao and studentServiceProxy. So the resultant list will have different student objects. If it’s a singleton, then both studentDao and studentServiceProxy will have the same object and the resultant list will have the same student objects.

Initialization and destruction:
                            If you assign any method to init-method attribute of bean element, the method will be called after the bean properties is set, but before the bean is completely initialized. We can use this, when we need to initialize something like opening file, creating or checking the database connections. This method will be called by spring container regardless of singleton or prototype beans. 
                            But destroy-method will be called by the spring container, only if the bean is singleton. It will never be called in case of the bean scope is prototype. The methods which we assign to this destroy-method attribute will be called by the spring container, before the object is destroyed. But we have to use this AbstractApplicationContext interface and call the registerShutdownHook method as we used in below test class,
 public class StudentServiceTest extends BaseTest {  
protected AbstractApplicationContext applicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml");
@Test
public void testGetTopStudents() {
applicationContext.registerShutdownHook();
StudentService studentService = (StudentService) applicationContext.getBean("studentService");
List<Student> students = studentService.getTopStudents();
System.out.println(students);
Student aStudent = null;
for(Student student:students){
if(null == aStudent){
aStudent = student;
} else if(student == aStudent) {
Assert.assertFalse(true);
}
}
}
}
                            The methods we use as init-method and destroy-method should not accept any arguments, but can be defined to throw exceptions. We can define initialization and destruction methods in all beans with same method signature and can specify it in default-init-method and default-destroy-method of beans elements, instead of specifying it in all the bean elements. Also please have a look at other beans attribute like default-autowire-candidates and default-lazy-init.
                            Singleton bean objects will be created when application context is loaded. Though it’s not used anywhere. Prototype scoped bean objects will always be created when it’s needed. But if we want singleton objects to be created when it’s needed, we can use the lazy-init attribute of bean element. 
Please do more examples like singleton-scoped bean has prototype-scoped beans and vice versa.
Click here to download this example project from GitHub.

Published