Spring Bean的六种作用域详解
在 Spring 容器中,Bean 的作用域决定了 Bean 实例的创建规则、生命周期和使用范围,它会直接影响程序的性能、线程安全和内存占用。Spring 一共定义了 6 种作用域,下面我们逐一拆解。
一、singleton(单例,默认作用域)
核心效果
- 整个 Spring IoC 容器中,只会创建 1 个该 Bean 的实例,所有依赖该 Bean 的对象,拿到的都是同一个实例。
- Bean 实例的生命周期与容器绑定:容器启动时初始化,容器关闭时销毁。
适用场景
- 无状态的 Bean,比如 Service、DAO、工具类、配置类等。
- 这类 Bean 不会保存线程 / 用户的私有状态,所有请求共用同一个实例,性能开销最低。
代码示例
// 方式1:注解方式(默认就是 singleton,可以省略)
@Component
@Scope("singleton")
public class UserService {
}
// 方式2:XML 配置
<bean id="userService" class="com.example.service.UserService" scope="singleton"/>二、prototype(原型 / 多例)
核心效果
- 每次从容器中获取该 Bean 时,都会创建一个全新的实例。
- Spring 容器不负责 prototype Bean 的完整生命周期:容器只会初始化、装配 Bean,不会在关闭时销毁它,需要使用者自己管理销毁。
适用场景
- 有状态的 Bean,比如需要保存用户私有数据的对象、多线程环境下的非线程安全对象。
- 不适合频繁创建的大对象(会增加 GC 压力),适合轻量级、需要独立状态的 Bean。
代码示例
@Component
@Scope("prototype")
public class OrderInfo {
// 每个请求/线程都会拿到独立的 OrderInfo 实例
}三、request(请求域)
核心效果
- 每次 HTTP 请求,都会创建一个新的 Bean 实例,同一个请求内的所有对象拿到的都是同一个实例。
- 仅在 Spring Web 环境中有效,实例的生命周期与 HTTP 请求绑定:请求结束,Bean 就会被销毁。
适用场景
- 存储 HTTP 请求相关的临时数据,比如请求上下文、用户单次请求的参数对象。
- 比如 Spring MVC 中,用于封装请求信息的对象。
代码示例
@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestInfo {
// 每个 HTTP 请求都会创建独立实例
}注意:需要配合 proxyMode 使用,否则会出现依赖注入异常。
四、session(会话域)
核心效果
- 每个用户 HTTP 会话(Session),都会创建一个新的 Bean 实例,同一个 Session 内的所有请求,拿到的都是同一个实例。
- 仅在 Spring Web 环境中有效,实例的生命周期与用户 Session 绑定:Session 超时 / 销毁,Bean 就会被销毁。
适用场景
- 存储用户会话级别的状态数据,比如用户登录信息、购物车信息、用户偏好设置等。
代码示例
@Component
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class UserSession {
// 每个用户会话都会创建独立实例
}五、application(应用域)
核心效果
- 整个 Web 应用中,只会创建 1 个 Bean 实例,和
singleton类似,但作用域是ServletContext级别的,比singleton范围更广(跨多个 Spring 容器也共享)。 - 实例的生命周期与 Web 应用绑定:应用启动时初始化,应用关闭时销毁。
适用场景
- 存储整个应用级别的全局数据,比如应用配置、全局统计信息、公共缓存对象。
代码示例
@Component
@Scope(value = "application", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class AppConfig {
// 整个 Web 应用中唯一实例
}六、websocket(WebSocket 域)
核心效果
- 每个 WebSocket 会话,都会创建一个新的 Bean 实例,同一个 WebSocket 会话内的消息处理,都会使用同一个实例。
- 仅在 Spring WebSocket 环境中有效,实例的生命周期与 WebSocket 会话绑定:会话关闭,Bean 就会被销毁。
适用场景
- WebSocket 长连接场景下,需要保存会话状态的对象,比如聊天室的用户连接信息、会话级别的消息处理器。
代码示例
@Component
@Scope(value = "websocket", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class WebSocketSessionInfo {
// 每个 WebSocket 会话创建独立实例
}作用域对比总结表
| 作用域 | 实例创建规则 | 适用环境 | 典型场景 |
|---|---|---|---|
| singleton | 容器中仅 1 个实例 | 所有环境 | Service、DAO、工具类 |
| prototype | 每次获取都新建实例 | 所有环境 | 有状态的对象、非线程安全对象 |
| request | 每个 HTTP 请求 1 个实例 | Web 环境 | 请求上下文、请求临时数据 |
| session | 每个用户 Session 1 个实例 | Web 环境 | 用户登录信息、购物车 |
| application | 整个 Web 应用 1 个实例 | Web 环境 | 全局配置、应用级缓存 |
| websocket | 每个 WebSocket 会话 1 个实例 | WebSocket 环境 | 长连接会话状态 |
一、先搞懂:Bean 作用域到底是什么?
简单说,就是 Spring 给你创建的对象,是「共用一个」还是「每次都给新的」,以及能用多久。比如:
- 有的对象整个程序里大家都用同一个(比如工具类)
- 有的对象每次用都给你新的(比如购物车,每个用户都要有自己的)
二、6 种作用域,一个一个讲
1. singleton(单例,默认)
大白话:整个程序里,大家共用同一个对象
- 效果:程序启动时,Spring 就创建好这一个对象,之后所有人调用,拿到的都是这同一个。
- 例子:就像学校的「公共饮水机」,全校同学都用这一台,谁来接水都用它。
- 什么时候用?没有自己的 “私有数据”,大家用着都一样的对象,比如 Service 业务类、DAO 数据库操作类、工具类。
2. prototype(多例 / 原型)
大白话:每次调用,都给你一个全新的对象
- 效果:你每次从 Spring 里拿这个对象,它都会给你新造一个,和之前的都不一样。
- 例子:就像「一次性纸杯」,每个人喝水都给你一个新的,用完就扔,不会和别人共用。
- 什么时候用?每个用户 / 每个操作都要有自己独立状态的对象,比如订单信息、购物车对象,不能和别人共用。
下面 4 种,只有做网页项目(Web 程序)才会用到,按「用多久」来分:
3. request(请求域)
大白话:一次网页请求,用一个对象
- 效果:用户点一下网页(发一次请求),Spring 给你造一个对象,这次请求里全程都用它;等用户刷新页面 / 点下一个链接,这次请求结束,这个对象就扔了,下次再给新的。
- 例子:就像「一次性纸巾」,你擦一次手就扔了,下次再拿新的。
- 什么时候用?只在这一次网页请求里用的数据,比如用户这次搜索的关键词、临时请求参数。
4. session(会话域)
大白话:一个用户的一次登录会话,用一个对象
- 效果:用户登录网站后,从登录到退出 / 超时这段时间,全程用同一个对象;用户退出登录,这个对象就销毁了。
- 例子:就像「你自己的水杯」,你在学校一天都用这一个,放学回家就收起来,第二天再用新的(或者说,每个学生都有自己的水杯,不会共用)。
- 什么时候用?要跟着用户登录状态走的数据,比如用户登录信息、购物车内容,用户不退出,这些数据就一直存在。
5. application(应用域)
大白话:整个网站,所有人共用同一个对象
- 效果:网站启动时造好,整个网站运行期间,所有用户、所有请求都用这同一个对象,和 singleton 很像,但范围是整个网站。
- 例子:就像「学校的公告栏」,全校所有同学都看这一个,公告内容更新了所有人都能看到。
- 什么时候用?整个网站都要用的全局数据,比如网站的配置信息、全站访问量统计。
6. websocket(WebSocket 域)
大白话:一次 WebSocket 连接,用一个对象
- 效果:用户和网站建立 WebSocket 长连接(比如聊天室、在线客服),连接期间全程用同一个对象;连接断开,对象就销毁了。
- 例子:就像「你打电话时的专属通话通道」,你和客服通话期间,这个通道只属于你,挂电话就关了。
- 什么时候用?WebSocket 长连接场景,比如聊天室里的用户连接信息、实时聊天的会话数据。
三、给你划重点(作业要写的核心点)
表格
| 作用域 | 一句话总结 | 关键特点 |
|---|---|---|
| singleton | 全程序共用 1 个 | 默认、无状态对象用它 |
| prototype | 每次调用给新的 | 有状态对象用它 |
| request | 一次请求用 1 个 | 网页单次请求用 |
| session | 一个用户会话用 1 个 | 登录用户的会话数据 |
| application | 全网站共用 1 个 | 全局配置 / 统计数据 |
| websocket | 一次 WebSocket 连接用 1 个 | 长连接场景用 |
四、举个你能懂的对比
- 学校里:
- singleton = 全校共用的操场
- prototype = 每个同学自己的笔记本
- request = 一次性考试草稿纸
- session = 你自己的储物柜(从开学用到放假)
- application = 学校的校史馆,所有人都看这一个
- websocket = 一次视频通话的专用线路
关键补充说明
- 线程安全问题:
singleton单例 Bean 是线程共享的,必须保证线程安全(不能保存可变的成员变量状态)。prototype/request/session等多实例 Bean,每个线程 / 请求 / 会话使用独立实例,天生线程安全。
- 性能与内存:
singleton实例全局复用,性能最高、内存占用最低。- 多实例作用域会频繁创建销毁对象,会增加内存和 GC 压力,仅在有状态场景下使用。
- 代理模式:
request/session/application等 Web 相关作用域,需要配合@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)使用,否则在注入 singleton Bean 时会出现依赖注入异常。
以上就是Spring Bean的六种作用域详解的详细内容,更多关于Spring Bean六种作用域的资料请关注脚本之家其它相关文章!


最新评论