Spring Bean Scopes Guide

Read this tutorial to learn about Spring Bean Scopes. Spring Bean Scopes define the beans’ lifecycle and availability in the Application Context.

Spring Bean Scopes

We know the Spring Inversion of Control Container (IoC Container) creates and manages the beans in a Spring Application. Each bean we define as a Spring Bean declares its dependency and ways to provide the dependency injection. The beans can also specify how many bean instances should get created and in what scope they should stay alive.

That is done by the @Scope in the annotation-based configurations or scope attribute of bean tag on XML-based configurations. Below is the list of Scopes available in Spring.

  • Singleton (default)
  • Prototype
  • Request
  • Session
  • Application

Out of these 5, the Singleton and Prototype scopes are called Standard Scopes and are available in an ApplicationContext. The other scopes like Request, Session, and Application are available only in Web-Based Applications. We will look at each of them with the help of simple examples.

Singleton Scope

Singleton object is a significant concept of Object-Oriented Programming. A class is Singleton if we can create one and only one instance. Whenever any part of the application wants to access the object, they get the same instance.

Any Spring Bean, by default, is Singleton. When two classes auto-wire a class, they both get the same instance. Alternatively, a bean can explicitly declare itself as Singleton, like below.

Annotation-based configuration

@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
@Component
public class DogsDao {}Code language: Java (java)

XML configuration

<bean id="dogsDao" class="com.amitph.spring.dogs.dao.DogsDao" scope="singleton" />Code language: HTML, XML (xml)
NOTE: Throughout this tutorial the examples are based on Field Based Dependency Injections. That doesn’t mean, we recommend it. Field injections are in-line and helps reader to focus on the business.

Let’s try to auto-wire the dogsDao in two different beans, and then we will check the equality.

Next are two different service classes.

// Bean 1
@Component
public class DogsService {
    @Autowired private DogsDao dao;

    public DogsDao getDao() {
        return dao;
    }
}
...
// Bean 2
@Component
public class DogsService2 {
    @Autowired private DogsDao dao;

    public DogsDao getDao() {
        return dao;
    }
}Code language: Java (java)

Now, let’s auto-wire them.

@SpringBootApplication
public class Application implements CommandLineRunner {

    @Autowired DogsService service1;

    @Autowired DogsService2 service2;

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        System.out.println(service1.getDao().equals(service2.getDao()));
    }
}Code language: Java (java)

When we run the above code, the output we get is true. That indicates that both services got the same instance of Dao.

Prototype Scope

The prototype scope is precisely opposite to the Singleton. When any bean tries to auto-wire a prototype bean, every time a new instance is created and assigned, below is the way a bean can declare itself as a prototype.

Annotation Based Configuration

@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Component
public class DogsDao {}Code language: Java (java)

XML based configuration

<bean id="dogsDao" class="com.amitph.spring.dogs.dao.DogsDao" scope="prototype" />Code language: HTML, XML (xml)

Let’s auto-wire a dogsDao in two different classes and do the equality check

Next are

// Bean 1
@Component
public class DogsService {
    @Autowired private DogsDao dao;

    public DogsDao getDao() {
        return dao;
    }
}
...
// Bean 2
@Component
public class DogsService2 {
    @Autowired private DogsDao dao;

    public DogsDao getDao() {
        return dao;
    }
}Code language: Java (java)

Let’s inject the service classes.

@SpringBootApplication
public class Application implements CommandLineRunner {

    @Autowired DogsService service1;

    @Autowired DogsService2 service2;

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        System.out.println(service1.getDao().equals(service2.getDao()));
    }
}Code language: Java (java)

The equality check here results in false which indicates both of the services got separate instances of Dao.

Request Scope

The request scope is only available in Web Applications. Each request gets a dedicated instance of request-scoped beans, and the beans remain available until the request does.

Below is the way we can declare beans with the request scope.

@Component
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class DogDto {
    private String id;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
}Code language: Java (java)

Why do we need proxyMode = ScopedProxyMode.TARGET_CLASS ?

Because, the bean has request scope. That means an instance of the bean won’t be created until there is a request. But the classes auto-wire this bean (like Controller in our case) gets instantiated on the Web Application startup. Spring then creates a Proxy instance and inject in the controller. When the controller receives a request the proxy instance is replaced with actual one

Dogs Controller
It has dependency over the dto. When it receives a GET request, it first prints an id from the dto to see there was no previously set value on it. It then sets the id that can call a method on service (without passing the dto instance).

@RestController
@RequestMapping("/dogs")
public class DogsController {

    @Autowired DogDto dto;
    @Autowired DogsService service;

    @GetMapping("/{id}")
    public void get(@PathVariable String id) {
        System.out.println("DogsController\tid: " + dto.getId());
        dto.setId(id);
        service.getDogs();
    }
}Code language: Java (java)

Dogs Service
The Service class has a dependency over the dto. It has a method that prints the id.

@Component
public class DogsService {
    @Autowired private DogDto dto;

    public void getDogs() {
        System.out.println("DogsService\tid: " + dto.getId());
    }
}Code language: Java (java)

Let’s execute a GET request. http://localhost:8080/dogs/4444
Output:

DogsController    id: null
DogsService    id: 4444

And another request http://localhost:8080/dogs/5555
Output:

DogsController id: null
DogsService id: 5555

The thing to note here is that the first statement is null. That indicates, for each request, we get a different dto.

Session Scope

When a bean declares its scope as a session, the bean remains alive in the session. Each session gets a dedicated instance of the session-scoped beans. Let’s reuse the example we saw in the last section to try and see this running. The only change is that the bean has a session scope.

@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
Code language: Java (java)

When we run the same GET twice from the same browser, we should see the last request value persisted in the second request. While, if we make a second request from a different browser the dto is new.

Application Scope

The bean marked with scope application is created only once per Web Application. It is created when the application starts and destroyed when the application stops. The application scope is no different from Singleton except that the singleton bean is created in an ApplicationContext while the bean with application scope is created in a WebApplicationContext.

We can try the application scope with the same example used above. Only the difference is the scope attribute in the annotation.

@Scope(value = WebApplicationContext.SCOPE_APPLICATION, proxyMode = ScopedProxyMode.TARGET_CLASS)
Code language: Java (java)

While the application is running, each request will set a new value on the dto, and it is retained on the subsequent request. That doesn’t affect which browser the request comes.

Summary

Today you learned that Spring Beans have five scopes: Singleton, prototype, request, session, and application. The request, session, and application scopes are only applicable to Web Applications.

You also learned how to use these scopes and annotations to declare them.