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的方式总结
相关推荐
极创信息3 分钟前
信创产品认证怎么做?信创产品测试认证的主要流程
java·大数据·数据库·金融·软件工程
SamDeepThinking22 分钟前
并发量就算只有2,该上锁还得上呀
java·后端·架构
Sam_Deep_Thinking38 分钟前
如何让订单系统和营销系统解耦
java·架构·系统架构
lzhdim1 小时前
SQL 入门 12:SQL 视图:创建、修改与可更新视图
java·大数据·服务器·数据库·sql
FQNmxDG4S2 小时前
Maven依赖管理:版本冲突解决与生命周期控制
java·数据库·maven
傻瓜搬砖人2 小时前
Spring集成Web环境
java·spring·maven
FQNmxDG4S2 小时前
Java泛型编程:类型擦除与泛型方法的应用场景
java·开发语言·python
GottdesKrieges3 小时前
OceanBase恢复常见问题
java·数据库·oceanbase
IGAn CTOU3 小时前
Java高级开发进阶教程之系列
java·开发语言
leo825...3 小时前
Claude Code Skills 清单(本地)
java·python·ai编程