Spring Beans Scope

Spring Bean Scopes Explained

Learn all about Spring bean scopes, their differences, and practical examples. Discover which scope suits your application best.

Introduction

In the Spring Framework, beans are the essential building blocks that represent objects managed by the Spring IoC (Inversion of Control) container. Each bean can have a specific scope, defining how many instances of the bean will be created and how long these instances will live within the Spring application context. Understanding Spring bean scopes is crucial for developing efficient and scalable applications. In this comprehensive guide, we will explore various Spring bean scopes, including Singleton, Prototype, Request, Session, Application, and WebSocket. We will explain each scope in detail with examples, and offer insights into when to use them. Let’s dive in!

What are Spring Bean Scopes?

In Spring, a bean’s scope defines the lifecycle and visibility of the bean instance within the application context. It determines how long the bean remains in memory and how it is accessed by different parts of the application. Spring offers several built-in bean scopes, each serving specific use cases and scenarios.



Singleton Scope: One Bean to Rule Them All

  • The Singleton scope is the default scope for Spring Beans if no explicit scope is defined.
  • When a bean is defined with the Singleton scope, the Spring IoC container creates and manages a single instance of the bean for the entire application context.
  • Every time the bean is requested, the same instance is returned, and subsequent requests for the bean will reuse this single instance.
  • This means that all parts of the application that use the bean will share the same instance, potentially leading to thread-safety concerns.
  • Singleton beans are generally used for stateless services and managing shared resources across the application.

Example:
In this example, we have a Spring Bean named SingletonBean with a Singleton scope. This means that Spring will only create a single instance of this bean for the entire application context.

When we access the SingletonBean using the Spring context, we always get the same instance, and any changes made to that instance are visible across all the references. In the given code snippet, the SingletonBean contains a counter that increments each time we call the getCounter() method.

import org.springframework.stereotype.Component;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;

// Explicitly stating that a particular bean is of type singleton. Two ways to define the scope.
// @Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
// @Scope("Singleton") 
@Component
public class SingletonBean {
    private int counter = 0;

    public int getCounter() {
        return counter++;
    }
}
SingletonBean.java

By default, each and every bean is of type Singleton but you can explicitly specify that a particular bean is of type single using a Scope annotation with value as a singleton.

@SpringBootApplication
public class HelloWorldApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext applicationContext = SpringApplication.run(HelloWorldApplication.class, args);

        SingletonBean bean1 = applicationContext.getBean(SingletonBean.class);
        System.out.println("Counter Value: " + bean1.getCounter()); // Output: 0

        SingletonBean bean2 = applicationContext.getBean(SingletonBean.class);
        System.out.println("Counter Value: " + bean2.getCounter()); // Output: 1

        SingletonBean bean3 = applicationContext.getBean(SingletonBean.class);
        System.out.println("Counter Value: " + bean3.getCounter()); // Output: 2
    }

}
HelloWorldApplication.java

Output:

This demonstrates that each time we access the getCounter() method, the same SingletonBean instance is used, and the counter increments accordingly.



Prototype Scope: Every Bean for Itself

  • The Prototype scope defines that a new instance of the bean should be created every time it is requested from the Spring IoC container.
  • Unlike Singleton, Prototype beans do not maintain a single shared instance; instead, each request for the bean creates a new instance.
  • This makes Prototype beans ideal for stateful components as each client requesting the bean gets a fresh instance.
  • Prototype-scoped beans can be more memory-intensive, so use them carefully.

Example:

In this example, we have a Spring Bean named PrototypeBean with a Prototype scope. This means that every time we request a bean of this type from the Spring context, a new instance is created.

When we access the PrototypeBean using the Spring context, we get a new instance of the bean each time, and any changes made to that instance are isolated to that particular instance only. In the given code snippet, the PrototypeBean contains a counter that increments each time we call the getCounter() method.

import org.springframework.stereotype.Component;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;

@Component
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
class PrototypeBean {
    private int counter = 0;

