一、Bean 的作用域
1. 什么是 Bean 作用域?
Bean 作用域是 Spring 用来控制 Bean 实例数量与存活范围的机制,简单说就是:每次从容器中获取 Bean 时,是复用同一个对象,还是新建一个对象。
Spring 内置了 6 种作用域,其中 4 种是通用作用域,另外 2 种是 Web 专属作用域。
2. 六大作用域详解
表格
| 作用域类型 | 含义 | 实例数量 | 适用场景 |
|---|---|---|---|
| singleton | 单例作用域,整个 Spring 容器仅一个实例 | 1 个 | 工具类、Service、Dao、Controller(无状态 Bean) |
| prototype | 原型多例作用域,每次获取都新建实例 | 多个 | 有状态 Bean、需要独立对象的场景 |
| request | 一次 HTTP 请求对应一个 Bean 实例 | 请求级 | Web 项目,请求临时数据存储 |
| session | 一个用户会话对应一个 Bean 实例 | 会话级 | 存储用户登录信息、会话数据 |
| application | 整个 Web 应用全局唯一,与容器同生命周期 | 全局 | 全局配置信息 |
| websocket | 一次 WebSocket 连接对应一个 Bean 实例 | 连接级 | 即时通讯、WebSocket 长连接场景 |
3. 重点作用域代码实战
(1)singleton 单例(默认)
Spring 容器启动时就直接创建实例,全局共享,所有获取操作拿到的都是同一个对象。
<bean id="dog" class="com.qcby.Dog" scope="singleton"/>
-
注解方式:
@Component
@Scope("singleton") // 可省略,默认就是单例
public class Dog {}
✅ 特点:容器启动初始化一次、全局唯一、性能高,但非线程安全(多线程修改共享状态会有问题)。
(2)prototype 多例
容器启动时不创建 Bean,每次getBean或注入时才新建对象。
@Component
@Scope("prototype")
public class Dog {}
✅ 特点:多实例、线程安全,但 Spring 不管理多例 Bean 的销毁生命周期,需要自己手动处理资源释放。
二、Bean 的完整生命周期:从诞生到销毁的全过程
Bean 的生命周期,就是 Bean 在 Spring IoC 容器中,从创建到销毁的完整流程,也是面试的高频考点。
1. 完整生命周期流程图
容器启动 → 实例化 → 属性赋值 → 预处理 → 初始化 → 后置处理 → 就绪使用 → 容器关闭销毁
2. 七步详细拆解
第一步:实例化(new 对象)
Spring 启动时,通过反射调用无参构造方法,创建 Bean 的空对象。 ⚠️ 关键提醒:必须有无参构造,否则 Bean 会创建失败(这也是很多启动报错的核心原因)。
第二步:属性赋值(依赖注入)
通过setter方法、构造函数、@Autowired等方式,给 Bean 的成员变量赋值,完成依赖注入。 ⚠️ 对应报错:没有setter方法、属性不可写 → 注入失败。
第三步:执行 Aware 接口(容器回调)
Spring 内置的扩展接口,让 Bean 感知容器资源:
BeanNameAware:获取当前 Bean 的名称BeanFactoryAware:获取 Bean 工厂对象ApplicationContextAware:获取 Spring 容器上下文
第四步:Bean 前后置处理器(BeanPostProcessor)
Spring 提供的全局增强机制,在 Bean 初始化前后执行自定义逻辑,是 Spring AOP、注解增强的核心原理。
- 前置处理:
postProcessBeforeInitialization - 后置处理:
postProcessAfterInitialization
第五步:初始化(自定义初始化逻辑)
有 3 种初始化执行方式,优先级从高到低:
@PostConstruct注解(推荐,最常用)- 实现
InitializingBean接口 - XML 配置
init-method属性
第六步:Bean 就绪(使用阶段)
初始化完成后,Bean 正式存入 Spring 单例池,对外提供服务,接收程序调用。
第七步:销毁(容器关闭)
Spring 容器关闭时,执行 Bean 的销毁逻辑,仅针对单例 Bean 生效。两种销毁方式:
@PreDestroy注解- 实现
DisposableBean接口
3. 生命周期完整代码演示
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.DisposableBean;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class LifeCycleBean implements BeanNameAware, InitializingBean, DisposableBean {
private String beanName;
// 1. 实例化(无参构造)
public LifeCycleBean() {
System.out.println("第一步:调用无参构造,实例化Bean");
}
// 2. 属性赋值(模拟依赖注入)
public void setBeanName(String name) {
System.out.println("第二步:属性赋值,设置beanName");
this.beanName = name;
}
// 3. Aware接口回调
@Override
public void setBeanName(String name) {
System.out.println("第三步:执行BeanNameAware,获取Bean名称:" + name);
this.beanName = name;
}
// 4. 初始化方式1:@PostConstruct
@PostConstruct
public void postConstruct() {
System.out.println("第五步:执行@PostConstruct初始化方法");
}
// 4. 初始化方式2:InitializingBean接口
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("第五步:执行InitializingBean的afterPropertiesSet方法");
}
// 销毁方式1:@PreDestroy
@PreDestroy
public void preDestroy() {
System.out.println("第七步:执行@PreDestroy销毁方法");
}
// 销毁方式2:DisposableBean接口
@Override
public void destroy() throws Exception {
System.out.println("第七步:执行DisposableBean的destroy方法");
}
}
4. 生命周期执行顺序总结
无参构造实例化 → 属性赋值 → Aware 接口 → 前置处理器 → @PostConstruct → InitializingBean → init-method → 后置处理器 → Bean 使用 → 容器关闭销毁
三、作用域与生命周期的关联关系
- singleton 单例 :容器启动完成实例化、属性赋值、初始化,容器关闭销毁,完整生命周期由 Spring 管理。
- prototype 多例 :调用时才创建,Spring 只负责创建和属性赋值,不管理初始化和销毁,需要开发者自己处理资源释放。
- Web 作用域(request/session):生命周期随请求 / 会话结束而终止,Spring 会在请求 / 会话结束时自动销毁 Bean。
四、结语
Bean 的作用域和生命周期,是 Spring IoC 最核心、最基础的知识点,也是面试和开发的必考点。
- 掌握作用域,能帮你合理设计 Bean 的实例模型,避免线程安全问题;
- 掌握生命周期,能帮你解决依赖注入失败、资源泄漏、初始化逻辑异常等 90% 的常见问题。
