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的方式总结
相关推荐
却话巴山夜雨时i26 分钟前
394. 字符串解码【中等】
java·数据结构·算法·leetcode
CryptoRzz28 分钟前
美股 (US) 与 墨西哥 (Mexico) 股票数据接口集成指南
后端
张人大 Renda Zhang1 小时前
Java 虚拟线程 Virtual Thread:让“每请求一线程”在高并发时代复活
java·jvm·后端·spring·架构·web·虚拟线程
一勺菠萝丶1 小时前
解决 SLF4J 警告问题 - 完整指南
java·spring boot·后端
济南壹软网络科技有限公司1 小时前
架构深潜:通霸IM——私有化部署、全链路开源的高可用企业级即时通讯技术基座
java·架构·开源·即时通讯源码·即时通讯im
小股虫1 小时前
手搓限流第二版:限流算法与动态阈值的深度整合
java
TracyCoder1231 小时前
大白话讲Java NIO
java·开发语言·nio
零日失眠者1 小时前
【文件管理系列】001:文件批量重命名工具
后端·shell
魂梦翩跹如雨1 小时前
P8615 [蓝桥杯 2014 国 C] 拼接平方数——Java解答
java·c语言·蓝桥杯