Spring IOC 容器初始化过程?
- 标签:后端、Spring
🏛 业务架构师
Spring IOC 容器初始化过程可以压缩为三阶段,我用"开店营业"来类比:
1. 定位与加载(找货源):入口是 refresh()。BeanDefinitionReader 从配置类/XML/注解扫描中读取元数据,封装成 BeanDefinition(类名、作用域、依赖等"采购清单"),注册进 BeanDefinitionRegistry。注意:此时只有"清单",还没有实例化任何 Bean;
2. 容器基础设施就绪(装修铺面)refresh() 内部的关键步骤:准备 Environment(外部化配置绑定)、启动 BeanFactoryPostProcessor 扩展点——自动配置、占位符解析、@Configuration 增强(CGlib 让配置类代理拦截 @Bean 调用保证单例)都发生在这一步,相当于开业前把货架规则全改好;
3. Bean 实例化(上架营业):国际化、事件广播器初始化后,finishBeanFactoryInitialization 预实例化所有非懒加载单例——走完整的 Bean 生命周期(实例化 → 注入 → Aware → BeanPostProcessor → 代理生成),最后发布 ContextRefreshedEvent。
架构师视角的关注点:启动耗时治理。业务膨胀后这个阶段动辄几十秒,直接影响 K8s 扩容速度和发布窗口。我的实战手段:懒加载非核心 Bean、spring-context-indexer/AOT 加速扫描、Spring Boot 3 的 CRaC 或 Native Image。理解初始化流程,才知道优化往哪使劲——这是这个知识点在 2026 年真正的业务价值。
🏗 系统架构师
两大阶段:BeanDefinition 装载 → refresh() 生命周期。
- 装载:通过 BeanDefinitionReader(注解扫描/XML)解析元数据并注册进 BeanDefinitionRegistry——此时只是图纸入库,未实例化;
- refresh() 关键步骤:
- prepareBeanFactory:容器基础设置;
- invokeBeanFactoryPostProcessors:配置治理的黄金扩展点——ConfigurationClassPostProcessor 处理
@Configuration、@Import、@ComponentScan,Spring Boot 自动配置就挂在这里; - registerBeanPostProcessors:注册 AOP 等实例级处理器;
- initMessageSource/事件广播器/onRefresh(Boot 在此创建内嵌服务器);
- finishBeanFactoryInitialization:实例化全部非懒加载单例;
- finishRefresh:发布 ContextRefreshedEvent。
架构视角:BFPP 改「图纸」、BPP 改「成品」,分清这两类扩展点就掌握了二次开发模型;启动耗时也集中在这条流水线——上万 Bean 的装配在弹性场景是扩容延迟,AOT/Native 与懒加载是当前的标准对策。
💻 全栈开发专家
入口是 AbstractApplicationContext#refresh(),模板方法十来个步骤,我抓主干讲:
- prepareRefresh:设置启动时间、active 标志
- obtainFreshBeanFactory:刷新 BeanFactory;注解项目由
ConfigurationClassPostProcessor解析@Configuration/@ComponentScan/@Import,把扫到的类注册成 BeanDefinition - invokeBeanFactoryPostProcessors:执行上面的解析 + 占位符处理——最早的扩展点,此时 Bean 还不存在
- registerBeanPostProcessors:注册后续用的后置处理器(含 AOP 代理创建器)
- initMessageSource / initApplicationEventMulticaster:国际化与事件广播器
- onRefresh:子类钩子,Boot 在这创建内嵌 Tomcat
- registerListeners + finishBeanFactoryInitialization:实例化所有非懒加载单例——真正的 Bean 创建、属性填充、三级缓存都在这
- finishRefresh:发布
ContextRefreshedEvent
记忆主线:BeanDefinition 先行 → BeanPostProcessor 就位 → 最后统一实例化单例。理解这个顺序就能解释为什么 BeanFactoryPostProcessor 能改 Bean 定义、为什么 AOP 代理发生在初始化之后。调试就在 refresh() 打断点单步走,Boot 下对应 SpringApplication#run 的 refreshContext 那一步。