Spring Bean Scopes – Singleton vs Prototype
When creating bean definitions you cannot only control various dependencies and configurations, but also define the scope of the bean. These scopes are configured via configuration which makes them very powerfull and flexible. You don’t need to hard code them at Java Class level. There are multiple scopes. Singleton and prototype are supported out of the box. The other scopes require a web-aware ApplicationContext
. Here is a list of the scopes available:
- singleton (Default) Single bean definition for a single object instance per container.
- prototype Single bean definition for multiple instances.
- request Single bean definition for a single HTTP request.
- session Single bean definition for the HTTP session.
- global-session Single bean definition for the global HTTP session. Typically only valid when used in portlet context.
- application Single bean definition for the entire application bound to the lifecycle of a
ServletContext
Request, session and application are only valid in the context of a web-aware ApplicationContext
Singleton Bean Scope Example
The default scope is singleton. Which means that only one instance of bean is created for a spring container. Singleton scoped beans are mostly used for stateless beans.
package com.memorynotfound.spring.core.scope;
public class CoffeeMachine {
private long serialNr;
public long getSerialNr() {
return serialNr;
}
public void setSerialNr(long serialNr) {
this.serialNr = serialNr;
}
}
Configure spring bean as singleton.
// default scope is singleton
<bean class="com.memorynotfound.spring.core.scope.CoffeeMachine"/>
// explicit singleton is equivalent
<bean class="com.memorynotfound.spring.core.scope.CoffeeMachine" scope="singleton"/>
We retrieve the singleton Coffee
bean and assign a value. The subsequent requests for the same bean will return the same instance of the bean.
package com.memorynotfound.spring.core.scope;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Run {
public static void main(String... args) throws InterruptedException {
ApplicationContext context = new ClassPathXmlApplicationContext("app-config.xml");
Coffee coffee = context.getBean(Coffee.class);
coffee.setBrand("Java");
System.out.println("Coffee brand: " + coffee.getBrand());
coffee = context.getBean(Coffee.class);
System.out.println("Coffee brand: " + coffee.getBrand());
}
}
Output
Serial nr: 12356789
Serial nr: 12356789
Prototype Bean Scope Example
The prototype scope means that a single bean definition is used to create multiple instances. This results in the creation of a new bean instance every time a request for that bean is made. Prototype scoped beans are mostly used for stateful beans.
package com.memorynotfound.spring.core.scope;
public class Coffee {
private String brand;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
}
Configuring prototype scoped bean.
<bean class="com.memorynotfound.spring.core.scope.Coffee" scope="prototype"/>
Everytime we get the prototype scoped bean via getBean()
method of the ApplicationContext
the container creates a new instance for that bean. Which means any subsequent request will also create a new bean.
package com.memorynotfound.spring.core.scope;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Run {
public static void main(String... args) throws InterruptedException {
ApplicationContext context = new ClassPathXmlApplicationContext("app-config.xml");
Coffee coffee = context.getBean(Coffee.class);
coffee.setBrand("Java");
System.out.println("Coffee brand: " + coffee.getBrand());
coffee = context.getBean(Coffee.class);
System.out.println("Coffee brand: " + coffee.getBrand());
}
}
Output
Coffee brand: Java
Coffee brand: null
Configure Beans scope with @Scope Annotation
Instead of defining your bean scope in xml, you can also annotate your bean using the @Scope
annotation. This annotation takes a name parameter indicating which bean scope to use.
package com.memorynotfound.spring.core.scope;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
@Scope("prototype")
public class Coffee {
private String brand;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
}
We can use this annotation by enabling the <context:component-scan/> element. This enables annotation configuration and scans for beans in a particular package.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.memorynotfound"/>
</beans>