SpringTechnology

Spring Bean Scopes Guide

Read this tutorial to learn about Spring Bean Scopes. Spring Bean Scopes define the lifecycle and the availability of the beans in 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. Along with this, the beans can also specify how many instances of the bean should get created and in what scope they should stay alive.

This is done by the @Scope in the annotation based configurations or scope attribute of bean tag on a 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 as Standard Scopes and are available in an ApplicationContext. The other scopes like Request, Session, and Application are available only in the Web Based Applications. We will look at each of them with the help of simple examples.

Singleton

Singleton object is an important concept of Object Oriented Programming. An object is called as Singleton if one and only one instance of that object is created. Whenever, any part of the application wants to access the object, exactly the same instance of the object is returned.

Any Spring Bean, by default, is Singleton. When two classes auto-wire a class they both get 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 {}

XML configuration

<bean id="dogsDao" class="com.amitph.spring.dogs.dao.DogsDao" scope="singleton" />
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-wirea the dogsDao in two different beans and then we will check the equality.

// 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;
    }
}
@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()));
    }
}

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

Prototype

The prototype scope is exactly opposite to the singleton. That means, 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 prototype.

Annotation Based Configuration

@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Component
public class DogsDao {}

XML based configuration

<bean id="dogsDao" class="com.amitph.spring.dogs.dao.DogsDao" scope="prototype" />

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

// 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;
    }
}
@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()));
    }
}

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

Request

The request scope is only available in the Web Applications. An instance of a bean with request scope is created for each HTTP request and remain available till the life of that request.

Below is the way a bean can be declared in 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;
    }
}

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, just to see there was no previously set value on it. It then sets the id can calls 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();
    }
}

Dogs Service
The Service class has a dependency over the dto. When service class’s method is called it just prints the id.

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

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

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 the first statement is null. That indicates, for each request we get a different dto.

Session

When a bean declares its scope as session, the bean remains alive in the session. For each session a new instance will be created. To try and see this running, let’s reuse the example we saw in last section. The only change is the bean has session scope.

@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)

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

Application

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 than singleton except that the singleton bean gets 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 scope attribute in the annotation.

@Scope(value = WebApplicationContext.SCOPE_APPLICATION, proxyMode = ScopedProxyMode.TARGET_CLASS)

Now while the application is running, each request will set a new value on dto, and is retained on the next request. This doesn’t affect which browser the request is made from.

Summary

Today you learnt the Spring Beans have 5 different scopes: singleton, prototype, request, session, and application. The request, session, and application scopes are only applicable to Web Applications.

You also learnt how to use these scope and use annotations to declare them.