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的方式总结
相关推荐
大鸡腿同学4 小时前
【成长类】《只有偏执狂才能生存》读书笔记:程序员的偏执型成长地图
后端
0xDevNull4 小时前
MySQL数据冷热分离详解
后端·mysql
一定要AK4 小时前
Spring 入门核心笔记
java·笔记·spring
A__tao4 小时前
Elasticsearch Mapping 一键生成 Java 实体类(支持嵌套 + 自动过滤注释)
java·python·elasticsearch
AI袋鼠帝4 小时前
OpenClaw(龙虾)最强开源对手!Github 40K Star了,又一个爆火的Agent..
后端
KevinCyao4 小时前
java视频短信接口怎么调用?SpringBoot集成视频短信及回调处理Demo
java·spring boot·音视频
凯尔萨厮4 小时前
创建SpringWeb项目(Spring2.0)
spring·mvc·mybatis
迷藏4944 小时前
**发散创新:基于Rust实现的开源合规权限管理框架设计与实践**在现代软件架构中,**权限控制(RBAC)** 已成为保障
java·开发语言·python·rust·开源
wuxinyan1235 小时前
Java面试题47:一文深入了解Nginx
java·nginx·面试题
新知图书5 小时前
搭建Spring Boot开发环境
java·spring boot·后端