How do I manage bean scopes in Spring Framework?

In the Spring Framework, beans are defined with different scopes that govern their lifecycle and interaction with the container. The scope determines how many instances of a bean are created and how they are shared within an application.

Common Bean Scopes in Spring

Spring provides several bean scopes, and they are managed through the @Scope annotation or XML configuration. Below are the commonly used scopes:

1. Singleton (Default Scope)

  • This is the default scope in Spring.
  • Ensures there is only one shared instance of the bean per Spring container.
  • Suitable for stateless beans.
  • Example:
@Component
public class MySingletonBean {
    // Default scope is singleton
}

Or explicitly:

@Component
@Scope("singleton")
public class MySingletonBean {
}

2. Prototype

  • A new instance of the bean is created every time it is requested.
  • Useful for stateful, non-shared objects.
  • Example:
@Component
@Scope("prototype")
public class MyPrototypeBean {
}

In XML:

<bean id="myBean" class="com.example.MyBean" scope="prototype" />

3. Request

  • A new bean instance is created for every HTTP request and is specific to the lifecycle of that request.
  • Used in web applications.
  • Example:
@Component
@Scope("request")
public class MyRequestScopedBean {
}

4. Session

  • A new bean instance is created for every HTTP session and remains valid for the session lifecycle.
  • Mainly used in web applications for session-specific data.
  • Example:
@Component
@Scope("session")
public class MySessionScopedBean {
}

5. Application

  • A new bean instance is shared across the entire ServletContext (application-wide).
  • Example:
@Component
@Scope("application")
public class MyApplicationScopedBean {
}

6. WebSocket

  • A new instance is created for the lifecycle of a WebSocket session.
  • Example:
@Component
@Scope("websocket")
public class MyWebSocketScopedBean {
}

Setting Bean Scope

  1. Using Annotations:
    • Leverage the @Scope annotation along with Spring’s @Component, @Service, @Controller, or @RestController.
    • Example:
    @Service
    @Scope("prototype")
    public class PrototypeService {
    }
    
  2. Using XML Configuration:
    • Define the scope inside the XML bean configuration.
    • Example:
    <bean id="myBean" class="com.example.MyService" scope="prototype" />
    
  3. Programmatically:
    • Define the bean and its scope programmatically using Java-based configuration.
    • Example:
    @Configuration
    public class AppConfig {
      @Bean
      @Scope("prototype")
      public MyService myService() {
          return new MyService();
      }
    }
    

Custom Scopes

You can define custom scopes in Spring by implementing the Scope interface. This is typically used in special cases like tenant-based architectures.

How the Container Manages Scopes

In singleton scope, the container ensures that only one instance of the bean exists at a time. In prototype and other scopes, however, the container provides a fresh instance depending on the request but does not manage the full lifecycle, such as destroying the bean (in the case of prototype beans).
If you use scopes such as request, session, or websocket, Spring’s WebApplicationContext is responsible for managing the beans’ lifecycle.

Key Points:

  • Singleton Scope is the default scope in Spring.
  • For web applications, consider request, session, or application scopes for beans tied to web-specific functionalities.
  • For stateful beans, do not use Singleton scope unless thread safety is accounted for.
  • Custom Scope definitions can extend the functionality of bean management.

How do I define bean scoping in Spring?

Bean scoping is how the bean is created and returned from the spring container to the bean requester. By default, the scope of all bean is singleton. The spring container will always return the same bean whenever this bean is required, for instance when in injected or call using the getBean() method from the application context.

There are five types of bean scope define in the Spring Container:

Scope Description
singleton Scope the bean definition to a single bean instance per Spring Container. This is the default scope when no scope is defined when creating a bean.
prototype Scope the bean to allow multiple times bean creation. This will create a new bean for each time the bean is required.
request Scope the bean definition to a single HTTP request. *
session Scope the bean definition to a single HTTP session. *
global-session Scope the bean definition to a global HTTP session. *

*) This is only valid when using the web-capable Spring context.

Let’s see the difference between Singleton and Prototype scope. First we’ll create our DummyService class.

package org.kodejava.spring.core;

public class DummyService {
    private String message;

    public String getMessage() {
        return message;
    }

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

Singleton Scope

By default, when no scope defined it will be a singleton.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="service" class="org.kodejava.spring.core.DummyService" />

</beans>

Now create a program to run our example. First will run it using the singleton.xml as the configuration.

package org.kodejava.spring.core;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeanScopeDemo {
    public static void main(String[] args) {
        try (var context = new ClassPathXmlApplicationContext("singleton.xml")) {
            DummyService serviceA = (DummyService) context.getBean("service");
            serviceA.setMessage("Hello From A");
            System.out.println("Message A = " + serviceA.getMessage());

            DummyService serviceB = (DummyService) context.getBean("service");
            System.out.println("Message B = " + serviceB.getMessage());
        }
    }
}

The output of the singleton configuration is:

Message A = Hello From A
Message B = Hello From A

The above output show that the message printed by the serviceB is the same as the serviceA. We don’t even set the message in the serviceB explicitly. It prints the same message because the getBean() method actually return the same bean both for serviceA and serviceB. This is the singleton scope.

Prototype Scope

To change the scope to prototype use the scope attribute in the bean element as shown below.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="service" class="org.kodejava.spring.core.DummyService" scope="prototype" />

</beans>
package org.kodejava.spring.core;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeanScopePrototypeDemo {
    public static void main(String[] args) {
        try (var context = new ClassPathXmlApplicationContext("prototype.xml")) {
            DummyService serviceA = (DummyService) context.getBean("service");
            serviceA.setMessage("Hello From A");
            System.out.println("Message A = " + serviceA.getMessage());

            DummyService serviceB = (DummyService) context.getBean("service");
            System.out.println("Message B = " + serviceB.getMessage());
        }
    }
}

Now if you try to run the same program again but changing the configuration to prototype.xml you’ll get the following output printed:

Message A = Hello From A
Message B = null

The serviceB now print a different message. This is the effect of using the prototype scope. When we call the getBean() a new bean will be created per request.

Maven Dependencies

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>5.3.23</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>5.3.23</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
        <version>5.3.23</version>
    </dependency>
</dependencies>

Maven Central Maven Central Maven Central

How do I share object or data between users in web application?

In a web application there are different type of scope where we can store object or data. There are a page, request, session and application scope.

To share data between users of the web application we can put a shared object in application scope which can be done by calling setAttribute() method of the ServletContext. By this way data can then be accessing by other users by calling the getAttribute() method of the ServletContext.

Let’s see the example code in a simple servlet.

package org.kodejava.servlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(name = "SharedObjectServlet", urlPatterns = "/shared-object")
public class ApplicationContextScopeAttribute extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        ServletContext context = this.getServletContext();
        context.setAttribute("HELLO.WORLD", "Hello World 123");
    }
}

And here is what we code in the JSP page to access it.

<%= request.getServletContext().getAttribute("HELLO.WORLD") %>

Maven dependencies

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
</dependency>

Maven Central