Spring provides us with beans after instantiating and configuring them. Spring Container manages objects. This means that any object can refer to any other object from Spring Container using the bean's ID, and Spring Container provides an instance of the requesting object.
When we start Spring Container, ApplicationContext
reads the Spring configuration, file looks for all bean definitions available there, and then initializes beans before any call to the getBean()
method.
During initialization, ApplicationContext
itself has initialized all the Spring beans configured in Spring XML. When another object makes a call to the getBean()
method, ApplicationContext
returns the same reference of bean that has already been initialized. This is the default behavior of beans.
This leads to the concept of a bean's scope. We can choose the number of instances of beans depending on the scope. There are different scopes in which a bean can be configured. The <bean>
tag has a scope
attribute that is used to configure the scope of the bean. There are different bean scopes in Spring, such as singleton, prototype, request, session, and global session. We will understand each session one by one.
Let's understand this by considering the following example, where we have the EmployeeService
interface, EmployeeServiceImpl
class, and PayrollSystem
class with the main()
method.
In the EmployeeService.java
interface, you'll find the following code:
package org.packt.Spring.chapter2.beanscope; public interface EmployeeService { void setMessage(String message); String getMessage(); }
In the preceding code snippet, the EmployeeService
interface declares two methods.
The following are the contents of the EmployeeServiceImpl.java
class:
package org.packt.Spring.chapter2.beanscope; import org.springframework.beans.factory.InitializingBean; public class EmployeeServiceImp implements EmployeeService { private String message; @Override public void setMessage(String message) { this.message = message; } @Override public String getMessage() { return this.message; } }
In the preceding code snippet, the EmployeeServiceImpl
class implemented the EmployeeService
interface.
In the beans.xml
file, you'll find the following code:
<?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="employeeServiceBean" class="org.packt.Spring.chapter2.beanscope.EmployeeServiceImpl"> </bean> </beans>
In the preceding configuration file, we defined employeeServiceBean
without any scope, to see the default nature of the bean.
In the PayrollSystem.java
class, you'll find the following code:
package org.packt.Spring.chapter2.beanscope; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class PayrollSystem { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext( "beans.xml"); // Retrieve for first time EmployeeService employeeServiceA = (EmployeeService) context .getBean("employeeServiceBean"); employeeServiceA.setMessage("Message by service A"); System.out .println("employeeServiceA: " + employeeServiceA.getMessage()); // Retrieve it again EmployeeService employeeServiceB = (EmployeeService) context .getBean("employeeServiceBean"); System.out .println("employeeServiceB: " + employeeServiceB.getMessage()); } }
In the preceding code snippet, the PayrollSystem
class has the main()
method. For the first time, we call getBean("employeeServiceBean")
, assign the bean to the employeeServiceA
variable of the EmployeeService
type, and then set the message by calling the setMessage()
method. Again, we call getBean("employeeServiceBean")
and assign the bean to the employeeServiceB
variable of the EmployeeService
type. The output after calling the getMessage()
method from both reference variable results is the same, as shown here:
org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1202d69: startup date [Sat Jan 24 20:04:30 IST 2015]; root of context hierarchy Jan 24, 2015 8:04:30 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions INFO: Loading XML bean definitions from class path resource [beans.xml] employeeServiceA: Message by service A employeeServiceB: Message by service A
By default, all Spring beans are singleton. Once ApplicationContext
is initialized, it looks at all the beans in XML and initializes only one bean per bean definition in Spring Container. On each call to the getBean()
method, Spring Container returns the same instance of the bean.
The first bean scope in Spring that is called is singleton, which initializes only one bean per bean definition in the container and returns the same instance reference on each call to the getBean()
method. This scope makes Spring initialize all beans during the load time itself without waiting for the getBean()
call.
In the beans.xml
file, you'll find the following code:
... <bean id="employeeServiceBean" class="org.packt.Spring.chapter2.beanscope.EmployeeServiceImpl" scope="singleton"> </bean> ...
In the preceding configuration file, we have a bean with a singleton scope. When we run PayrollSystem.java
, the output will be as follows:
org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1855562: startup date [Sat Jan 24 20:36:27 IST 2015]; root of context hierarchy Jan 24, 2015 8:36:28 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions INFO: Loading XML bean definitions from class path resource [beans.xml] employeeServiceA: Message by service A employeeServiceB: Message by service A
Since the EmployeeServiceImpl
bean is in the singleton scope, the second retrieval by employeeServiceB
will display the message set by employeeServiceA
even though it's retrieved by calling a new getBean()
method.
The singleton pattern in general says that overall there will be only one instance of the object. But when we talk about singleton in the Spring Framework, we are talking about Spring Container alone.
We can have multiple containers running in the same JVM, so we can have multiple instances of the same bean in same JVM.
So, singleton in Spring represents in a particular Spring container, and there is only one instance of a bean created in that container that is used across different references.
The prototype is second bean scope in Spring, which returns a brand-new instance of a bean on each call to the getBean()
method. When a bean is defined as a prototype, Spring waits for getBean()
to happen and only then does it initialize the prototype. For every getBean()
call, Spring has to perform initialization, so instead of doing default initialization while a context is being created, it waits for a getBean()
call. So, every time getBean()
gets called, it creates a new instance.
In the beans.xml
file, you'll find the following code:
... <bean id="employeeServiceBean" class="org.packt.Spring.chapter2.beanscope.EmployeeServiceImpl" scope="prototype"> </bean> ...
In the preceding configuration file, we have a bean with scope as a prototype. When we run the PayrollSystem.java
file, the output will be as follows:
org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1855562: startup date [Sat Jan 24 21:05:14 IST 2015]; root of context hierarchy Jan 24, 2015 9:05:15 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions INFO: Loading XML bean definitions from class path resource [beans.xml] employeeServiceA: Message by service A employeeServiceB: null
The configured destruction life cycle callbacks are not called in the case of a prototype. Spring doesn't maintain the complete life cycle of the prototype. Here, the container instantiates and configures prototype beans and returns this bean to the client with no further record of this prototype instance.
Since every getBean()
call creates a new instance of the prototype bean, this could lead to performance issues when beans use limited resources such as network connections, whereas it may be useful if you would like to get a new instance of a domain object, such as an employee
object.
The third bean scope in Spring is request, which is available only in web applications that use Spring and create an instance of bean for every HTTP request. Here, a new bean is created per Servlet request. Spring will be aware of when a new request is happening because it ties well with the Servlet APIs, and depending on the request, Spring creates a new bean. So, if the request scope has getBean()
inside it, for every new request, there will be a new bean. However, as long as it's in the same request scope, the same bean is going to be used.
The session is the fourth bean scope in Spring, which is available only in web applications that use Spring and create an instance of bean for every HTTP session. Here, a new bean is created per session. As long as there is one user accessing in a single session, each call to getBean()
will return same instance of the bean. But if it's a new user in a different session, then a new bean instance is created.