    public int getCounter() {
        return counter++;
    }
}
PrototypeBean.java
@SpringBootApplication
public class HelloWorldApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext applicationContext = SpringApplication.run(HelloWorldApplication.class, args);

        PrototypeBean bean1 = applicationContext.getBean(PrototypeBean.class);
        System.out.println("Counter Value: " + bean1.getCounter()); // Output: 0

        PrototypeBean bean2 = applicationContext.getBean(PrototypeBean.class);
        System.out.println("Counter Value: " + bean2.getCounter()); // Output: 0

        PrototypeBean bean3 = applicationContext.getBean(PrototypeBean.class);
        System.out.println("Counter Value: " + bean3.getCounter()); // Output: 0
    }

}
HelloWorldApplication.java

Output:

This demonstrates that each time we access the getCounter() method, a new PrototypeBean instance is created, and the counter starts from zero for each instance independently.



Request Scope: Unique Beans for Each HTTP Request

  • The Request scope is specific to web applications and only valid in the context of a web-aware Spring ApplicationContext.
  • When a bean is defined with the Request scope, a new instance of the bean is created for each HTTP request.
  • This is particularly useful for handling request-specific data, as each user’s request gets its own isolated instance of the bean.
  • This scope ensures that each user request is isolated and doesn’t interfere with other requests.
  • Request-scoped beans are thread-safe within the context of a single HTTP request.

The Working Principle

In a web application context, when a user sends an HTTP request to the server, Spring creates a new instance of the bean associated with the Request scope. This instance remains available throughout the duration of that specific request. Once the request is processed and the response is sent back to the user, the bean is discarded, and its resources are released.

Example:
In this example, we have a special bean (RequestBean) that keeps track of the number of times it’s accessed within a single web request. The REST Controller (HelloWorldController) uses this bean to show how the count resets with each new HTTP request, ensuring a fresh count for every user interaction.

import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Component;

@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestBean {
    private int counter = 0;

    public int getCounter() {
        return counter++;
    }
}
RequestBean.java

By using proxyMode = ScopedProxyMode.TARGET_CLASS, we are resolving the issue of accessing request-scoped beans from singleton-scoped beans in a web context. It ensures that each request gets its own instance of the RequestBean, and the proxy takes care of managing the correct instances based on the request context.

@RestController
public class CounterController {

    @Autowired
    private RequestBean requestBean;

    @GetMapping("/get-counter-value")
    public String counterValue() {
        int currentCounterValue = requestBean.getCounter();
        System.out.println("Counter value: " + currentCounterValue);

        currentCounterValue = requestBean.getCounter();
        System.out.println("Counter value post increment: " + currentCounterValue);

        // return incremented counter value
        return "Counter value: " + currentCounterValue;
    }
}
CouterController.java

Output:

Each time you access the /get-counter-value endpoint, a new instance of RequestBean is created for that specific request, and the counter increments independently. This demonstrates the request scope behavior, and the proxy ensures that each request gets its own instance of the RequestBean.



Session Scope: Beans Bound to User Sessions

  • The Session scope is also specific to web applications and valid in the context of a web-aware Spring ApplicationContext.
  • When a bean is defined with the Session scope, a new instance of the bean is created for each user session.
  • This ensures that each user interacting with the application gets a separate instance of the bean, maintaining session-specific data.
  • Session-scoped beans are useful for managing user-specific information throughout their session.

The Working Principle

In a web application context, when a user starts a session (e.g., by logging in), Spring creates a new instance of the bean associated with the Session scope. This bean instance remains available and shared throughout the entire duration of that user’s session. Once the user’s session ends (e.g., by logging out or session timeout), the bean is discarded, and its resources are released.

Example:
In this example, we have a Spring Bean named SessionBean, designed with session scope, which means it retains its state throughout a user’s session. The SessionBean has a counter that increments each time the getCounter() method is called. We also have a REST Controller named CounterController, which utilizes the SessionBean. When the endpoint /get-counter-value is accessed, the CounterController calls the getCounter() method multiple times. As a result, the counter increments with each call within the same user session, and the updated value is returned in the response. This session-scoped bean ensures that each user maintains an independent counter value, allowing separate counting for different users interacting with the application.

