Tutorial

Spring Bean Scopes

Published on August 3, 2022
author

Pankaj

Spring Bean Scopes

Spring Bean Scopes allows us to have more granular control of the bean instances creation. Sometimes we want to create bean instance as singleton but in some other cases we might want it to be created on every request or once in a session.

Spring Bean Scopes

There are five types of spring bean scopes:

  1. singleton - only one instance of the spring bean will be created for the spring container. This is the default spring bean scope. While using this scope, make sure bean doesn’t have shared instance variables otherwise it might lead to data inconsistency issues.
  2. prototype – A new instance will be created every time the bean is requested from the spring container.
  3. request – This is same as prototype scope, however it’s meant to be used for web applications. A new instance of the bean will be created for each HTTP request.
  4. session – A new bean will be created for each HTTP session by the container.
  5. global-session – This is used to create global session beans for Portlet applications.

Spring Bean Singleton and Prototype Scope

Spring bean singleton and prototype scopes can be used in standalone spring apps. Let’s see how we can easily configure these scopes using @Scope annotation. Let’s say we have a java bean class.

package com.journaldev.spring;

public class MyBean {

	public MyBean() {
		System.out.println("MyBean instance created");
	}

}

Let’s define the spring configuration class where we will define the method to get MyBean instance from spring container.

package com.journaldev.spring;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

@Configuration
public class MyConfiguration {
	
	@Bean
	@Scope(value="singleton")
    public MyBean myBean() {
		return new MyBean();
	}
	
}

Note that singleton is default scope, so we can remove @Scope(value="singleton") from above bean definition. Now let’s create a main method and test the singleton scope.

package com.journaldev.spring;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MySpringApp {

	public static void main(String[] args) {
		AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
		ctx.register(MyConfiguration.class);
		ctx.refresh();

		 MyBean mb1 = ctx.getBean(MyBean.class);
		 System.out.println(mb1.hashCode());

		 MyBean mb2 = ctx.getBean(MyBean.class);
		 System.out.println(mb2.hashCode());

		ctx.close();
	}

}

When above program is executed, we will get output like below.

MyBean instance created
867988177
867988177

Notice that both MyBean instances have same hashcode and the constructor is called once once, it means that spring container is returning the same instance of MyBean always. Now let’s change the scope to prototype.

@Bean
@Scope(value="prototype")
public MyBean myBean() {
	return new MyBean();
}

This time we will get following output when main method is executed.

MyBean instance created
867988177
MyBean instance created
443934570

It’s clear that MyBean instance is created every time it’s requested from spring container. Now let’s change the scope to request.

@Bean
@Scope(value="request")
public MyBean myBean() {
	return new MyBean();
}

In this case, we will get following exception.

Exception in thread "main" java.lang.IllegalStateException: No Scope registered for scope name 'request'
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:347)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:224)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1015)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:339)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:334)
	at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1107)
	at com.journaldev.spring.MySpringApp.main(MySpringApp.java:12)

It’s because request, session and global-session scopes are not available for standalone applications.

Spring Bean Request and Session Scope

For spring bean request and session scope example, we will create Spring Boot web application. Create a spring boot starter project and choose “web” so that we can run it as a web application. spring boot starter project Our final project will look like below image. spring bean scopes spring boot web app project ServletInitializer and SpringBootMvcApplication are auto generated spring boot classes. We don’t need to make any changes there. Here is my pom.xml file, have a look at the dependencies for our application. Your pom.xml file might be slightly different based on the Eclipse version you are using.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.journaldev.spring</groupId>
	<artifactId>Spring-Boot-MVC</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>

	<name>Spring-Boot-MVC</name>
	<description>Spring Beans Scope MVC</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.2.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>10</java.version>
	</properties>

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

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-tomcat</artifactId>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>


</project>

Let’s create some spring components and configure them as spring beans in the spring container with scope as request and session.

Spring Bean Request Scope

package com.journaldev.spring;

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

