[面试题] Spring 中 singleton 和 prototype 的创建与管理有什么区别?
📖 版块 A:知识讲解版 (温故知新)
-
singleton(单例):
- Spring 默认作用域。
- 同一个 BeanName 在整个容器中通常只对应一个实例。
- 创建完成后会缓存到单例池,如
singletonObjects。 - 后续再获取时,通常直接从缓存返回。
- 容器会负责它的完整生命周期,包括销毁回调。
-
prototype(多例):
- 每次获取都会创建一个新对象。
- 一般不会进入单例池缓存。
- Spring 通常只负责创建和初始化,不完整托管其后续销毁过程。
-
源码视角的差异:
- singleton 强调“创建一次,多次复用”。
- prototype 强调“每次请求,现场新建”。
-
一个常见误区:
- 单例不等于不安全,多例也不等于绝对安全。
- 线程安全与否,更关键还是取决于对象是否有状态、是否访问共享资源。
🎤 版块 B:面试实战版 (高手逐字稿)
Q:Spring 中 singleton 和 prototype 的创建与管理有什么区别?
💬 高手逐字稿:
在 Spring 里,singleton 和 prototype 的核心区别,不只是数量不同,更重要的是容器怎么管理它们。
先说 singleton。这是 Spring 默认作用域。对同一个 BeanName 来说,Spring 通常只会创建一个实例。这个实例在创建完成后,会被放进单例池里,比如 singletonObjects 这样的缓存结构。后续不管谁再来 getBean,通常拿到的都是同一个对象引用。也正因为如此,Spring 会完整托管它的生命周期,从创建、注入、初始化到最终销毁,容器都会负责。
再说 prototype。它的思路完全不同。每次调用 getBean,Spring 都会重新走一遍创建流程,给你 new 出一个新对象。它通常不会进入单例池,也不会像单例那样被长期缓存。更关键的是,Spring 对 prototype 的管理通常只到“创建并初始化完成”为止,后面的销毁回调很多时候要靠业务侧自己处理。
所以从源码视角可以这么记:
- singleton 是“创建一次,缓存复用”;
- prototype 是“每次请求,现场新建”。
这里还有一个容易混的点:很多人会把作用域和线程安全直接画等号。其实不准确。singleton 如果是无状态的,完全可以在并发场景里很安全;prototype 即便每次都是新对象,如果内部又用了共享静态变量、共享缓存、共享连接,也照样可能出并发问题。
所以这道题最后最好的收束方式是:作用域决定的是容器的管理策略,不直接决定业务对象的线程安全。
最后更新于: