Back to Spring Boot Course

Spring Boot Course

In Spring Boot (and Spring Framework), beans are objects that are managed by the Spring container. The lifecycle and visibility of these beans are determined by the scope of the bean, which defines how and when the Spring container creates and manages the bean instances. Spring provides several types of bean scopes, allowing you to define how beans are created, shared, and destroyed.

Here are the primary bean scopes in Spring Boot:

Singleton Scope (Default)

A single instance of the bean is created by the Spring container, and this instance is shared across the entire application context. Every time the bean is requested, the same instance is returned.

This is the default scope in Spring if no other scope is explicitly specified.

@Component public class MySingletonBean { // Singleton bean logic }

The bean is created once per Spring container (i.e., once per application context), and the same instance is reused for all calls.

No need for @Scope as Singleton is the default.

Real-World Example: Logging Service

A logging service doesn't need to be instantiated multiple times as it serves the same purpose across the entire application. We can use a Singleton for efficient resource management.

Let's see the code

LoggingService.java

import org.springframework.stereotype.Service; @Service // Singleton by default public class LoggingService { public void log(String message) { System.out.println("LOG: " + message); } }

LoggingController.java

import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class LoggingController { private final LoggingService loggingService; public LoggingController(LoggingService loggingService) { this.loggingService = loggingService; } @GetMapping("/log") public String logMessage() { loggingService.log("This is a log message."); return "Log created!"; } }

Why Singleton?

The LoggingService doesn't maintain any state and is the same across all parts of the application, making it ideal for Singleton scope.

Prototype Scope

A new instance of the bean is created every time the bean is requested. It's not shared across requests.

This scope is useful when you need a new instance each time you inject or request the bean.

For example,

@Component @Scope("prototype") public class MyPrototypeBean { // Prototype bean logic }

The Spring container will create a new bean instance each time you call getBean(). It's not shared across multiple requests.

Real-World Example: Invoice Generation

Imagine you're generating invoices where each invoice is unique and needs to be generated for each request.

Lets see the code

InvoiceService.java

import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Service; @Service @Scope("prototype") public class InvoiceService { public InvoiceService() { System.out.println("InvoiceService created"); } public String generateInvoice(String customerName) { return "Invoice for " + customerName + " generated!"; } }

InvoiceController.java

import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class InvoiceController { private final InvoiceService invoiceService; public InvoiceController(InvoiceService invoiceService) { this.invoiceService = invoiceService; } @GetMapping("/generate-invoice") public String generateInvoice(@RequestParam String customerName) { return invoiceService.generateInvoice(customerName); } }

Why Prototype?

Each time an invoice is generated, a new instance of the InvoiceService is needed because the data (invoice details) is different each time.

Request Scope (Web-specific)

A new bean is created for each HTTP request. This scope is available only in web applications and is tied to the lifecycle of a single HTTP request.

Often used in web applications when you want a bean to be tied to a single HTTP request.

For example,

@Component @Scope("request") public class MyRequestScopedBean { // Request-scoped bean logic }

Each HTTP request will have its own instance of the bean.

Real-World Example: User Request Data

Imagine a web application where you need to capture user preferences for each HTTP request.

Let's see the code

UserRequestData.java

import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @Component @Scope("request") public class UserRequestData { private String userAgent; private String ipAddress; public UserRequestData(String userAgent, String ipAddress) { this.userAgent = userAgent; this.ipAddress = ipAddress; } public String getUserAgent() { return userAgent; } public String getIpAddress() { return ipAddress; } }

UserRequestController.java

import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RestController; @RestController public class UserRequestController { private final UserRequestData userRequestData; public UserRequestController(UserRequestData userRequestData) { this.userRequestData = userRequestData; } @GetMapping("/user-request") public String captureUserData(@RequestHeader("User-Agent") String userAgent, @RequestHeader("X-Forwarded-For") String ipAddress) { userRequestData = new UserRequestData(userAgent, ipAddress); return "User Agent: " + userRequestData.getUserAgent() + ", IP Address: " + userRequestData.getIpAddress(); } }

Why Request Scope?

The UserRequestData bean is scoped to the HTTP request and captures information specific to the user’s current request, like the user-agent and IP address.

Session Scope (Web-specific)

A new bean is created for each HTTP session. This scope is also available only in web applications, and each session will have its own instance of the bean.

It's typically used when you need to store user-specific data across multiple requests during the user's session.

For example,

@Component @Scope("session") public class MySessionScopedBean { // Session-scoped bean logic }

A new instance is created for each HTTP session.

Real-World Example: Shopping Cart

A Shopping Cart is a classic example where session scope is beneficial. The cart is associated with a specific user session and should persist across requests until the session expires.

Let's see the code

ShoppingCart.java

import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; @Component @Scope("session") public class ShoppingCart { private List<String> items = new ArrayList<>(); public void addItem(String item) { items.add(item); } public List<String> getItems() { return items; } }

CartController.java

import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class CartController { private final ShoppingCart shoppingCart; public CartController(ShoppingCart shoppingCart) { this.shoppingCart = shoppingCart; } @GetMapping("/add-to-cart") public String addToCart(@RequestParam String item) { shoppingCart.addItem(item); return "Item added to cart!"; } @GetMapping("/view-cart") public List<String> viewCart() { return shoppingCart.getItems(); } }

Why Session Scope?

The ShoppingCart bean stores items that are specific to a user’s session. The cart should be persistent across multiple requests during the user’s session.

Application Scope (Web-specific)

A new bean is created for the entire lifecycle of the ServletContext. It's shared among all requests and sessions in the web application.

This scope is typically used for beans that need to exist throughout the entire lifetime of the application.

For example,

@Component @Scope("application") public class MyApplicationScopedBean { // Application-scoped bean logic }

The bean instance is shared across the entire application and is tied to the lifecycle of the servlet context.

Real-World Example: Application Configuration

An application-wide configuration setting, like the application name, version, or an external service connection that is initialized once and used across the application.

Let's see the code

ApplicationConfig.java

import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @Component @Scope("application") public class ApplicationConfig { private String appName = "My Spring Boot Application"; private String version = "1.0.0"; public String getAppName() { return appName; } public String getVersion() { return version; } }

ConfigController.java

import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class ConfigController { private final ApplicationConfig applicationConfig; public ConfigController(ApplicationConfig applicationConfig) { this.applicationConfig = applicationConfig; } @GetMapping("/app-config") public String getAppConfig() { return "App Name: " + applicationConfig.getAppName() + ", Version: " + applicationConfig.getVersion(); } }

Why Application Scope?

The ApplicationConfig bean holds settings that are constant and should be shared across the entire application (e.g., app name and version), which makes it suitable for application scope.

Global Session Scope (Web-specific)

Available only in a portlet-based application. It ties the bean to the global session.

Rarely used, specific to portlet-based web applications.

For example,

@Component @Scope("globalSession") public class MyGlobalSessionScopedBean { // Global session-scoped bean logic }

The bean will be created for the entire global session in a portlet application.

Real-World Example (Portlets)

If you're building portlet-based applications, you could store data related to the global user session across different portlet applications.

Let's see the code

GlobalSessionBean.java

import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @Component @Scope("globalSession") public class GlobalSessionBean { private String userRole; public String getUserRole() { return userRole; } public void setUserRole(String userRole) { this.userRole = userRole; } }

PortletController.java

import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class PortletController { private final GlobalSessionBean globalSessionBean; public PortletController(GlobalSessionBean globalSessionBean) { this.globalSessionBean = globalSessionBean; } @GetMapping("/set-role") public String setRole(String role) { globalSessionBean.setUserRole(role); return "User role set!"; } @GetMapping("/get-role") public String getRole() { return "User role: " + globalSessionBean.getUserRole(); } }

Why Global Session Scope?

The GlobalSessionBean is used in a Portlet application where data needs to persist across different portlets within the same global session.

Summary

screenshot of the app

In Spring Boot, the most commonly used scopes are Singleton and Prototype, but other scopes are available for web applications (request, session, and application). If you're developing a non-web Spring Boot application, singleton and prototype are typically the most useful. For web applications, you may encounter request and session scopes frequently.