When spring context XML is loaded, a bean definition is created for each bean declared in the XML.
If the bean is marked for eager instantiation, for example, using the beans level attribute default-lazy-init=true
or the bean level attribute lazy-init=true
then the bean will be instantiated right after its bean definition is created.
Spring also allows you to control the bean creation using the attribute scope
. If an eagerly instantiated bean is declared scoped at ‘singleton’ then whenever the bean is requested by the getBean(beanId)
method, the same instance will be returned.
Suppose the same bean is scoped at ‘prototype’, a unique bean instance is returned whenever getBean(beanId)
method is called.
In this article, we will look into the various scopes supported by spring with some examples.
Valid Scopes in Spring
In Spring 1.x, singleton and prototype were the only two valid bean scopes so the scope was specified using singleton
attribute set to true
or false
. From 2.0 on wards, spring supports a variety of scopes which is why it introduced a new attribute scope
instead of the singleton
attribute.
Let’s review all the available scopes.
singleton
– Creates a single bean instance per spring contextprototyp
– Creates a new bean instance each time whengetBean(beanId)
is called.request
– Creates a single bean instance per HTTP request; only valid in the context of a web applicationsession
– Creates a single bean instance per HTTP session; only valid in the context of a web applicationglobalSession
– Creates a single bean instance per global HTTP session; only valid in the context of a portal application
Before we get to the examples, let’s first understand at what stage spring converts a bean definition into a bean.
Bean Creation
When you declare a bean in the configuration file, you are only defining a template for bean creation, the template is represented by BeanDefinition
class. A template is not an actual bean instance. You can configure in spring whether you want the beans to be created eagerly right after the bean definition is created or lazily when you call getBean()
. See lazy-init examples if you want to know more about lazy-init
attribute.
In all our examples, we will use the below bean. We have structured the bean such a way that we know when the bean is created and also shed some light about the scope and its behavior.
Few things to note about the bean:
- We will be using this bean in more than one bean definition so we made the bean implement
BeanNameAware
. This way we know which bean definition the instance represents. - The bean has three state variables – a long value which we will increment whenever
toString()
is called, bean created date time, and a list of string items. We can add an item usingaddItem(item)
SpringScopeBean:
package com.javarticles.web; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.concurrent.atomic.AtomicLong; import org.springframework.beans.factory.BeanNameAware; public class SpringScopeBean implements BeanNameAware { private AtomicLong value = new AtomicLong(0); private static final DateFormat dateFormat = new SimpleDateFormat( "HH:MM:SS"); private String beanCreatedTime; private String beanName; private List<String> items = new ArrayList<String>(); public SpringScopeBean() { value.incrementAndGet(); beanCreatedTime = dateFormat.format(new Date()); System.out.println("SpringScopeBean constructor called"); } public String toString() { return beanName + " created at " + beanCreatedTime + ", no. of times " + beanName + " is called(" + value.getAndIncrement() + ")"; } public void setBeanName(String name) { beanName = name; } public void addItem(String item) { items.add(item); } public List<String> getItems() { return items; } }
The first bean definition is of singleton scope. Attribute default-lazy-init
is set to true so that it is lazily created when getBean(beanID)
is called.
singletonApplicationContext.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" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd" default-lazy-init="true"> <bean id="singletonBean" class="com.javarticles.web.SpringScopeBean" scope="singleton"/> </beans>
In below example, we load the context XML and then get the bean.
SpringSingletonBeanExample:
package com.javarticles.web; import java.io.IOException; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringLazySingletonExample { public static void main(String[] args) throws IOException { System.out.println("Load application context"); ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( "singletonApplicationContext.xml"); try { System.out.println("Get SpringScopeBean bean"); SpringScopeBean singletonBean = (SpringScopeBean) context .getBean("singletonBean"); System.out.println(singletonBean); } finally { context.close(); } } }
If you note, the bean is created only after the getBean("singletonBean")
is called.
Output:
Load application context Get SpringScopeBean bean SpringScopeBean constructor called singletonBean created at 21:06:749, no. of times singletonBean is called(1)
Singleton Scope
Spring will decide which bean instance should be returned according to the bean scope. By default, its scope is ‘singleton’ which means Spring creates exactly one instance for each bean declared in the spring container, and this instance will be shared in the scope of the entire container. This unique bean instance will be returned for all subsequent calls to getBean(beanId)
.
In the below example, we get the singleton scoped bean and add item ‘one’. We once again retrieve the bean from spring container and this time add ‘two’. Next, we print all the items added. We see both ‘one’ and ‘two’ in there which means the second call to geBean()
returned as the same as instance as the first call.
SpringSingletonExample:
package com.javarticles.web; import java.io.IOException; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringSingletonExample { public static void main(String[] args) throws IOException { System.out.println("Load application context"); ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( "applicationContext.xml"); try { System.out.println("Get SpringScopeBean bean"); SpringScopeBean singletonBean = (SpringScopeBean) context .getBean("singletonBean"); singletonBean.addItem("one"); System.out.println(singletonBean.getItems()); singletonBean = (SpringScopeBean) context .getBean("singletonBean"); singletonBean.addItem("two"); System.out.println(singletonBean.getItems()); } finally { context.close(); } } }
Output:
Load application context Get SpringScopeBean bean SpringScopeBean constructor called [one][one, two]
Prototype Scope
Suppose you expect each call to getBean()
to return a new instance of the bean then you should change the scope of the bean to ‘prototype’.
Let’s declare a bean with prototype scope.
prototypeApplicationContext.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" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd" default-lazy-init="true"> <bean id="prototypeBean" class="com.javarticles.web.SpringScopeBean" scope="prototype"/> </beans>
We will now revisit the item example. Since the bean is scoped as prototype, we should be getting a new instance for each getBean()
call thus, the second bean instance shouldn’t be seeing item ‘one’ in its list.
SpringPrototypeExample:
package com.javarticles.web; import java.io.IOException; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringPrototypeExample { public static void main(String[] args) throws IOException { System.out.println("Load application context"); ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( "prototypeApplicationContext.xml"); try { System.out.println("Get Prototype bean"); SpringScopeBean prototypeBean = (SpringScopeBean) context.getBean("prototypeBean"); prototypeBean.addItem("one"); System.out.println(prototypeBean.getItems()); prototypeBean = (SpringScopeBean) context .getBean("prototypeBean"); prototypeBean.addItem("two"); System.out.println(prototypeBean.getItems()); } finally { context.close(); } } }
As you can see, the constructor is called twice at each getBean()
call.
Output:
Load application context Get Prototype bean SpringScopeBean constructor called [one]SpringScopeBean constructor called [two]
Session and Request Scopes
The next two scopes session
and prototype
are valid only in the context of a web application. Let’s write a mini web application so we can understand both these scopes.
First create web.xml
.
- Make sure you specify the spring context XML location in parameter
contextConfigLocation
- You also need to specify the listener classes
ContextLoaderListener
andRequestContextListener
web.xml:
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <display-name>Spring Scoping Example</display-name> <context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath*:/webApplicationContext.xml, </param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <listener> <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> </listener> </web-app>
Let’s look at the spring context XML. If you note we have used the same bean class to create beans with different scopes.
webApplicationContext.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" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd" default-lazy-init="true"> <context:annotation-config /> <bean id="springSessionBean" class="com.javarticles.web.SpringScopeBean" scope="session"/> <bean id="springRequestBean" class="com.javarticles.web.SpringScopeBean" scope="request"/> <bean id="springSingletonBean" class="com.javarticles.web.SpringScopeBean" scope="singleton"/> <bean id="springPrototypeBean" class="com.javarticles.web.SpringScopeBean" scope="prototype"/> </beans>
Now let’s look at the main page. In the main entry page index.jsp
we simply get the bean and print it so we know its creation time and number of times toString()
method on the instance is called.
index.jsp:
<%@page import="org.springframework.web.context.support.WebApplicationContextUtils, com.javarticles.web.SpringScopeBean" %> <html> <body> <h2> <% SpringScopeBean sessionBean = (SpringScopeBean) WebApplicationContextUtils.getWebApplicationContext(application).getBean("springSessionBean"); out.println("Session Scoped Bean" + sessionBean.toString()); SpringScopeBean requestBean = (SpringScopeBean) WebApplicationContextUtils.getWebApplicationContext(application).getBean("springRequestBean"); out.println("Request Scoped Bean" + requestBean.toString()); SpringScopeBean singletonBean = (SpringScopeBean) WebApplicationContextUtils.getWebApplicationContext(application).getBean("springSingletonBean"); out.println("Singleton Scoped Bean" + singletonBean.toString()); SpringScopeBean prototypeBean = (SpringScopeBean) WebApplicationContextUtils.getWebApplicationContext(application).getBean("springPrototypeBean"); out.println("Prototype Scoped Bean" + prototypeBean.toString()); %> </h2> </body> </html>
Right Click on project and click on ‘Run on server’.
Output:
Session Scoped BeanspringSessionBean created at 23:06:406, no. of times springSessionBean is called(1) Request Scoped BeanspringRequestBean created at 23:06:424, no. of times springRequestBean is called(1) Singleton Scoped BeanspringSingletonBean created at 23:06:424, no. of times springSingletonBean is called(1) Prototype Scoped BeanspringPrototypeBean created at 23:06:425, no. of times springPrototypeBean is called(1)
Now refresh the screen, you get a different output.
Note that the session scoped bean is of the same instance so toString()
gets called twice which is why the called number shows 2.
Also note request scoped bean is of a new instance whenever you refresh. You can see a different created time than that of the first request.
Singleton scoped bean is of the same instance as the first one only the toString()
got called twice, the call number shows 2.
Prototype scoped bean is of a new instance whenever you refresh. You can see a different created time for each request.
What is the difference between request and prototype scopes?
Within the same web request, if the scope is ‘request’, call to getBean(beanID)
will return us the same instance whereas if it is prototype scope, you will get a new instance for each call.
Output:
Session Scoped BeanspringSessionBean created at 23:06:406, no. of times springSessionBean is called(2) Request Scoped BeanspringRequestBean created at 23:06:819, no. of times springRequestBean is called(1) Singleton Scoped BeanspringSingletonBean created at 23:06:424, no. of times springSingletonBean is called(2) Prototype Scoped BeanspringPrototypeBean created at 23:06:820, no. of times springPrototypeBean is called(1)
What is the difference between session and singleton scopes?
Open the URL ‘http://localhost:8080/springWebappExample/’ in a different browser. You will get a new instance for the session scoped bean. You can verify the time creation is different from the above one whereas the singleton bean time creation is still same as it is application scoped.
Output:
Session Scoped BeanspringSessionBean created at 23:06:430, no. of times springSessionBean is called(1) Request Scoped BeanspringRequestBean created at 23:06:430, no. of times springRequestBean is called(1) Singleton Scoped BeanspringSingletonBean created at 23:06:424, no. of times springSingletonBean is called(3) Prototype Scoped BeanspringPrototypeBean created at 23:06:430, no. of times springPrototypeBean is called(1)
Download the source code
This was an example about spring scopes.