尧图精选

Spring IoC容器与Bean生命周期详解

🕒 发布时间:2026/10/2 20:52:56 📁 来源:尧图网络
Spring IoC容器与Bean生命周期详解定位讲透 IoC 容器的两级接口、Bean 定义的注册来源、Bean 完整生命周期、核心组件分工与容器启动流程——这是理解整个 Spring 生态的地基适用版本Spring Framework 6.xJDK 17目录一、IoC 容器定位二、Bean 定义与注册三、Bean 完整生命周期四、核心组件分工五、容器启动流程refresh六、总结七、常见高频面试题一、IoC 容器定位1.1 IoC 与 DI控制反转Inversion of Control对象的创建、组装、生命周期管理不再由使用者代码负责而是交给容器——控制权从应用代码反转到框架。依赖注入Dependency Injection是 IoC 的具体实现手段容器把依赖注入给需要它的对象。注入方式构造器/字段/方法与优劣在 02 篇展开本篇只建立容器管一切的心智模型。传统写法UserService 自己 new UserDao()耦合具体实现 IoC 写法容器创建 UserDao 并注入给 UserService使用者只面向接口收益解耦面向接口、可测试注入替身、集中管理统一配置与生命周期。1.2 两级容器接口BeanFactory ← 最基础按定义创建/获取 Bean ▲ ApplicationContext ← 超集企业级能力能力BeanFactoryApplicationContextBean 实例化与依赖注入✓✓单例初始化时机懒加载getBean 时启动即初始化非懒加载单例事件发布ApplicationEvent✗✓国际化MessageSource✗✓资源访问Resource✗✓环境抽象Environment基础完整实践几乎只用ApplicationContextAnnotationConfigApplicationContext/ Web 环境的ServletWebServerApplicationContext等BeanFactory的意义是理解容器的最小内核。1.3 容器的四件事读取元数据注解/Configuration/XML→ 注册 BeanDefinition 按定义实例化、注入依赖、执行生命周期回调 按名称/类型提供 Bean、管理作用域 容器关闭时销毁回调二、Bean 定义与注册2.1 BeanDefinition 是什么容器不直接保存对象先保存Bean 的元数据描述——BeanDefinition元数据对应配置beanClass实现类scopeScopesingleton/prototype…lazyInitLazyprimaryPrimaryinitMethod / destroyMethodBean(initMethod…)/destroyMethodpropertyValues / constructorArgs注入信息autowireMode自动装配模式流程本质一切配置注解/Java/XML先统一翻译成 BeanDefinition后续流程只面对它——这是配置方式多样、内核只有一套的原因。2.2 注册来源与处理时机来源方式组件扫描Component 及派生Service/Repository/Controller/Configuration由 ComponentScan 触发Java 配置Configuration 类中的 Bean 方法XMLbean遗留系统APIBeanDefinitionRegistry#registerBeanDefinition动态注册框架扩展常用处理时机在容器刷新refresh阶段先扫描解析并注册全部定义再统一实例化——因此 Bean 之间的依赖不受声明顺序限制构造器循环依赖除外见 02 篇。三、Bean 完整生命周期单例 Bean 的完整阶段链面试最高频的一张图1. 实例化Instantiation 构造器创建原始对象尚未注入任何依赖 │ 2. 属性填充Populate 依赖注入Autowired/Resource、Value、setter │ 3. Aware 回调 BeanNameAware → BeanFactoryAware → ApplicationContextAware │ 4. BeanPostProcessor#postProcessBeforeInitialization PostConstruct 在此阶段由 CommonAnnotation 处理器执行 │ 5. 初始化顺序固定 InitializingBean#afterPropertiesSet → 自定义 init-method │ 6. BeanPostProcessor#postProcessAfterInitialization AOP 代理对象通常在此产生返回的可能是代理 │ 7. 就绪放入容器供使用 │ 8. 容器关闭时销毁顺序固定 PreDestroy → DisposableBean#destroy → 自定义 destroy-method关键认知“拿到手的 Bean 可能不是原始对象”第 6 步后置处理器可能返回代理AOP容器存的是最终对象初始化三种方式的先后PostConstructJSR-250 注解属第 4 步→ InitializingBean 接口 → init-method销毁反之 PreDestroy → DisposableBean → destroy-methodprototype Bean 不走销毁回调容器注入后即放手销毁责任在使用方。四、核心组件分工生命周期各阶段由不同扩展点负责理解分工才能正确扩展组件作用层级时机典型用途BeanDefinitionRegistry定义注册期存取 BeanDefinitionBeanFactoryPostProcessor容器级实例化之前修改/补充 Bean 定义Value 占位符解析器即此类InstantiationAwareBeanPostProcessorBean 级实例化前后、属性注入时提前返回代理、注入介入Autowired 注入由其实现BeanPostProcessorBean 级初始化前后包装对象AOP 代理、PostConstruct 处理两条辨析BeanFactoryPostProcessor vs BeanPostProcessor前者改定义对象还没创建后者改对象实例已存在Aware 接口让 Bean 感知容器基础设施自己的名字、所在工厂、上下文是框架级集成入口业务代码通常不需要。五、容器启动流程refreshAbstractApplicationContext#refresh()是容器启动的骨架模板方法主干步骤① prepareRefresh 准备时间戳、环境校验、占位符属性 ② obtainFreshBeanFactory 创建/刷新 BeanFactory加载 BeanDefinition ③ prepareBeanFactory 配置工厂类加载器、Aware 处理器、默认注册 ④ postProcessBeanFactory 子类扩展Web 环境注册作用域等 ⑤ invokeBeanFactoryPostProcessors 执行所有 BeanFactoryPostProcessor 配置类解析、组件扫描在此完成 ⑥ registerBeanPostProcessors 注册所有 BeanPostProcessor ⑦ initMessageSource 国际化 ⑧ initApplicationEventMulticaster 事件广播器 ⑨ onRefresh 子类扩展Boot 在此创建内嵌 Web 服务器 ⑩ registerListeners 注册监听器 ⑪ finishBeanFactoryInitialization 实例化所有非懒加载单例 ★ ⑫ finishRefresh 清缓存、发布 ContextRefreshedEvent三个要点⑤ 和 ⑪ 是两个大动作⑤把配置翻译成定义⑪把定义变成活对象——绝大多数启动问题出在这两步⑨ onRefresh 是 Spring Boot 内嵌服务器的挂载点BT 篇展开——理解 Framework 的扩展点才能理解 Boot 的魔法事件时机ContextRefreshedEvent在全部单例就绪后发布是容器可用的信号关闭前对应ContextClosedEvent。六、总结IoC 容器BeanFactory 是最小内核ApplicationContext 叠加事件/国际化/资源/环境并即时初始化单例容器读取元数据、管理 Bean 全生命周期。BeanDefinition 是枢纽注解/Java/XML 全部翻译成它先注册全部定义、后统一实例化依赖不受声明顺序限制。生命周期八阶段实例化 → 属性注入 → Aware → BPP 前置PostConstruct→ 初始化InitializingBean → init-method→ BPP 后置AOP 代理→ 使用 → 销毁PreDestroy → DisposableBean → destroy-method容器里存的可能已是代理。扩展点分工BeanFactoryPostProcessor 改定义实例化前BeanPostProcessor 改对象初始化前后Autowired 注入由 InstantiationAwareBeanPostProcessor 实现。refresh 十二步⑤ 解析配置、⑪ 实例化单例是两大关键⑨ 是 Boot 内嵌服务器挂载点⑫ 发布 ContextRefreshedEvent 标志就绪。七、常见高频面试题1. BeanFactory 和 ApplicationContext 的区别要点BeanFactory 是最基础容器提供 Bean 的实例化与依赖注入单例懒加载getBean 时才创建ApplicationContext 是其超集增加事件发布、国际化、资源访问、环境抽象并在启动时即初始化所有非懒加载单例提前暴露配置错误。实践基本都用 ApplicationContextBeanFactory 的意义在于理解容器最小内核。2. 完整描述一个 Bean 的生命周期。要点① 实例化构造器创建原始对象② 属性填充依赖注入③ Aware 回调BeanName/BeanFactory/ApplicationContext④ BeanPostProcessor 前置处理PostConstruct 在此⑤ 初始化InitializingBean#afterPropertiesSet → 自定义 init-method⑥ BeanPostProcessor 后置处理AOP 代理在此产生⑦ 就绪使用⑧ 容器关闭时销毁PreDestroy → DisposableBean → destroy-method。注意拿到的可能是代理对象且 prototype 不执行销毁回调。3. BeanPostProcessor 和 BeanFactoryPostProcessor 的区别要点作用对象与时机不同。BeanFactoryPostProcessor 作用于容器级在所有 Bean 实例化之前执行修改或补充的是 BeanDefinition元数据典型如属性占位符解析BeanPostProcessor 作用于单个 Bean在实例已创建后的初始化前后执行可包装/替换对象AOP 代理、PostConstruct 处理。简记前者改图纸后者改成品。4. 什么是 BeanDefinition注解、Java 配置、XML 三种方式最终如何统一要点BeanDefinition 是 Bean 的元数据描述类名、作用域、懒加载、Primary、初始化/销毁方法、依赖与属性等。三种配置方式Component 扫描、ConfigurationBean、XML 在容器刷新阶段都被解析翻译成 BeanDefinition 注册进容器后续实例化流程只面对它。这是配置入口多样、内核统一的设计也解释了为什么配置方式可以混用。5. PostConstruct、InitializingBean、init-method 的执行顺序要点PostConstruct 最先由注解处理器在 BeanPostProcessor 前置阶段执行随后是 InitializingBean#afterPropertiesSet最后才是自定义 init-method销毁顺序镜像PreDestroy → DisposableBean#destroy → destroy-method。实际项目推荐注解方式不侵入接口、声明清晰init-method 用于不想让业务类依赖 Spring 接口的场景。6. refresh() 里最关键的步骤是哪些要点两个大动作——invokeBeanFactoryPostProcessors执行所有容器级后置处理器配置类解析与组件扫描在此完成BeanDefinition 就绪和 finishBeanFactoryInitialization实例化所有非懒加载单例生命周期全链路在此跑完。另外 onRefresh 是 Spring Boot 创建内嵌 Web 服务器的挂载点finishRefresh 发布 ContextRefreshedEvent 标志容器就绪。启动问题排查基本围绕这两步。7. 容器中的单例 Bean 和单例模式是一回事吗要点不是。设计模式的单例指整个 JVM 中某类只有一个实例由类自己控制Spring 单例是每个容器中该 Bean 定义只有一个实例由容器的单例注册表singletonObjects管理——同一类可以注册多个不同名的 Bean 各自单例不同容器也可各有一份。且 Spring 单例默认无状态才安全有状态单例存在并发问题。8. 为什么容器里 getBean 拿到的对象可能不是原始类的实例要点生命周期第 6 步BeanPostProcessor 后置处理允许返回替换对象——AOP 在此把原始 Bean 包装成代理JDK 动态代理或 CGLIB 子类容器存储与注入的都是代理。后果对 Bean 做 instanceof 具体类判断在 JDK 代理下会失败代理不继承具体类只实现接口。这也是循环依赖注入的可能是半成品/代理等复杂问题的根源02 篇展开。9. Component 和 Bean 有什么区别要点作用层级不同。Component及 Service/Repository/Controller标注在类上由组件扫描发现并注册适合自有业务类Bean 标注在 Configuration 类的方法上方法返回值被注册为 Bean适合把第三方类无源码无法加注解或需要条件/多版本创建的类纳入容器。两者最终都生成 BeanDefinition。Configuration 类本身也是一个 Bean且被 CGLIB 增强保证 Bean 方法间调用返回同一实例。10. prototype 作用域的 Bean 生命周期有什么不同要点容器每次 getBean或注入都创建新实例不缓存关键差异是容器不管理其销毁——不执行销毁回调PreDestroy/DisposableBean释放资源的责任在获取它的一方。因此有状态对象如持有资源句柄用 prototype 时要自行管理清理单例 Bean 依赖 prototype 时每次拿到的都是新实例但单例自身只创建一次注入不会自动刷新需要 Lookup 或 ObjectProvider。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →