Java Spring framework has several different bean scopes. Today I’ll explain the meaning of each Spring beanscope.
The scope of a bean defines the life cycle and visibility of that bean in the contexts in which it is used.
Java Spring defines 5 different types of scopes:
- Singleton
- Prototype
- Request
- Session
- GlobalSession
Request
, Session
and GlobalSession
scopes are only for a web-application.
Singleton Scope
Defining a bean with Singleton
scope means that container creates a single instance of that bean, and all requests for that bean name will return the same cached object. Any modifications to the object will be reflected in all references to the bean. This scope is the default scope in Java Spring.
I’ll create a simple Employee class to show Spring scopes concept:
public class Employee { private String name; private String position; // ... }
Now, let’s define the bean with Singleton
scope by using Spring @Scope
annotation:
@Bean @Scope("singleton") public Employee employeeSingleton() { return new Employee(); }
Now let’s test our code to ensure that two objects referring to the same bean with the same values:
private static final String NAME = "Bob Norton"; private static final String POSITION= "Software Engineer"; @Test public void singletonScopeTest() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("scopes.xml"); Employee employeeOne = (Employee) applicationContext.getBean("employeeSingleton"); Employee employeeTwo = (Employee) applicationContext.getBean("employeeSingleton"); employeeOne.setName(NAME); Assert.assertEquals(NAME, employeeTwo.getName()); employeeOne.setName(POSITION); Assert.assertEquals(POSITION, employeeTwo.getName()); ((AbstractApplicationContext) applicationContext).close(); }
The scopes.xml
contains the xml definitions of the beans:
<?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="employeeSingleton" class="com.codeflex.scopes.Employee" scope="singleton"/> </beans>
Prototype Scope
A bean with Prototype
scope will return a different instance every time it is requested from the container:
@Bean @Scope("prototype") public Employee employeePrototype() { return new Employee(); }
private static final String BOB = "Bob Norton"; private static final String JOE = "Joe Newton"; @Test public void prototypeScopeTest() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("scopes.xml"); Person employeeOne = (Person) applicationContext.getBean("employeePrototype"); Person employeeTwo = (Person) applicationContext.getBean("employeePrototype"); employeeOne.setName(BOB); employeeTwo.setName(JOE); Assert.assertEquals(BOB, employeeOne.getName()); Assert.assertEquals(JOE, employeeTwo.getName()); ((AbstractApplicationContext) applicationContext).close(); }
Don’t forget to edit scopes.xml
file and change definition for the bean with prototype
scope instead of singleton
:
<bean id="employeeSingleton" class="com.codeflex.scopes.Employee" scope="prototype"/></beans>
Web Application Scopes
Request
scope – creates a bean instance for each HTTP request.
Session
scope – creates an instance for an HTTP Session
GlobalSession
scope – creates an instance for a global HTTP Session.
This is our sample class:
public class Messenger{ private String message; // ... }
Request Scope
Defining the bean with Request
scope:
@Bean @Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS) public Messenger requestMessage() { return new Messenger(); }
The proxyMode
attribute is necessary because at the moment of the instantiation of the web application context, there is no active request. Spring will create a proxy to be injected as a dependency, and instantiate the target bean when it is needed in a request.
Now, let’s define a controller
that has an injected reference to the Messenger. We need to access the same request twice in order to test the web specific scopes. If we display the message each time the request is running, we can see that the value for the Messenger will go back to the value null
, even though it is later changed in the method, because we have a different bean instance for each request.
@Controller public class SpringScopesController { @Resource(name = "requestMessage") Messenger requestMessage; @RequestMapping("/scopes") public String getScopes(Model model) { requestMessage.setMessage("Java Spring Scopes Explained!"); model.addAttribute("requestMessage", requestMessage.getMessage()); return "scopesExample"; } }
Session Scope
Let’s define a bean with Session
scope in a similar manner:
@Bean @Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS) public Messenger requestMessage() { return new Messenger(); }
Next I define a controller with a reference to the sessionMessage
bean.
Same, we need to run two requests in order to show that the value of the message field is the same for the session. If we call the request that sets the message for the bean reference once, and then make the same call again and display the message, we will see the value previously set, because there is only one instance of a bean per session:
@Controller public class SpringScopesController { @Resource(name = "sessionMessage") Messenger sessionMessage; @RequestMapping("/scopes") public String getScopes(Model model) { sessionMessage.setMessage("Java Spring Scopes Explained!"); model.addAttribute("sessionMessage", sessionMessage.getMessage()); return "scopesExample"; } }
GlobalSession Scope
@Bean @Scope(value = WebApplicationContext.SCOPE_GLOBAL_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS) public Messenger requestMessage() { return new Messenger(); }
This type of scope is used in applications with a portlet container, each portlet has its own session. The beans with GlobalSession
scope will be available over all sessions.