import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Component;

@Component
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class SessionBean {
    private int counter = 0;

    public int getCounter() {
        return counter++;
    }
}
SessionBean.java

By using proxyMode = ScopedProxyMode.TARGET_CLASS, we are resolving the issue of accessing session-scoped beans from singleton-scoped beans in a web context. It ensures that each user session gets its own unique instance of the SessionBean, and the proxy handles managing the correct instances based on the user’s session context.

@RestController
public class CounterController {

    @Autowired
    private SessionBean sessionBean;

    @GetMapping("/get-counter-value")
    public String counterValue() {
        int couterValue = sessionBean.getCounter();
        System.out.println("Session Bean Counter: " + couterValue);

        couterValue = sessionBean.getCounter();
        System.out.println("Session Bean Counter: " + couterValue);

        couterValue = sessionBean.getCounter();
        System.out.println("Session Bean Counter: " + couterValue);

        // return incremented counter value
        return "Counter value: " + couterValue;
    }
}
CouterController.java

Output:

With the SessionBean set to session scope, every time a user starts a new session and accesses the /get-counter-value endpoint, a unique instance of SessionBean is created. The counter within the SessionBean increments independently for each method call within the same user session. This demonstrates the session scope behavior, where the same bean instance persists throughout the user’s session, ensuring separate counting for each user’s interaction with the application.



Application Scope: Beans Across the Entire Application

  • The Application scope is specific to web applications and valid in the context of a web-aware Spring ApplicationContext.
  • When a bean is defined with the Application scope, a single instance of the bean is created for the entire ServletContext.
  • This means that the same instance will be shared across all user sessions and requests within the application.
  • Application-scoped beans are useful for objects that need to maintain state globally across the application.

The Working Principle

In a web application context, when the application starts, Spring creates a single instance of the bean associated with the Application scope. This instance remains available throughout the entire lifecycle of the web application until it is shut down.

Example:
In this example, we use the custom “application” scope for the ApplicationBean. This scope behaves similar to the singleton scope but persists throughout the entire application’s lifetime. The CounterController uses the ApplicationBean instance, and the getCounter() method increments the counter each time it’s called. Since the “application” scope ensures that there’s only one instance of the bean throughout the application, the counter value will persist across different HTTP requests, showing the application scope behavior.

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope("application")
public class ApplicationBean {
    private int counter = 0;

    public int getCounter() {
        return counter++;
    }
}
ApplicationBean.java
@RestController
public class CounterController {

    @Autowired
    private ApplicationBean applicationBean;

    @GetMapping("/get-counter-value")
    public String counterValue() {
        int currentValue = applicationBean.getCounter();
        System.out.println("Counter value: " + currentValue);

        return "Counter value: " + currentValue;
    }
}
CouterController.java

Output:



WebSocket Scope: Beans for Real-Time WebSockets

  • The WebSocket scope is specific to web applications and valid in the context of a web-aware Spring ApplicationContext.
  • When a bean is defined with the WebSocket scope, a single instance of the bean is created for each WebSocket connection.
  • This scope is useful for managing WebSocket-specific data for individual clients connected to the application.
  • WebSocket-scoped beans are ideal for real-time applications using WebSocket communication.

The Working Principle

The WebSocket scope is specific to web applications and creates a single instance of a bean for each WebSocket connection. When a client establishes a WebSocket connection with the server, Spring creates a new instance of the bean associated with the WebSocket scope. The WebSocket-scoped bean instance remains available throughout the entire duration of that specific WebSocket connection. This allows the WebSocket-scoped bean to hold session-specific data and manage WebSocket interactions independently for each client session.

Example:
Let’s consider a chat application where multiple users can connect via WebSocket to participate in real-time chat. Each WebSocket session corresponds to a single user, and we want to maintain user-specific data for each session.

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;

