Read this tutorial to learn about Spring Bean Scopes. Spring Bean Scopes define the beans’ lifecycle and availability in the Application Context.
Tutorial Contents
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)
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 classesauto-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.