Bean Scopes – Singleton and Prototype

The Spring Container manages the beans, remember that the Spring container is the implementation of the principle of IoC. The term bean Scope refers to the lifecycle and the visibility of the beans. In other words the bean scope tell us how long the bean lives, how many instances of the bean are created and how the bean is shared.

Types of Beans Scopes

Spring has six types of scopes: singleton, prototype, request, session, application, and websocket.

Singleton and Prototype are the two scopes that can be used in any application meanwhile the other four scopes are only available for a web application. For this entry we only focus on the Singleton and Prototype.

To explain this topic let’s review our beans LatteCoffee and MochaCoffee, (the code can be download the code from CoffeShop, this example is under the package: com.programmingsquirrel.coffeeshop.scopes).

@Component
@Qualifier("Latte")
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class LatteCoffee implements Coffee {

    @Override
    public void prepareCoffee() {
        System.out.println("Making a Latte...");
    }
}
@Component
@Primary
@Qualifier("Mocha")
public class MochaCoffee implements Coffee {

    @Override
    public void prepareCoffee() {
        System.out.println("Making a Mocha...");
    }
}

The bean LatteCoffee is marked with the annotation @Scope and the value of ConfigurableBeanFactory.SCOPE_PROTOTYPE is provided. This @Scope annotation indicates the scope that the bean will have, in this case, the Prototype.

Next, we have the bean MochaCoffee. This bean is not explicitly marked with the @Scope annotation because, as a reminder, the Singleton scope is the default scope. However, we can also use the @Scope annotation with the value ConfigurableBeanFactory.SCOPE_SINGLETON to explicitly specify the Singleton scope. An example showcasing this usage is provided below.

@Component
@Primary
@Qualifier("Mocha")
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
public class MochaCoffee implements Coffee {

    @Override
    public void prepareCoffee() {
        System.out.println("Making a Mocha...");
    }
}

Singleton Scope

This is the default scope of a bean, in which only one instance of the bean is created and cached in memory. Multiple requests for the bean return a shared reference to the same bean.

The MochaCoffee bean has a Singleton scope. To test this scope, we need to execute the application after modifying the CoffeeshopApplication class. In this modification, we will get three instances of MochaCoffe bean. Spring will return the same bean for all three instances, and we can verify this observing that all three beans have the same memory reference.

@SpringBootApplication
public class CoffeeshopApplication {

	public static void main(String[] args) {

		//Here we create the ApplicationContext that manages the beans and dependencies
		ApplicationContext appContext = SpringApplication.run(CoffeeshopApplication.class, args);

		//Retrieve the singleton bean from application Context
		MochaCoffee coffe1 = appContext.getBean(MochaCoffee.class);
		MochaCoffee coffe2 = appContext.getBean(MochaCoffee.class);
		MochaCoffee coffe3 = appContext.getBean(MochaCoffee.class);

		System.out.println(coffe1);
		System.out.println(coffe2);
		System.out.println(coffe2);

	}

After execute the application we will get this messages in the console:

...
2023-07-11 11:34:16.874  INFO 9960 --- [           main] c.p.c.scopes.CoffeeshopApplication       : Started CoffeeshopApplication in 0.726 seconds (JVM running for 1.027)
com.programmingsquirrel.coffeeshop.scopes.impl.MochaCoffee@79c3f01f
com.programmingsquirrel.coffeeshop.scopes.impl.MochaCoffee@79c3f01f
com.programmingsquirrel.coffeeshop.scopes.impl.MochaCoffee@79c3f01f

In the output, we can verify that Spring retrieves the same bean, this can be verified with the same memory address. The application context doesn’t create a new bean each time we request it, whether it’s the second or third time. Instead, Springs returns the same reference to the bean that was already created.

The Singleton bean scope is the default scope, and is used to minimize the number of objects created. It’s important to remember the beans are created when the context is loaded and cached in memory. All request for a bean are returned with the same memory address. This type of scope is best suited for cases where stateless beans are required.

It’s important to note that Spring creates the Singleton bean even before we explicitly request it. This means that Spring is prepared to provide the Singleton bean whenever it is needed.

Another important consideration is that the Singleton scope in Spring is different from the Singleton design pattern described in Gang of Four. In Spring, the Singleton scope refers to a single instance per application, not per JVM. it’s essential to distinguish between the two to avoid any confusion.

Prototype Scope

The Prototype scope, results in the creation of new beans whenever a request for the bean is made to the application context. This scope is used in our LatteCoffee bean with the @Scope annotation and the value ConfigurableBeanFactory.SCOPE_PROTOTYPE. This annotation belong to the org.springframework.context.annotation.

Before to continue, Spring offer two options to specify the scope type using the @Scope annotation. One way is using the constants: SCOPE_PROTOTYPE and SCOPE_SINGLETON from the ConfigurableBeanFactory Interface. And the other is using the word "prototype" or "singleton". The preferred approach is use the ConfigurableBeanFactory constants.

Returning to the Prototype Scope, we have the LatteCoffee bean that has a Prototype scope. To test this scope, we need to execute the application after modifying the CoffeeshopApplication class. In this modification, we will get three instances of LatteCoffee bean. Spring will return a new bean for all three bean requests, and we can verify this observing that all three beans have different memory reference.

@SpringBootApplication
public class CoffeeshopApplication {

	public static void main(String[] args) {

		//Here we create the ApplicationContext that manages the beans and dependencies
		ApplicationContext appContext = SpringApplication.run(CoffeeshopApplication.class, args);

		//...

        //Retrieve the Prototype bean from application Context
		LatteCoffee latteCoffe1 = appContext.getBean(LatteCoffee.class);
		LatteCoffee latteCoffe2 = appContext.getBean(LatteCoffee.class);
		LatteCoffee latteCoffe3 = appContext.getBean(LatteCoffee.class);

		System.out.println(latteCoffe1);
		System.out.println(latteCoffe2);
		System.out.println(latteCoffe3);

	}

In the output, we can verify that Spring creates a new bean each time that the bean is requested, this can be verified with the memory address.

...
2023-07-11 12:51:03.156  INFO 10840 --- [           main] c.p.c.scopes.CoffeeshopApplication       : Started CoffeeshopApplication in 0.733 seconds (JVM running for 1.052)
com.programmingsquirrel.coffeeshop.scopes.impl.LatteCoffee@38600b
com.programmingsquirrel.coffeeshop.scopes.impl.LatteCoffee@669d2b1b
com.programmingsquirrel.coffeeshop.scopes.impl.LatteCoffee@721eb7df

When a bean has the Prototype scope, Spring will create the bean only when we explicitly request it from the Spring container.

These are the two primary scopes that Spring manages, and it is important to be familiar with them when starting with Spring.

Thanks for reading and happy learning!!!

Leave a comment