在 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六种作用域的资料请关注代码网其它相关文章!
发表评论