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的方式总结
相关推荐
橙露16 小时前
Spring Boot 核心原理:自动配置机制与自定义 Starter 开发
java·数据库·spring boot
小程故事多_8016 小时前
Agent Infra核心技术解析:Sandbox sandbox技术原理、选型逻辑与主流方案全景
java·开发语言·人工智能·aigc
冰暮流星16 小时前
sql语言之分组语句group by
java·数据库·sql
望舒51316 小时前
代码随想录day25,回溯算法part4
java·数据结构·算法·leetcode
黎雁·泠崖16 小时前
【魔法森林冒险】3/14 Allen类(一):主角核心属性与初始化
java·开发语言
程序员敲代码吗16 小时前
Spring Boot与Tomcat整合的内部机制与优化
spring boot·后端·tomcat
黎雁·泠崖16 小时前
【魔法森林冒险】1/14 项目总览:用Java打造你的第一个回合制冒险游戏
java·开发语言
NuageL16 小时前
原始Json字符串转化为Java对象列表/把中文键名变成英文键名
java·spring boot·json
222you17 小时前
Redis的主从复制和哨兵机制
java·开发语言
江湖有缘17 小时前
零基础入门:使用 Docker 快速部署 Organizr 个人主页
java·服务器·docker