@Component
@Scope(scopeName = "websocket", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class WebSocketSessionBean {
    private WebSocketSession webSocketSession;
    private String username;

    // Getter and Setter methods for webSocketSession and username
}
WebSocketSessionBean.java

In this example, we define a WebSocketSessionBean with the WebSocket scope. When a new WebSocket connection is established, Spring creates a new instance of this bean and associates it with the WebSocket session. The WebSocketSessionBean can then hold the WebSocketSession and other user-specific data, such as the username.

With the WebSocket scope, you can manage WebSocket-related state and handle user-specific data during WebSocket interactions, providing a seamless real-time experience for your web application users.



Comparison of Spring Bean Scopes

Let’s compare the characteristics of each Spring bean scope.

ScopeCharacteristicsUsage
Singleton– Single shared instance per container– Global configuration
– Same instance returned for all requests– Stateless services
– Potential thread-safety concerns– Application-wide beans
Prototype– New instance per request or injection– Stateful components
– Increased memory usage due to multiple instances– Data-access objects
Request– New instance per HTTP request– Request-specific data and handlers
– Isolated for each user request– User session management
Session– Single instance per user session– User-specific data and shopping carts
– Persists throughout a user’s session– User authentication and session management
Application– Single instance per web application– Application-wide settings and constants
– Shared across all users and components– Global configuration
WebSocket– Single instance per WebSocket connection– Real-time WebSocket communication
– Specific to web applications– WebSocket message handling


FAQs

Can I use multiple scopes for the same bean definition?

No, a single bean definition can have only one scope. If you need different scopes for different scenarios, you should define multiple bean definitions with corresponding scopes.

Can I change the scope of a bean at runtime?

No, the scope of a bean is defined at the time of bean creation and cannot be changed at runtime. Once the bean is instantiated with a specific scope, it remains the same throughout its lifecycle.

What is the default scope for Spring beans?

The default scope for Spring beans is “singleton.” It means that only one instance of the bean is created and shared across the entire application.

What is the difference between Singleton and Prototype scopes?

Singleton scope creates a single shared instance of the bean, while Prototype scope creates a new instance of the bean whenever requested. Singleton beans are suitable for stateless services, while Prototype beans are used for stateful components.

How do I decide which scope to use for my beans?

The choice of scope depends on the specific use case and requirements of the bean. Use Singleton for stateless services and Application-wide beans, Prototype for stateful components, and Request or Session for web-specific data management.

Things to Consider

When choosing the scope for Spring beans, there are several important factors to consider:

  1. Functionality: Understand the behavior and requirements of the bean. Determine if it needs to maintain state or hold global configurations.
  2. Concurrency: Consider thread safety if the bean will be accessed by multiple threads simultaneously. Choose the appropriate scope to avoid potential concurrency issues.
  3. Memory Usage: Be mindful of memory consumption, especially with prototype scope, as it creates new instances on every request, potentially increasing memory usage.
  4. Dependency Management: Be cautious when using prototype-scoped beans with circular dependencies, as it can lead to dependency resolution issues.
  5. Transaction Management: For beans involved in transactions, such as data access objects, choose the appropriate scope to ensure consistent transaction behavior.
  6. Web Applications: In web applications, use request scope for request-specific data and session scope for user-specific data.
  7. Singletons for Statelessness: Consider using singleton scope for stateless services, as it reduces memory overhead and improves performance.
  8. Prototype for Stateful Components: Use prototype scope for stateful components where a new instance is required for each interaction.
  9. Testing: Consider the impact of scope on testing. Prototype scope may require additional setup and teardown in unit tests.
  10. Bean Lifecycle: Understand how bean initialization, destruction, and cleanup methods are affected by different scopes.
  11. Configuration and Maintenance: Choose scopes that align with the application’s configuration and maintenance needs.

Conclusion

Understanding Spring bean scopes is crucial for effectively managing the lifecycle and behavior of your beans in a Spring application. By selecting the appropriate scope for each bean, you can optimize resource usage, ensure thread safety, and manage data efficiently across different parts of your application. Choose the scope that best suits your specific use case and enhances the overall performance and user experience of your application.



Learn More

#

Interested in learning more?

Check out our blog on how to gracefully terminate the Spring Boot application.

Add a Comment

Your email address will not be published.