Spring @Scope Annotation with Prototype Scope Example

In this article, we will discuss how to use the @Scope annotation with Prototype scope in a Spring Boot application.

Overview

The @Scope annotation is used to define the scope of a @Component class or a @Bean definition. The @Scope annotation can be used with all Spring bean scopes:

  1. Singleton: Only one instance of the bean is created and shared across the entire application. This is the default scope.
  2. Prototype: A new instance of the bean is created every time it is requested.
  3. Request: A new instance of the bean is created for each HTTP request. It is only applicable to web applications.
  4. Session: A new instance of the bean is created for each HTTP session. It is only applicable to web applications.
  5. Application: A single instance of the bean is created and shared across the entire application context. It is only applicable to web applications.

In this article, we will discuss how to use the @Scope annotation with Prototype scope with an example.

When a Spring bean is scoped as a prototype, the Spring IoC container creates a new bean instance every time a request is made for that bean. We can define the scope of a bean as a prototype using the @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) annotation.

We will demonstrate this example using annotation-based (@Component) as well as Java-based configuration (@Bean).

Spring @Scope Annotation + Prototype Scope + @Component Example

Let's create an example to demonstrate the usage of @Scope annotation with a prototype scope in a Spring application.

1. Create a Simple Maven Project

Create a simple Maven project using your favourite IDE. Below is the project structure for your reference:

Spring @Scope Annotation with Prototype Scope Example

2. The pom.xml File

Make sure to use Java 17 or later for Spring Framework 6:

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.example</groupId>
    <artifactId>learn-spring-framework</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>6.0.6</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.0.6</version>
        </dependency>
    </dependencies>
</project>

3. Create Spring Beans

MessageService Interface

package net.javaguides.spring.scope;

public interface MessageService {
    String getMessage();
    void setMessage(String message);
}

This interface defines two methods: getMessage() and setMessage(String message). Any class that implements this interface will need to provide implementations for these methods.

TwitterMessageService Class

package net.javaguides.spring.scope;

import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class TwitterMessageService implements MessageService {

    private String message;

    @Override
    public String getMessage() {
        return message;
    }

    @Override
    public void setMessage(String message) {
        this.message = message;
    }
}

In this class:

  • @Component annotation tells Spring that this class is a Spring component.
  • @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) annotation specifies that this bean should be scoped as a prototype.
  • getMessage() returns the current message.
  • setMessage(String message) sets the current message.

4. Annotation-Based Configuration

AppConfig Class

package net.javaguides.spring.scope;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = "net.javaguides.spring")
public class AppConfig {
}

In this class:

  • @Configuration indicates that this class contains Spring bean definitions.
  • @ComponentScan(basePackages = "net.javaguides.spring") tells Spring to scan the specified package for components (i.e., classes annotated with @Component).

5. Running Spring Application

Application Class

package net.javaguides.spring.scope;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Application {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        MessageService messageService = context.getBean(MessageService.class);
        messageService.setMessage("TwitterMessageService Implementation");
        System.out.println(messageService.getMessage());

        MessageService messageService1 = context.getBean(MessageService.class);
        System.out.println(messageService1.getMessage());
        context.close();
    }
}

In this class:

  • AnnotationConfigApplicationContext is used to create and manage the Spring application context.
  • context.getBean(MessageService.class) retrieves a bean of type MessageService from the Spring context.
  • The first bean (messageService) sets and prints a message.
  • The second bean (messageService1) retrieves and prints the message.

Output

TwitterMessageService Implementation
null

Explanation:

  • The first bean (messageService) sets the message to "TwitterMessageService Implementation" and prints it.
  • The second bean (messageService1) is a new instance (because of the prototype scope) and has no message set, so it prints null.

Spring @Scope Annotation + Prototype Scope + @Bean Example

Create MessageService Interface

MessageService Interface

package net.javaguides.spring.scope;

public interface MessageService {
    String getMessage();
    void setMessage(String message);
}

This interface remains the same as in the previous example.

Create TwitterMessageService Class

TwitterMessageService Class

package net.javaguides.spring.scope;

public class TwitterMessageService implements MessageService {

    private String message;

    @Override
    public String getMessage() {
        return message;
    }

    @Override
    public void setMessage(String message) {
        this.message = message;
    }
}

This class remains the same, but without @Component and @Scope annotations since we will configure it using Java-based configuration.

Java-based Configuration

AppConfig Class

package net.javaguides.spring.scope;

import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

@Configuration
public class AppConfig {

    @Bean
    @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public MessageService messageService() {
        return new TwitterMessageService();
    }
}

In this class:

  • @Bean annotation tells Spring that this method returns a Spring bean.
  • @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) specifies that this bean should be scoped as a prototype.

Running Spring Application

Application Class

package net.javaguides.spring.scope;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Application {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        MessageService messageService = context.getBean(MessageService.class);
        messageService.setMessage("TwitterMessageService Implementation");
        System.out.println(messageService.getMessage());

        MessageService messageService1 = context.getBean(MessageService.class);
        System.out.println(messageService1.getMessage());
        context.close();
    }
}

This class remains the same as in the previous example.

Output

TwitterMessageService Implementation
null

Explanation:

  • The first bean (messageService) sets the message to "TwitterMessageService Implementation" and prints it.
  • The second bean (messageService1) is a new instance (because of the prototype scope) and has no message set, so it prints null.

Conclusion

In this article, we demonstrated how to use the @Scope annotation with Prototype scope in

Spring Boot applications. Using the prototype scope, we ensure that a new instance of the bean is created each time it is requested. This is particularly useful for beans that are stateful and need to be re-instantiated with every use.

Related Spring and Spring Boot Annotations

Comments