Keywords: Spring Bean | Scope | Singleton | Prototype | Request | Session | IoC Container
Abstract: This article provides an in-depth exploration of the five bean scopes in the Spring Framework: singleton, prototype, request, session, and global session. Through comparative analysis of different scopes' lifecycles, use cases, and configuration methods, it helps developers choose appropriate bean management strategies based on application requirements. The article combines code examples and practical scenarios to explain the behavioral characteristics of each scope and their implementation mechanisms in the Spring IoC container.
Overview of Spring Bean Scopes
In the Spring Framework, bean scope defines the lifecycle and visibility boundaries of bean instances within the Spring IoC container. Scope determines how the container creates, manages, and destroys bean instances, forming a crucial component of Spring's dependency injection mechanism. Proper understanding and utilization of bean scopes are essential for building efficient and maintainable Spring applications.
Detailed Explanation of Five Bean Scopes
1. Singleton Scope
Singleton is the default scope for Spring beans. In this scope, the Spring IoC container creates exactly one instance per bean definition. This instance is stored in the container's singleton cache, and all subsequent requests for that bean return the same cached instance.
Configuration example:
<bean id="exampleBean" class="com.example.ExampleBean" scope="singleton">
<property name="dependency" ref="someDependency"/>
</bean>
Or using annotation approach:
@Component
@Scope("singleton")
public class ExampleBean {
// Bean implementation
}
Singleton scope is suitable for stateless beans such as service layer components and data access objects, which typically don't need to maintain request- or session-specific state.
2. Prototype Scope
Prototype scope is the opposite of singleton - a new instance is created each time the bean is requested from the container. The Spring container does not cache prototype bean instances, generating new objects with every getBean() call or dependency injection reference.
Configuration example:
<bean id="customerInfoController" class="com.action.Controller" scope="prototype">
<property name="accountDao" ref="accountDao"/>
<property name="utilityDao" ref="utilityDao"/>
<property name="account_usageDao" ref="account_usageDao"/>
</bean>
Prototype scope is appropriate for beans that need to maintain state, particularly those requiring independent instances for each usage. Note that the Spring container only handles prototype bean initialization, not destruction, requiring developers to manage resource cleanup.
3. Request Scope
Request scope confines a bean's lifecycle to a single HTTP request. Each HTTP request creates an independent bean instance, which is destroyed when the request completes. This scope is only valid in web-aware Spring ApplicationContext environments.
Configuration example (annotation-based):
@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestScopedBean {
private String requestId;
@PostConstruct
public void init() {
this.requestId = UUID.randomUUID().toString();
}
public String getRequestId() {
return requestId;
}
}
Request scope is commonly used for scenarios requiring request-specific state tracking, such as request-level data holders or request-specific configurations.
4. Session Scope
Session scope binds bean instances to the lifecycle of an HTTP session. Each user session corresponds to one bean instance, instantiated when the session is created and cleaned up when the session is destroyed. This also requires web-aware ApplicationContext support.
Configuration example:
@Component
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class UserPreferences {
private String theme = "default";
private Locale locale = Locale.getDefault();
// Getter and setter methods
public String getTheme() {
return theme;
}
public void setTheme(String theme) {
this.theme = theme;
}
public Locale getLocale() {
return locale;
}
public void setLocale(Locale locale) {
this.locale = locale;
}
}
Session scope is suitable for storing user-specific data such as user preferences, shopping cart contents, etc.
5. Global Session Scope
Global session scope is a concept from the Portlet specification, binding bean instances to global HTTP sessions. In standard Servlet environments, it behaves identically to session scope; in Portlet environments, it spans sessions across multiple portlets. This scope also requires web-aware ApplicationContext.
Configuration example:
<bean id="globalPreferences" class="com.example.GlobalPreferences" scope="globalSession">
<!-- Bean configuration -->
</bean>
Global session scope is primarily used in Portlet applications for sharing session data across multiple portlets.
Scope Selection and Practical Recommendations
Comparative Analysis of Scopes
Different scopes exhibit significant variations in memory usage, performance, and thread safety:
- Singleton: Highest memory efficiency but requires thread safety assurance
- Prototype: Creates new instances per request with higher memory overhead but naturally thread-safe
- Request/Session: Intermediate approach suitable for specific web application scenarios
Scope Proxy Mechanism
When injecting shorter-lived scopes (e.g., request, session) into longer-lived beans (e.g., singleton), scope proxies are necessary. Spring configures proxy modes through ScopedProxyMode:
@Autowired
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
private RequestScopedBean requestBean;
The proxy mechanism ensures that each method invocation retrieves the correct scoped instance.
Best Practices
- Default to singleton scope unless other scopes are explicitly required
- For stateful beans, select appropriate scopes based on state lifecycle requirements
- In web applications, judiciously use request and session scopes for managing request and session data
- Pay attention to proxy configuration when combining scopes to avoid scope mismatch issues
- For prototype beans, ensure proper resource release management
Advanced Configuration and Custom Scopes
XML vs Annotation Configuration
Spring supports multiple configuration approaches for defining bean scopes:
XML configuration:
<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="exampleBean" class="com.example.ExampleBean" scope="prototype"/>
</beans>
Java configuration:
@Configuration
public class AppConfig {
@Bean
@Scope("prototype")
public ExampleBean exampleBean() {
return new ExampleBean();
}
}
Custom Scope Implementation
Spring allows developers to register custom scopes by implementing the Scope interface and registering it with the container:
public class ThreadLocalScope implements Scope {
private final ThreadLocal<Map<String, Object>> threadLocal =
ThreadLocal.withInitial(HashMap::new);
@Override
public Object get(String name, ObjectFactory<?> objectFactory) {
Map<String, Object> scope = threadLocal.get();
Object object = scope.get(name);
if (object == null) {
object = objectFactory.getObject();
scope.put(name, object);
}
return object;
}
@Override
public Object remove(String name) {
Map<String, Object> scope = threadLocal.get();
return scope.remove(name);
}
@Override
public void registerDestructionCallback(String name, Runnable callback) {
// Implement destruction callback
}
@Override
public Object resolveContextualObject(String key) {
return null;
}
@Override
public String getConversationId() {
return String.valueOf(Thread.currentThread().getId());
}
}
// Register custom scope
ConfigurableBeanFactory beanFactory = (ConfigurableBeanFactory) applicationContext.getBeanFactory();
beanFactory.registerScope("threadLocal", new ThreadLocalScope());
Conclusion
The Spring bean scope mechanism provides flexible instance management strategies, ranging from global singletons to request-level granular control. Understanding the characteristics and appropriate use cases of each scope enables developers to design more efficient and maintainable Spring applications. In practical development, scope configuration should be selected based on bean state requirements, performance considerations, and thread safety concerns.