In Spring Framework, bean scope defines the lifecycle and visibility of a bean — i.e., how many instances of a bean are created and how they are shared within the container. Spring provides several built-in scopes (some are for regular apps, others specific to web apps).
1. singleton (default)
Definition: Only one instance of the bean per Spring IoC container.
- Single instance is cached in the container.
- All
@Autowired
injections of that bean will point to the same instance. - In Spring, every bean has
singleton
scope by default unless you explicitly specify another scope using@Scope
(or XML config).
Best for: Reusable components.
Bean type: Stateless
Real-time use case:
- Service layer classes (UserService, ProductService)
- DAO classes (UserRepository, OrderRepository)
- Utility classes like logging or configuration readers
Example:
@RestController
@RequestMapping("/users")
public class UserController {
private final UserService userService; // singleton
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
return userService.getUserById(id);
}
}
@Service
public class UserService { // By default singleton scoped
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public User getUserById(Long id) {
return userRepository.findById(id).orElseThrow();
}
}
@Repository
public interface UserRepository extends JpaRepository<User, Long> { }
Use case: Shared, stateless beans (business logic, database access, controllers)
Analogy: CEO of a company – only one CEO manages the entire organization.
👉 Almost 90% of beans in real Spring Boot apps are singletons.
2. prototype
Definition: A new bean instance is created each time it’s requested.
Best for: Stateful beans where each caller needs a fresh instance.
Bean type: Stateful
Real-time use case:
- PDF reports (each report generation is independent)
- Temporary user session data (non-web contexts)
- Game objects (different players/characters)
Example:
@Component
@Scope("prototype")
public class ReportGenerator {
public void generateReport() {
System.out.println("New Report instance: " + this);
}
}
@Service
public class ReportService {
private final ObjectProvider<ReportGenerator> reportProvider;
public ReportService(ObjectProvider<ReportGenerator> reportProvider) {
this.reportProvider = reportProvider;
}
public void createReport() {
ReportGenerator generator = reportProvider.getObject(); // new instance
generator.generateReport();
}
}
Use case: PDF/Excel generation, notification builders, temporary objects
Analogy: Visitor badge at office – every time a visitor comes, they get a new badge.
Stateless vs Stateful Beans
- Stateless Beans: Do not hold any user-specific or instance-specific data between method calls. Safe to use as a singleton because the same instance can serve multiple users without conflicts.
Example: Service layer classes like UserService or utility classes like logging.
- Stateful Beans: Hold data specific to a user or a task. If shared (singleton), the state can leak between requests/users. Prototype scope ensures each caller gets a fresh instance.
Example: PDF report generation, shopping carts, session-based data.
Singleton vs Prototype: Why Stateful Beans Need Prototype?
Sometimes, beans store user-specific data (stateful). If we use singleton for such beans, data can leak between users. Prototype scope solves this.
1. Singleton Example (Problematic)
@Component // By default, Spring beans are singleton-scoped
public class SingletonPdfGenerator {
private String fileName;
public SingletonPdfGenerator() {
this.fileName = "Invoice_" + UUID.randomUUID() + ".pdf";
}
public void generate(String customerName) {
System.out.println("Using " + fileName + " for " + customerName);
}
}
@Service
public class SingletonInvoiceService {
private final SingletonPdfGenerator pdfGenerator;
public SingletonInvoiceService(SingletonPdfGenerator pdfGenerator) {
this.pdfGenerator = pdfGenerator;
}
public void createInvoice(String customerName) {
pdfGenerator.generate(customerName);
}
}
Output:
Using Invoice_1234.pdf for Alice
Using Invoice_1234.pdf for Bob
Using Invoice_1234.pdf for Charlie
👉 Problem:
- Same file reused for all users → risk of data corruption
- Singleton is unsafe for stateful tasks
Analogy: Using the same visitor badge for everyone — confusion is inevitable.
2. Prototype Example (Correct Approach)
@Component
@Scope("prototype")
public class PrototypePdfGenerator {
private String fileName;
public PrototypePdfGenerator() {
this.fileName = "Invoice_" + UUID.randomUUID() + ".pdf";
}
public void generate(String customerName) {
System.out.println("Using " + fileName + " for " + customerName);
}
}
@Service
public class PrototypeInvoiceService {
private final ObjectProvider<PrototypePdfGenerator> pdfProvider;
public PrototypeInvoiceService(ObjectProvider<PrototypePdfGenerator> pdfProvider) {
this.pdfProvider = pdfProvider;
}
public void createInvoice(String customerName) {
PrototypePdfGenerator pdf = pdfProvider.getObject(); // NEW instance every call
pdf.generate(customerName);
}
}
Output:
Using Invoice_9876.pdf for Alice
Using Invoice_6543.pdf for Bob
Using Invoice_3210.pdf for Charlie
Correct Behavior:
- Each user gets a new instance → no overlap
- Prototype scope ensures stateful beans remain independent
Key Takeaways
Scope | Behavior for Stateful Tasks |
Singleton | One object reused → unsafe for tasks storing user-specific data |
Prototype | New object per request → safe and isolated |
Analogy:
- Singleton: One shared visitor badge → causes mix-ups
- Prototype: Each visitor gets their own badge → no conflict
Definition: New bean instance per HTTP request
Best for: Request-specific data processing
Bean type: Stateful
Real-time use case: Request metadata (requestId, headers), form validation
Example:
@Component
@Scope("request")
public class RequestMetadata {
private final String requestId = UUID.randomUUID().toString();
public String getRequestId() { return requestId; }
}
@RestController
@RequestMapping("/orders")
public class OrderController {
private final RequestMetadata requestMetadata;
public OrderController(RequestMetadata requestMetadata) {
this.requestMetadata = requestMetadata;
}
@GetMapping
public String placeOrder() {
return "Order placed with Request ID: " + requestMetadata.getRequestId();
}
}
Use case: Request tracing, audit logging, validation
Analogy: Order receipt in a restaurant – every order generates a new receipt.
Definition: One bean instance per HTTP session
Best for: User-specific data across multiple requests
Bean type: Stateful
Real-time use case: Shopping cart, user preferences, authentication tokens
Example:
@Component
@Scope("session")
public class ShoppingCart {
private final List<String> items = new ArrayList<>();
public void addItem(String item) { items.add(item); }
public List<String> getItems() { return items; }
}
@RestController
@RequestMapping("/cart")
public class CartController {
private final ShoppingCart shoppingCart;
public CartController(ShoppingCart shoppingCart) {
this.shoppingCart = shoppingCart;
}
@PostMapping("/add/{item}")
public String addItem(@PathVariable String item) {
shoppingCart.addItem(item);
return "Item added: " + item;
}
@GetMapping
public List<String> viewCart() {
return shoppingCart.getItems();
}
}
Use case: Session-based authentication, user preferences
Analogy: Shopping cart – same cart for the entire session.
Definition: Single bean per ServletContext (web app)
Best for: Application-wide shared resources
Bean type: Stateless
Real-time use case: Cache, global configuration, application statistics
Example:
@Component
@Scope("application")
public class AppStatistics {
private int visitorCount = 0;
public synchronized void incrementVisitorCount() { visitorCount++; }
public int getVisitorCount() { return visitorCount; }
}
@RestController
@RequestMapping("/stats")
public class StatisticsController {
private final AppStatistics statistics;
public StatisticsController(AppStatistics statistics) {
this.statistics = statistics;
}
@GetMapping
public String getStats() {
statistics.incrementVisitorCount();
return "Total visitors: " + statistics.getVisitorCount();
}
}
Use case: Global counters, cache managers
Analogy: Notice board – visible to everyone.
Definition: One bean instance per WebSocket session
Best for: Real-time communication
Bean type: Stateful
Real-time use case: Chat apps, live streams, multiplayer games
Example:
@Component
@Scope("websocket")
public class ChatSession {
private String username;
public void setUsername(String username) { this.username = username; }
public String getUsername() { return username; }
}
Use case: Chat apps, live streams
Analogy: Private call line – each user has their own connection.
1. Annotation-based:
@Component
@Scope("prototype")
public class MyBean { }
2. XML-based:
<bean id="myBean" class="com.example.MyBean" scope="prototype"/>
Scope | Description | Lifecycle | Real-Time Use Cases |
singleton | One bean per container (default) | Container-wide | Services, DAOs, Utilities |
prototype | New bean per request | Caller-managed | Report generators, Temporary objects |
request | One bean per HTTP request | Request duration | Request tracking, Form validation |
session | One bean per HTTP session | Session duration | Shopping cart, User preferences |
application | One bean per web app | Application duration | Caches, App stats, Global config |
websocket | One bean per WebSocket session | WebSocket duration | Chat session, Live streams, Games |
Spring bean scopes in terms of stateless vs stateful:
Scope | Stateless or Stateful | Explanation |
singleton | Stateless | Safe to share because it does not hold user-specific or temporary data. Example: Service or DAO beans. |
prototype | Stateful | Each caller gets a new instance, so it can hold user-specific or task-specific data safely. Example: PDF report generator. |
request | Stateful | Bean lives for one HTTP request → can hold request-specific data safely. Example: Request metadata. |
session | Stateful | Bean lives for one HTTP session → holds user session data. Example: Shopping cart. |
application | Stateless | Bean is shared across the whole app → used for global resources. Example: Cache manager, global statistics. |
websocket | Stateful | Bean lives for a WebSocket session → holds connection-specific data. Example: Chat session. |