@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class DataRequestScope {

	private String name = "Request Scope";
	
	public DataRequestScope() {
		System.out.println("DataRequestScope Constructor Called");
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

Spring Bean Session Scope

package com.journaldev.spring;

import org.springframework.context.annotation.Scope;
import java.time.LocalDateTime;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Component;

@Component
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class DataSessionScope {

	private String name = "Session Scope";
	
	public DataSessionScope() {
		System.out.println("DataSessionScope Constructor Called at "+LocalDateTime.now());
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

Spring Component

Now let’s create a spring component and use spring to auto configure above beans.

package com.journaldev.spring;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class Customer {

	@Autowired
	private DataRequestScope dataRequestScope;
	
	@Autowired
	private DataSessionScope dataSessionScope;

	public DataRequestScope getDataRequestScope() {
		return dataRequestScope;
	}

	public void setDataRequestScope(DataRequestScope dataRequestScope) {
		this.dataRequestScope = dataRequestScope;
	}

	public DataSessionScope getDataSessionScope() {
		return dataSessionScope;
	}

	public void setDataSessionScope(DataSessionScope dataSessionScope) {
		this.dataSessionScope = dataSessionScope;
	}


}

Spring Rest Controller

Finally, let’s create a RestController class and configure some API end points for our testing purposes.

package com.journaldev.spring;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloData {

	@Autowired
	private Customer customer;
	
	@RequestMapping("/nameRS")
	public String helloRS() {
		return customer.getDataRequestScope().getName();
	}
	
	@RequestMapping("/nameSSUpdated")
	public String helloSSUpdated() {
		customer.getDataSessionScope().setName("Session Scope Updated");
		return customer.getDataSessionScope().getName();
	}
	
	@RequestMapping("/nameSS")
	public String helloSS() {
		return customer.getDataSessionScope().getName();
	}
}

Spring Boot Session Timeout Configuration

Finally we have to configure spring boot session timeout variables, add below properties in src/main/resources/application.properties.

server.session.cookie.max-age= 1
server.session.timeout= 1

Now our spring beans with session scope will be invalidated in one minute. Just run the SpringBootMvcApplication class as spring boot application. You should see below output for our endpoints being configured.

2018-05-23 17:02:25.830  INFO 6921 --- [main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/nameRS]}" onto public java.lang.String com.journaldev.spring.HelloData.helloRS()
2018-05-23 17:02:25.831  INFO 6921 --- [main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/nameSSUpdated]}" onto public java.lang.String com.journaldev.spring.HelloData.helloSSUpdated()
2018-05-23 17:02:25.832  INFO 6921 --- [main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/nameSS]}" onto public java.lang.String com.journaldev.spring.HelloData.helloSS()

Spring Bean Request Scope Test

Open any browser and go to URL https://localhost:8080/nameRS and check the console output. You should see DataRequestScope Constructor Called getting printed on each request.

Spring Bean Session Scope Test

Go to https://localhost:8080/nameSS and you would get following output. Spring Bean Session Scope Test Output Now go to https://localhost:8080/nameSSUpdated so that DataSessionScope name value is updated to Session Scope Updated. Spring Bean Scopes test Now again go to https://localhost:8080/nameSS and you should see the updated value. spring beans scope By this time, you should see DataSessionScope Constructor Called at XXX only once in the console output. Now wait for 1 minute so that our session scoped bean is invalidated. Then again go to https://localhost:8080/nameSS and you should see the original output. Also you should check console message for creation of DataSessionScope again by the container. spring bean session scope That’s all for spring beans scope tutorial.

You can download the Spring Beans Scope Spring Boot project from our GitHub Repository.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the authors
Default avatar
Pankaj

author

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
JournalDev
DigitalOcean Employee
DigitalOcean Employee badge
February 23, 2021

Very clear article easy to digest

- andres

    JournalDev
    DigitalOcean Employee
    DigitalOcean Employee badge
    July 27, 2020

    PLEASE LAST ONE ALSO GLOBAL-SESSION ???

    - Prabhat

      JournalDev
      DigitalOcean Employee
      DigitalOcean Employee badge
      November 26, 2019

      Thanks for this! This is the only article on request scope beans that actually worked.

      - Mike C

        JournalDev
        DigitalOcean Employee
        DigitalOcean Employee badge
        May 28, 2019

        Now almost everything works! It has to be deployed with a WAR file, I had forgot the WAR tagg. But the session stays and is not ended although I have : server.servlet.session.cookie.max-age= 1 server.servlet.session.timeout= 1 server.session.cookie.max-age= 1 server.session.timeout= 1 is not allowed anymore. What can I do to make the session end after 1 minute?

        - Eyvind

          JournalDev
          DigitalOcean Employee
          DigitalOcean Employee badge
          May 28, 2019

          I tried your tutorial project, but https://localhost:8080/nameSS never gets updated after https://localhost:8080/nameSSUpdated. What could be wrong?

          - Eyvind

            Try DigitalOcean for free

            Click below to sign up and get $200 of credit to try our products over 60 days!

            Sign up

            Join the Tech Talk
            Success! Thank you! Please check your email for further details.

            Please complete your information!

            Become a contributor for community

            Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

            DigitalOcean Documentation

            Full documentation for every DigitalOcean product.

            Resources for startups and SMBs

            The Wave has everything you need to know about building a business, from raising funding to marketing your product.

            Get our newsletter

            Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.

            New accounts only. By submitting your email you agree to our Privacy Policy

            The developer cloud

            Scale up as you grow — whether you're running one virtual machine or ten thousand.

            Get started for free

            Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

            *This promotional offer applies to new accounts only.