Sunday, 30 March 2014

Scope of Spring Beans (singleton & prototype)

What is a Bean?
  • The objects that form the backbone of your application and that are managed by the Spring IoC container are called as beans
  • A bean is an object that is instantiated, assembled, and managed by a Spring IoC container.
When defining a <bean> in Spring, you have the option of declaring a scope for that bean. For example, To force Spring to produce a new bean instance each time one is needed, you should declare the bean's scope attribute to be prototype. Similar way if you want Spring to return the same bean instance each time one is needed, you should declare the bean's scope attribute to be singleton.

The Spring Framework supports following five scopes, three of which are available only if you use a web-aware ApplicationContext.

ScopeDescription
singleton This scopes the bean definition to a single instance per Spring IoC container (default).
prototype This scopes a single bean definition to have any number of object instances.
request This scopes a bean definition to an HTTP request. Only valid in the context of a web-aware Spring ApplicationContext.
session This scopes a bean definition to an HTTP session. Only valid in the context of a web-aware Spring ApplicationContext.
global-session This scopes a bean definition to a global HTTP session. Only valid in the context of a web-aware Spring ApplicationContext.

In this post we will discuss about first two scopes viz. singleton and prototype with an example for each.

Specifying scope of a bean
<bean class="org.techmight.HelloWorld" id="helloWorld" scope="singleton">

The singleton scope

This is the default scope. If scope is set to singleton, the Spring IoC container creates exactly one instance of the object defined by that bean definition. This single instance is stored in a cache of such singleton beans, and all subsequent requests and references for that named bean return the cached object.

Example
This is in continuation of the previous introductory Hello World example in Spring. Click here to read that post.

spring-config.xml
<?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.0.xsd">
 
 <bean id="helloWorld" class="org.techmight.HelloWorld" scope="singleton"> 
  <property name="message" value="Hello World from TechMight Solutions!"/>
 </bean>
 
 <bean id="user" class="org.techmight.User"> 
  <property name="hello">
   <ref local="helloWorld"/>
  </property>
 </bean>
 
</beans>

In this example we are going to create a new User class and injected HelloWorld class as its dependency. by using ref. One way of injecting dependency is

<bean id="user" class="org.techmight.User"> 
 <property name="hello" ref="helloWorld"/>
</bean>

Actually, the ‘ref’ tag can access to a bean either in same or different XML files, however, for the project readability, you should use the ‘local’ attribute if you reference to a bean which declared in the same XML file and 'bean' attribute if you reference to a bean which is declared in a different XML file.

<bean id="user" class="org.techmight.User"> 
 <property name="hello">
  <ref bean="helloWorld"/>
 </property>
</bean>

User class will have getter and setter for the HelloWorld class object because HelloWorld is defined as property in spring-config file.

User.java
package org.techmight;

/**
 * @author TechMight Solutions
 */

public class User {

 HelloWorld hello;

 public HelloWorld getHello() {
  return hello;
 }

 public void setHello(HelloWorld hello) {
  this.hello = hello;
 }

 public void execute() {
  String response = getHello().getMessage();
  System.out.println(response + " (From User class) ");
 }
}

The HelloWorld class is modified as follows.

HelloWorld.java
package org.techmight;

/**
 * @author TechMight Solutions
 */
public class HelloWorld {

 private String message;
 private int count = 0;
 public String getMessage() {
  count++;
  return ("Your Message (" + count + ") : " + message);
 }

 public void setMessage(String message) {
  this.message = message;
 }
}

MainApp.java
package org.techmight;

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

public class MainApp {

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

  HelloWorld obj = (HelloWorld) context.getBean("helloWorld");

  String response = obj.getMessage();
  System.out.println(response);
  // Output-> Your Message (1) : Hello World from TechMight Solutions!

  User user = (User) context.getBean("user");
  user.execute();
  // Output-> Your Message (2) : Hello World from TechMight Solutions!
  // (From User class)

  response = obj.getMessage();
  System.out.println(response);
  // Output-> Your Message (3) : Hello World from TechMight Solutions!
 }
}

Output
Your Message (1) : Hello World from TechMight Solutions!
Your Message (2) : Hello World from TechMight Solutions! (From User class) 
Your Message (3) : Hello World from TechMight Solutions!

Observation
The count variable was increased each time as getMessage() method is called from different locations.

The prototype scope
If scope is set to prototype, the Spring IoC container creates new bean instance of the object every time a request for that specific bean is made.

As a rule, use the prototype scope for all state-full beans and the singleton scope for stateless beans.

In spring-config.xml just change the scope of the helloWorld bean to prototype.
<bean id="helloWorld" class="org.techmight.HelloWorld" scope="prototype"> 

Now execute MainApp.java and see the output which will be as follows.

Output
Your Message (1) : Hello World from TechMight Solutions!
Your Message (1) : Hello World from TechMight Solutions! (From User class) 
Your Message (2) : Hello World from TechMight Solutions!

We are leaving it for our readers to determine what is the difference in the output and the reason behind !!

No comments:

Post a Comment

Your comments are very much valuable for us. Thanks for giving your precious time.