Spring Bean Scopes: Singleton vs Prototype

1. Introduction

In the realm of Spring Framework, understanding bean scopes is vital for effective application development. The bean scope determines the lifecycle and visibility of a bean in the Spring container. Put simply, it specifies how and when a bean is created, used, and destroyed. There are several scopes available in Spring, but the two most commonly used are Singleton and Prototype. In this blog, we’ll explore these two scopes, providing clear examples and real-time use cases to help you grasp their differences and applications.

2. Usages

Choosing the correct bean scope is essential for optimizing resource management and application performance. Here’s when to consider using each of these scopes:

  • Singleton: Use this scope when you need a single shared instance of a bean throughout the Spring container. It's the default scope in Spring. Singleton beans are best when:
    • You want to ensure that there's only one shared instance for the entire application.
    • The bean is stateless or handles shared state carefully.
  • Prototype: Use this scope when you need a new instance of a bean every time one is requested from the Spring container. Prototype beans are most suitable when:
    • You need a mutable state in your beans where each instance should not impact others.
    • You are dealing with beans that maintain certain contextual data specific to each user or request.

3. Code Example

Let’s dive into a Spring Boot application to demonstrate how Singleton and Prototype scopes work in practice.

Step 1: Setting Up Spring Boot

Create a new Spring Boot project and include the necessary dependencies in your pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>

Step 2: Create Singleton and Prototype Beans

Create two classes representing the Singleton and Prototype beans.

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

@Component
@Scope("singleton")
public class SingletonBean {
    private String message = "I am a Singleton bean!" ;

    public String getMessage() {
        return message;
    }
}
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope("prototype")
public class PrototypeBean {
    private String message = "I am a Prototype bean!";

    public String getMessage() {
        return message;
    }
}

Step 3: Create the Main Application Class

Let’s set up the main application class that utilizes both beans:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

@SpringBootApplication
public class BeanScopeDemoApplication implements CommandLineRunner {

    @Autowired
    private ApplicationContext context;

    public static void main(String[] args) {
        SpringApplication.run(BeanScopeDemoApplication.class, args);
    }

    @Override
    public void run(String... args) {
        SingletonBean singletonBean1 = context.getBean(SingletonBean.class);
        SingletonBean singletonBean2 = context.getBean(SingletonBean.class);
        System.out.println("Singleton Bean 1: " + singletonBean1.getMessage());
        System.out.println("Singleton Bean 2: " + singletonBean2.getMessage());
        System.out.println("Are Singleton Beans same instance? " + (singletonBean1 == singletonBean2));

        PrototypeBean prototypeBean1 = context.getBean(PrototypeBean.class);
        PrototypeBean prototypeBean2 = context.getBean(PrototypeBean.class);
        System.out.println("Prototype Bean 1: " + prototypeBean1.getMessage());
        System.out.println("Prototype Bean 2: " + prototypeBean2.getMessage());
        System.out.println("Are Prototype Beans same instance? " + (prototypeBean1 == prototypeBean2));
    }
}

Step 4: Run the Application

When you run the application, you should see output similar to this:

Singleton Bean 1: I am a Singleton bean!
Singleton Bean 2: I am a Singleton bean!
Are Singleton Beans same instance? true
Prototype Bean 1: I am a Prototype bean!
Prototype Bean 2: I am a Prototype bean!
Are Prototype Beans same instance? false

4. Explanation

In our example, we created two Spring beans, one with Singleton scope and the other with Prototype scope.

  • Singleton Bean: When you request a SingletonBean from the Spring context, the same instance is returned each time. This is evident from the output, where both singletonBean1 and singletonBean2 refer to the same object in memory, confirming their Singleton nature.
  • Prototype Bean: Conversely, when PrototypeBean is requested, a new instance is created every time you call context.getBean(PrototypeBean.class). In our output, prototypeBean1 and prototypeBean2 are different instances, shown by the result of their equality check being false.

5. Best Practices

To effectively use Singleton and Prototype bean scopes in your applications, consider the following best practices:

  • Use Singleton for Shared State: If your beans manage shared data and do not have instance-specific variables, Singleton is typically the way to go. Avoid using Singleton for mutable state that can change over time without synchronization.
  • Avoid State in Singleton Beans: If you're using Singleton beans, keep them stateless if possible to prevent unintended side effects, especially in concurrent environments.
  • Leverage Prototype for Stateful Beans: Use Prototype when the bean needs to maintain state specific to a user session or transaction. This avoids conflict and data leakage between different users or operations.
  • Beware of Resource Management: Understand that Prototype beans are not automatically managed by Spring’s container when they are created. Ensure that you handle the cleanup of any resources appropriately.

6. Conclusion

Understanding Spring's bean scopes, particularly Singleton and Prototype, is essential for building effective, maintainable applications. By making informed decisions about which scope to use based on the specific needs of your application, you can optimize performance, manage resources better, and avoid potential issues down the line.

So, as you work on your next Spring project, carefully consider how bean scopes will affect your application's architecture. Keep experimenting and learning, and you’ll soon master the nuances of Spring Framework! Happy coding!

Previous Post Next Post