Sunday面试指南

Spring Bean 的生命周期是什么?实例化、依赖注入和初始化有什么区别?

下面是一段教学用的模拟面试。

🧑‍💻 面试官:Spring Bean 是怎么从创建走到可使用状态的?

🙋‍♂️ 我:先 new 对象,再注入依赖,最后初始化。

🧑‍💻 面试官:如果用构造器注入,依赖要等构造器结束以后才拿到吗?

🙋‍♂️ 我:不是。构造器参数在实例化时就要准备好。

🧑‍💻 面试官:那 PostConstruct 为什么不等于构造器?如果返回的是代理,初始化回调是在谁身上执行?

生命周期不是“new 完就好了”。要看「依赖何时准备、初始化在哪执行、最终交给调用方的是谁」。

面试速答(60 秒版)

Spring Bean 的常见生命周期可以理解为:根据定义创建实例,完成必要的依赖设置和容器回调,执行初始化,再把可用的 Bean 提供给调用者;容器关闭时,对受管理的 Bean 执行相应销毁回调。

实例化是把对象创建出来。依赖注入是把它需要的协作者交给它,构造器注入会参与实例化过程,字段或 setter 注入则通常在实例创建后完成。

初始化负责在依赖已设置的基础上,检查配置、准备内部状态。常见方式有 PostConstruct、InitializingBean 和自定义 init 方法。BeanPostProcessor 可以参与初始化前后处理,常规 AOP 代理通常在相关后处理阶段形成。

同时,作用域会影响生命周期。prototype Bean 创建后交给调用方,容器不会像管理 singleton 那样自动负责完整的销毁过程。

Bean 不是 new 完就能用

知识点详解:用一个连接配置 Bean,把几个阶段分开

创建实例,和让对象准备好,不是一件事

假设有一个 ReportClient,需要地址配置和认证组件。

使用构造器注入时,Spring 先准备构造器需要的参数,再调用构造器创建实例。因此,不能把所有依赖注入都画成“构造器结束后才发生”。

如果使用 setter 注入,实例先被创建出来,Spring 再调用 setter 设置相应属性。具体时间不同,但共同目标都是让这个 Bean 拿到需要的依赖。

所以“实例化 → 注入”可以作为普通讲解主线,遇到构造器注入时,必须把这个重叠关系补上。

初始化要解决的是“现在能不能正常工作”

地址已经赋值,不等于地址一定合法。认证组件已经存在,不等于当前配置满足调用条件。

初始化回调可以检查这些条件,准备基于配置的内部数据。PostConstruct 不是构造器的另一个名字,它发生在容器完成相关依赖设置之后。

如果同一个 Bean 配置了不同名称的多种初始化回调,Spring 文档给出的顺序是 PostConstruct、afterPropertiesSet、自定义初始化方法。不要在这几个位置重复执行同一份昂贵工作。

同时,初始化里不适合随意启动复杂、耗时且依赖其他 Bean 完全就绪的操作。需要容器整体启动后的工作,应选择相应的容器事件或生命周期机制,而不是把所有事情塞进 PostConstruct。

依赖注入与初始化怎样交接?

BeanPostProcessor 为什么也出现在生命周期里?

它不是当前 Bean 的某个业务方法,而是容器的扩展机制。后处理器可以在初始化前后检查、修改或包装 Bean。

例如 PostConstruct 的支持本身就涉及相应后处理器。常规 AOP 代理也会利用后处理过程,把目标对象包装成调用方最终取得的代理。

因此,不要把“初始化前后”理解成两段绝对没有其他动作的空白。也不要认为构造器一完成,所有代理已经存在。高级的提前引用等机制另有细节,本篇只解释普通创建路径。

为什么在初始化里调用方法,不一定触发事务代理?

初始化回调通常在原始目标对象上执行。调用方之后拿到代理,并不能让对象内部较早发生的初始化调用倒过来经过代理。

如果某段工作需要事务拦截,应该明确调用边界和启动时机,而不是只在初始化方法上加注解,再认定一定生效。

这里与 Bean 生命周期有关,但不需要重新把 JDK 动态代理、CGLIB 全讲一遍。

原始对象、代理、调用者

创建由容器负责,销毁也一定由容器负责吗?

singleton Bean 通常由容器持续管理,容器正常关闭时会执行已登记的销毁回调,例如 PreDestroy、自定义 destroy 方法等。

prototype 则不同。容器负责创建和配置,交付实例后,后续资源清理通常需要调用方负责。

还要注意,销毁回调不是操作系统强制终止进程时仍保证执行的机制。数据库连接、文件句柄等资源的安全释放,不能完全依赖一次“理想的关闭”。

面试官继续追问

构造器、PostConstruct 和应用启动完成事件怎么选?

构造器建立对象必须满足的基本条件;PostConstruct 检查已经注入的配置与内部准备;需要其他普通 singleton 也初始化完成以后再做的工作,选择合适的容器事件或扩展机制。先确定依赖条件,再选回调。

BeanPostProcessor 和 BeanFactoryPostProcessor 是一回事吗?

不是。前者主要处理 Bean 实例,后者在实例创建前处理容器里的 Bean 定义等配置元数据。把定义和实例区分开,就不容易背混。

怎么核对生命周期顺序?

在小型测试项目中记录构造器、setter、初始化回调、后处理器和关闭回调,附上 Bean 名称与实例身份。分别测试构造器注入、setter 注入和不同作用域,不把一种配置的日志当成全部路径。

面试速记卡

  • 实例化:创建对象;构造器依赖在这个阶段就要准备。
  • 依赖注入:交给对象需要的协作者,时机取决于注入方式。
  • 初始化:依赖设置后检查配置、准备内部状态。
  • 后处理器:参与实例处理与包装,普通代理路径要考虑这一层。
  • 销毁:看作用域与关闭条件,不是所有 Bean 都由容器自动清理。

公司面试真题

这道题暂未收录可核验的公司真题来源。你可以先阅读本文解析,或浏览已收录的公司面试真题。

浏览公司面试真题 →
简历汪永久免费在线制作简历,模板直接套用、导出无水印,永久免费、下载免费,不需要付费解锁任何功能。去写简历