原文来自于:zha-ge.cn/java/129
项目写得再多也没用!Spring Bean 的核心概念要是没懂,迟早踩坑
有次带新人改项目,他拍着胸脯说:"我写过好几个 Spring 项目,Bean 我用得飞起。" 结果一问:"那 Bean 的生命周期有几个阶段?什么时候依赖注入?什么时候销毁?"------表情秒变成 🫠。
说实话,这种事我自己也踩过坑。Spring 的魔法 80% 都藏在 Bean 这俩字后面,你以为只是一个对象,其实是整个容器的灵魂。 项目写得再多,Bean 没整明白,迟早要在调试里原地爆炸。
1. Bean 究竟是个啥?不是"new"出来的对象!
一句话总结:Bean 是由 Spring 容器创建、管理、装配和销毁的对象。
这意味着它不是你手动 new
出来的那种对象,而是被托管在 IoC 容器中,生命周期、依赖注入、作用域这些都交给容器来操心。
你要一个 UserService
:
java
@Service
public class UserService {
public void register() { ... }
}
Spring 就在启动时扫描到它 → 实例化 → 放进 IoC 容器 → 以后你用的时候,直接拿已经准备好的 Bean 实例:
java
@Autowired
private UserService userService;
你不管它是怎么 new 出来的、依赖怎么塞进去的、啥时候销毁的,这些都被 Spring 管了。这就是 Bean 的核心价值:解耦对象的创建和使用。
2. Bean 的生命周期:从出生到退休的一生
很多人知道"Spring 会帮我创建 Bean",但你真知道它从出生到死亡有几步吗?这其实是面试最爱考的基础题之一👇:
-
实例化(Instantiation)
- Spring 通过反射创建 Bean 实例(构造器注入就在这里搞定)。
-
依赖注入(Populate Properties)
- 把其他 Bean 塞进来,比如用
@Autowired
注入。
- 把其他 Bean 塞进来,比如用
-
调用
Aware
接口(可选)- 如果 Bean 实现了
BeanNameAware
、ApplicationContextAware
等,会在此时回调。
- 如果 Bean 实现了
-
BeanPostProcessor 前置处理
- 比如自动代理(AOP)就在这里织入。
-
初始化(Initialization)
- 调用
@PostConstruct
或InitializingBean.afterPropertiesSet()
。
- 调用
-
BeanPostProcessor 后置处理
- 后期增强处理完成。
-
就绪(Ready)
- Bean 开始正式提供服务。
-
销毁(Destruction)
- 容器关闭时调用
@PreDestroy
或DisposableBean.destroy()
。
- 容器关闭时调用
👉 一句话记忆法:实例化 → 注入 → 感知 → 前置增强 → 初始化 → 后置增强 → 就绪 → 销毁
这 8 步你要是没概念,排查 Bean 初始化问题会特别痛苦。
3. 作用域:Bean 不止一种"活法"
默认情况下,Spring 的 Bean 是单例(singleton
)的,但它还有多种作用域模式,搞清楚它们是理解 Bean 行为的关键。
作用域 | 含义 | 适用场景 |
---|---|---|
singleton |
整个容器里只有一个实例(默认) | 大多数服务类 |
prototype |
每次注入都新建一个实例 | 有状态对象 |
request |
每个 HTTP 请求一个实例(Web 环境) | Web 请求级别的组件 |
session |
每个 Session 一个实例(Web 环境) | 用户会话数据 |
application |
ServletContext 级别单例 | Web 全局状态共享 |
最容易踩坑的是 prototype
:容器不会管理它的销毁,生命周期你得自己收尾。比如:
java
@Bean
@Scope("prototype")
public Task task() {
return new Task();
}
这类 Bean 通常用在"短生命周期"或"临时状态"对象上,比如线程任务、策略对象等。
4. Bean 和普通对象的本质区别
这题是面试官最喜欢用来"筛选初中级"的问题之一👇:
对比项 | 普通对象 | Spring Bean |
---|---|---|
创建 | new 手动创建 |
容器反射实例化 |
生命周期 | 由程序员控制 | 由 IoC 容器管理 |
注入 | 手动调用构造器/Setter | 自动依赖注入 |
配置 | 写死在代码里 | 可由配置文件/注解动态控制 |
管理 | 程序员负责 | Spring 负责全生命周期管理 |
简单说,Bean 是容器里的"公民",而你手动 new 出来的只是"野生对象"。
5. 常见坑点:Bean 搞不懂,项目迟早出事
🔴 坑 1:在容器外手动 new
对象 你以为只是 new 了一下,结果它的依赖全是 null
,AOP 不生效,事务也没用。
✅ 解决 :始终通过容器获取 Bean(@Autowired
/ ApplicationContext.getBean()
)。
🔴 坑 2:误把 Bean 当线程安全用 Spring 只保证单例 Bean 是唯一实例 ,不保证线程安全。 如果它有可变状态,就得自己加锁或用原子类。
🔴 坑 3:prototype
用完不销毁 prototype
Bean 的销毁容器不管,容易内存泄漏。
✅ 解决:使用完毕手动清理资源,或交给自定义工厂管理。
6. 面试官最爱的灵魂拷问(附答案)
❓ Q:Spring Bean 默认是线程安全的吗? 👉 不是。singleton
只是单实例,不等于线程安全。有状态对象要自己保证并发安全。
❓ Q:Bean 的生命周期有哪些阶段? 👉 实例化 → 依赖注入 → Aware → 前置处理 → 初始化 → 后置处理 → 就绪 → 销毁
❓ Q:prototype
Bean 和 singleton
的区别? 👉 前者每次注入新建实例,不受容器销毁管理;后者全局单例,由容器全程托管。
❓ Q:Bean 和普通对象有何不同? 👉 Bean 由 IoC 容器管理生命周期、注入依赖、支持 AOP 等;普通对象一切都得自己来。
总结:Bean 不只是"对象",而是 Spring 的灵魂
项目能跑不代表你理解了 Spring,Bean 是一切的起点:
- 它不仅是"被托管的对象",更是容器与业务代码的连接点;
- 它的生命周期决定了依赖注入、AOP、事务能否正确工作;
- 它的作用域影响着实例行为和线程安全;
- 它的管理方式,决定了你的代码是"Spring 风格"还是"面向 new 风格"。
一句话记住:
"Bean 不是你 new 出来的对象,而是 Spring 世界的公民。你要理解它的一生,才能真正理解 Spring。"