<

I just announced the new Spring 5 modules in REST With Spring:

>> CHECK OUT THE COURSE

1. Overview

In this quick tutorial, you’ll learn about the different types of bean scopes in the Spring framework.

The scope of a bean defines the life cycle and visibility of that bean in the contexts in which it is used.

Spring defines 5 types of scopes:

  • singleton
  • prototype
  • request
  • session
  • globalSession

The last three scopes mentioned, request, session and globalSession are only available in a web-aware application.

2. Singleton Scope

Defining a bean with singleton scope means the container creates a single instance of that bean, and all requests for that bean name will return the same object, which is cached. Any modifications to the object will be reflected in all references to the bean. This scope is the default value if no other scope is specified.

Let’s create a Person entity to exemplify the concept of scopes:

public class Person {
    private String name;

    // standard constructor, getters and setters
}

Afterwards, we define the bean with singleton scope by using the @Scope annotation:

@Bean
@Scope("singleton")
public Person personSingleton() {
    return new Person();
}

We can also use a constant instead of the String value in the following manner:

@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)

Now we proceed to write a test that shows that two objects referring to the same bean will have the same values, even if only one of them changes their state, as they are both referencing the same bean instance:

private static final String NAME = "John Smith";

@Test
public void givenSingletonScope_whenSetName_thenEqualNames() {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("scopes.xml");

    Person personSingletonA = (Person) applicationContext.getBean("personSingleton");
    Person personSingletonB = (Person) applicationContext.getBean("personSingleton");

    personSingletonA.setName(NAME);
    Assert.assertEquals(NAME, personSingletonB.getName());

    ((AbstractApplicationContext) applicationContext).close();
}

The scopes.xml file in this example should contain the xml definitions of the beans used:

<?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="personSingleton" class="org.baeldung.scopes.Person" scope="singleton"/>    
</beans>

3. Prototype Scope

A bean with prototype scope will return a different instance every time it is requested from the container. It is defined by setting the value prototype to the @Scope annotation in the bean definition:

@Bean
@Scope("prototype")
public Person personPrototype() {
    return new Person();
}

We could also use a constant as we did for the singleton scope:

@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)

We will now write a similar test as before that shows two objects requesting the same bean name with scope prototype will have different states, as they are no longer referring to the same bean instance:

private static final String NAME = "John Smith";
private static final String NAME_OTHER = "Anna Jones";

@Test
public void givenPrototypeScope_whenSetNames_thenDifferentNames() {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("scopes.xml");

    Person personPrototypeA = (Person) applicationContext.getBean("personPrototype");
    Person personPrototypeB = (Person) applicationContext.getBean("personPrototype");

    personPrototypeA.setName(NAME);
    personPrototypeB.setName(NAME_OTHER);

    Assert.assertEquals(NAME, personPrototypeA.getName());
    Assert.assertEquals(NAME_OTHER, personPrototypeB.getName());

    ((AbstractApplicationContext) applicationContext).close();
}

The scopes.xml file is similar to the one presented in the previous section, while adding the xml definition for the bean with prototype scope:

<bean id="personPrototype" class="org.baeldung.scopes.Person" scope="prototype"/>

4. Web Aware Scopes

As mentioned, there are three additional scopes that are only available in a web-aware application context. These are less often used in practice.

The request scope creates a bean instance for each HTTP request. Session scope creates an instance for an HTTP Session, and the globalSession scope creates an instance for a global HTTP Session.

We will create a class to use for instantiating the beans:

public class HelloMessageGenerator {

    private String message;
    
    // standard getter and setter
}

4.1. Request Scope

We can define the bean with request scope using the @Scope annotation:

@Bean
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public HelloMessageGenerator requestMessage() {
    return new HelloMessageGenerator();
}

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.

Next we can define a controller that has an injected reference to the requestMessage bean. 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 run, we can see that the value for the requestMessage bean 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 ScopesController {
    @Resource(name = "requestMessage")
    HelloMessageGenerator requestMessage;

    @RequestMapping("/scopes")
    public String getScopes(Model model) {
        requestMessage.setMessage("Good morning!");
        model.addAttribute("requestMessage", requestMessage.getMessage());
        return "scopesExample";
    }
}

4.2. Session Scope

We can define the bean with session scope in a similar manner:

@Bean
@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public HelloMessageGenerator sessionMessage() {
    return new HelloMessageGenerator();
}

Next we define a controller with a reference to the sessionMessage bean.

Again, 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 ScopesController {
    @Resource(name = "sessionMessage") 
    HelloMessageGenerator sessionMessage; 
    
    @RequestMapping("/scopes")
    public String getScopes(Model model) {
        sessionMessage.setMessage("Good afternoon!");
        model.addAttribute("sessionMessage", sessionMessage.getMessage());
        return "scopesExample";
    }
}

4.3. GlobalSession Scope

The bean with globalSession scope can be defined using the same @Scope annotation:

@Bean
@Scope(value = WebApplicationContext.SCOPE_GLOBAL_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public HelloMessageGenerator globalSessionMessage() {
    return new HelloMessageGenerator();
}

This type of scope is used in applications with a portlet container, each portlet having its own session. The beans with this scope will be available over all sessions.

5. Conclusion

We have demonstrated how to define bean scopes and what their intended usages are.

The implementation of this tutorial can be found in the github project – this is an Eclipse based project, so it should be easy to import and run as it is.

I just announced the new Spring 5 modules in REST With Spring:

>> CHECK OUT THE LESSONS