Spring内置的Bean作用域介绍

在 Spring 框架中,Bean 的作用域(Scope)定义了 Bean 实例的生命周期和可见范围。Spring 提供了多种内置作用域,并支持自定义作用域。

1. Spring 内置的 Bean 作用域

1.1. singleton(单例) ✅ 默认作用域

  • 描述:在整个 Spring IoC 容器中,该 Bean 只有一个实例。
  • 生命周期:容器启动时创建(默认懒加载除外),容器关闭时销毁。
  • 线程安全:不保证线程安全,需开发者自行处理(通常无状态组件无需担心)。
  • 适用场景:无状态的服务类,如 Service、DAO、工具类等。
java 复制代码
@Component
@Scope("singleton") // 可省略,默认就是 singleton
public class OrderService {
    public void processOrder() { /* ... */ }
}

所有通过 @Component@Service 等注解声明的 Bean 默认都是 singleton。


1.2. prototype(原型)

  • 描述:每次从容器请求该 Bean 时,都会创建一个新实例。
  • 生命周期 :容器只负责创建,不管理销毁(调用者需自行清理资源)。
  • 适用场景:有状态的对象,如购物车、临时计算上下文等。
java 复制代码
@Component
@Scope("prototype")
public class ShoppingCart {
    private List<Item> items = new ArrayList<>();
    
    public void addItem(Item item) {
        items.add(item);
    }
}

注意:如果将 prototype Bean 注入到 singleton Bean 中,注入的仍是同一个实例(因为 singleton 初始化时就完成注入)。此时应使用 ObjectProvider<ShoppingCart> 或方法注入来获取新实例。


1.3. request(Web 作用域)

  • 描述:每个 HTTP 请求创建一个新实例,请求结束时销毁。
  • 适用范围 :仅在 Web 应用中可用(需 WebApplicationContext)。
  • 适用场景:保存单次请求的数据,如请求参数封装对象。
java 复制代码
@Component
@Scope("request")
public class RequestContext {
    private String userId;
    // getters/setters
}

在 Controller 中注入 RequestContext,每个 HTTP 请求都会获得独立实例。


1.4. session(Web 作用域)

  • 描述:每个 HTTP 会话(HttpSession)创建一个 Bean 实例,会话结束时销毁。
  • 适用范围:Web 应用。
  • 适用场景:用户登录信息、会话级缓存等。
java 复制代码
@Component
@Scope("session")
public class UserSession {
    private String username;
    private LocalDateTime loginTime;
}

同一会话中的多次请求共享同一个 UserSession 实例。


1.5. application(Web 作用域)

  • 描述:在整个 ServletContext 生命周期内只有一个实例(相当于 Web 应用级别的单例)。
  • 与 singleton 区别
    • singleton 是 Spring 容器级别;
    • application 是 ServletContext 级别(在 Web 环境中,通常两者行为一致,但语义不同)。
  • 适用场景:全局配置、应用级缓存。
java 复制代码
@Component
@Scope("application")
public class AppConfig {
    private String appName = "MyApp";
}

实际开发中较少显式使用,多数情况用 singleton 即可。


1.6. websocket(Web 作用域)

  • 描述:每个 WebSocket 会话创建一个 Bean 实例。
  • 适用范围:基于 WebSocket 的应用。
  • 适用场景:WebSocket 连接相关的状态管理。
java 复制代码
@Component
@Scope("websocket")
public class WebSocketHandler {
    private String connectionId;
}

需配合 Spring WebSocket 模块使用。


2. 作用域对比表

作用域 范围 是否 Web 专用 实例数量 容器管理销毁
singleton 整个 Spring 容器 1 个 ✅ 是
prototype 每次请求 N 个(每次获取都新建) ❌ 否
request 单个 HTTP 请求 ✅ 是 1 个/请求 ✅ 是
session 单个 HTTP 会话 ✅ 是 1 个/会话 ✅ 是
application 整个 Web 应用(ServletContext) ✅ 是 1 个/Web 应用 ✅ 是
websocket 单个 WebSocket 会话 ✅ 是 1 个/WebSocket 连接 ✅ 是

Spring 的作用域机制灵活支持从全局单例到请求/会话级实例的各种场景。默认使用 singleton 是出于性能和无状态设计的最佳实践,而 Web 相关作用域则为 Web 应用提供了细粒度的状态管理能力。


3. 注意事项

1. 非 Web 环境下使用 Web 作用域会报错 : 如在普通 Java SE 应用中使用 @Scope("request"),会抛出 IllegalStateException

2. 代理模式解决作用域注入问题: 当短作用域 Bean(如 request)注入到长作用域 Bean(如 singleton)时,需使用代理:

java 复制代码
@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestContext { /* ... */ }

// 这样 Spring 会注入一个代理对象,每次调用方法时动态获取当前请求的实例。

3. 自定义作用域 : Spring 支持通过 ConfigurableBeanFactory.registerScope() 注册自定义作用域(如"租户"作用域等)。

4. 相关文档

  1. spring为什么把bean默认设计成单例

  2. Spring Bean生命周期简介

3.Sping中获取bean的方式总结

  1. Spring中生成Bean的方式总结
相关推荐
要开心吖ZSH16 小时前
Spring AI Alibaba 个人学习笔记
人工智能·学习·spring·spring ai·springaialibaba
马猴烧酒.16 小时前
【团队空间|第十一天】基础功能实现,RBAC权限控制,ShardingSphere详解
java·开发语言·数据库
fengxin_rou16 小时前
从 String 到 Zset:Redis 核心数据结构全解析及排行榜应用
java·开发语言·redis·多线程
世界尽头与你16 小时前
CVE-2025-55752_ Apache Tomcat 安全漏洞
java·安全·网络安全·渗透测试·tomcat·apache
Re.不晚16 小时前
Java进阶之路--线程最最详细讲解
java·开发语言
步步为营DotNet16 小时前
深入理解ASP.NET Core Middleware:管道执行机制与高效应用
后端·asp.net
遨游xyz16 小时前
数据结构-栈
java·数据结构·算法
海南java第二人16 小时前
Flink动态字符串处理框架:构建灵活可配置的实时数据管道
java·flink
lbb 小魔仙16 小时前
MyBatis-Plus 系统化实战:从基础 CRUD 到高级查询与性能优化
java·性能优化·mybatis
BLUcoding16 小时前
Docker 离线安装和镜像源配置
java·docker·eureka