Spring 框架支持多种 Bean 的作用域(Scope),通过作用域可以控制 Bean 的生命周期和可见性。了解不同作用域的用途,可以帮助开发者更好地管理 Bean 的创建和销毁,从而提高资源利用效率并确保应用程序的性能。以下是 Spring 支持的几种常见 Bean 作用域:
1. 单例作用域(Singleton)
定义:在 Spring 容器中,每个定义的 Bean 只有一个实例,默认作用域。
特点:
- 在整个 Spring 容器生命周期内,Bean 只有一个实例。
- 所有对该 Bean 的请求都返回同一个实例。
使用场景:
- 适用于线程安全的无状态服务或共享资源。
示例:
java复制代码
@Component @Scope("singleton") public class SingletonBean { // 单例 Bean }
2. 原型作用域(Prototype)
定义:每次请求 Bean 时,都会创建一个新的实例。
特点:
- 每次请求都会返回一个新的 Bean 实例。
- Spring 只负责初始化 Bean,不负责销毁 Bean。
使用场景:
- 适用于有状态、线程不安全的组件。
示例:
java复制代码
@Component @Scope("prototype") public class PrototypeBean { // 原型 Bean }
3. 请求作用域(Request)
定义:每次 HTTP 请求都会创建一个新的 Bean 实例。
特点:
- 每次 HTTP 请求都会创建一个新的 Bean 实例,并在请求结束时销毁该实例。
- 仅适用于 Web 应用程序。
使用场景:
- 适用于需要在每次 HTTP 请求期间保持状态的 Bean。
示例:
java复制代码
@Component @Scope("request") public class RequestScopedBean { // 请求作用域 Bean }
4. 会话作用域(Session)
定义:在 HTTP 会话期间,每个会话创建一个新的 Bean 实例。
特点:
- 每个 HTTP 会话创建一个新的 Bean 实例,并在会话过期或无效时销毁该实例。
- 仅适用于 Web 应用程序。
使用场景:
- 适用于需要在 HTTP 会话期间保持状态的 Bean。
示例:
java复制代码
@Component @Scope("session") public class SessionScopedBean { // 会话作用域 Bean }
5. 全局会话作用域(Global Session)
定义:在全局 HTTP 会话期间,每个全局会话创建一个新的 Bean 实例。
特点:
- 主要用于基于 Portlet 的 Web 应用程序,每个 Portlet 全局会话会创建一个新的 Bean 实例。
- 在标准的 Web 应用程序中很少使用。
使用场景:
- 适用于需要在全局 HTTP 会话期间保持状态的 Bean。
示例:
java复制代码
@Component @Scope("globalSession") public class GlobalSessionScopedBean { // 全局会话作用域 Bean }
6. 应用程序作用域(Application)
定义:在 ServletContext 生命周期内,每个 ServletContext 创建一个新的 Bean 实例。
特点:
- 在整个 ServletContext 期间,Bean 只有一个实例。
- 适用于 Web 应用程序。
使用场景:
- 适用于需要在整个 Web 应用程序生命周期内共享状态的 Bean。
示例:
java复制代码
@Component @Scope("application") public class ApplicationScopedBean { // 应用程序作用域 Bean }
自定义作用域
Spring 还支持自定义作用域。通过实现 org.springframework.beans.factory.config.Scope
接口,可以定义自定义作用域。
示例:
java复制代码
public class CustomScope implements Scope { private Map<String, Object> scopedObjects = new HashMap<>(); private Map<String, Runnable> destructionCallbacks = new HashMap<>(); public Object get(String name, ObjectFactory<?> objectFactory) { return scopedObjects.computeIfAbsent(name, k -> objectFactory.getObject()); } public Object remove(String name) { destructionCallbacks.remove(name); return scopedObjects.remove(name); } public void registerDestructionCallback(String name, Runnable callback) { destructionCallbacks.put(name, callback); } public Object resolveContextualObject(String key) { return null; } public String getConversationId() { return "custom"; } }
注册自定义作用域:
java复制代码
@Configuration public class AppConfig { @Bean public CustomScope customScope() { return new CustomScope(); } @Bean public static CustomScopeConfigurer customScopeConfigurer(CustomScope customScope) { CustomScopeConfigurer configurer = new CustomScopeConfigurer(); configurer.addScope("custom", customScope); return configurer; } }
使用自定义作用域:
java复制代码
@Component @Scope("custom") public class CustomScopedBean { // 自定义作用域 Bean }
总结
Spring 支持多种 Bean 作用域,可以根据不同应用场景选择合适的作用域:
- 单例作用域(Singleton):默认作用域,全局共享单一实例。
- 原型作用域(Prototype):每次请求创建一个新实例。
- 请求作用域(Request):每次 HTTP 请求创建一个新实例。
- 会话作用域(Session):每个 HTTP 会话创建一个新实例。
- 全局会话作用域(Global Session):每个 Portlet 全局会话创建一个新实例。
- 应用程序作用域(Application):在整个 ServletContext 生命周期内共享单一实例。
理解和合理选择 Bean 的作用域,可以帮助开发者在不同的业务场景中更好地管理 Bean 的生命周期,提高应用程序的性能和资源利用效率。