说说 Spring 启动过程?
- 标签:后端、Spring
🏛 业务架构师
Spring 启动我按对业务有意义的阶段讲,不背源码细节:
- 准备与加载配置:SpringApplication.run 先推断应用类型(Servlet/Reactive),加载 environment(配置文件、环境变量、启动参数)——配置的优先级体系在这里生效,多环境(dev/staging/prod)隔离就靠它;
- 创建并准备容器:实例化 ApplicationContext,注册 BeanDefinition(扫描 @Component、解析 @Import)——此时 bean 还只是"图纸";
- refresh 核心流程:invokeBeanFactoryPostProcessors(自动配置在这里展开,条件注解过滤该装哪些 starter 的 bean)→ 注册 BeanPostProcessor → onRefresh 启动内嵌 Tomcat → 实例化非懒加载单例(实例化 → 属性注入 → 初始化回调);
- 收尾:发布 ready 事件、执行 ApplicationRunner/CommandLineRunner——业务预热动作(缓存预加载、配置校验)的标准挂点,我的习惯是预热没完成就不放流量。
业务视角我最关注两点:
- 启动时长是工程效能指标:决定发布速度、滚动发布的批量、以及弹性伸缩和 Serverless 的冷启动体验。应用膨胀后 bean 数千个、启动从 30 秒涨到 5 分钟,要做懒加载治理和启动分析(Spring Boot Startup Actuator);
- 启动钩子承载业务初始化协议:资源预建(连接、线程池)、强依赖校验(fail-fast,配置缺失宁可起不来也别带病上岗)。
理解启动过程,本质是掌握在哪里安全地插进业务初始化逻辑。
🏗 系统架构师
Spring 启动我按"容器生命周期"主线讲(以 AnnotationConfig 为例):
- 准备阶段:
new AnnotationConfigApplicationContext()时创建 BeanFactory(DefaultListableBeanFactory),注册内置 PostProcessor(如 ConfigurationClassPostProcessor); - 配置解析:注册配置类,
refresh()开启核心流程; - refresh 的关键步骤:
- obtainFreshBeanFactory:加载 BeanDefinition(注解扫描/配置类解析,
@ComponentScan、@Import、@Bean在这阶段被处理); - prepareBeanFactory / postProcessBeanFactory:设置类加载器、表达式解析器,留给子类扩展;
- invokeBeanFactoryPostProcessors:执行 BFPP,ConfigurationClassPostProcessor 在这里完成扫描闭环;
- registerBeanPostProcessors:注册 BPP(AutowiredAnnotationBeanPostProcessor 等);
- initMessageSource / initApplicationEventMulticaster / onRefresh(Web 容器在这启动内嵌 Tomcat)/ registerListeners;
- finishBeanFactoryInitialization:实例化所有非懒加载单例(依赖注入、初始化回调、AOP 代理生成都在此时);
- finishRefresh:发布 ContextRefreshedEvent。
- obtainFreshBeanFactory:加载 BeanDefinition(注解扫描/配置类解析,
面试我抓两点:BeanDefinition 是蓝本、BeanFactoryPostProcessor 和 BeanPostProcessor 是两大扩展支柱,理解了它们就能解释 Spring 绝大部分魔法(自动配置、AOP、注入)。
💻 全栈开发专家
核心是 AbstractApplicationContext.refresh() 的模板流程,我按"面试必讲 + 工程排障点"挑六个阶段:
- prepareRefresh:设置启动时间/活跃标记,加载环境属性。
- obtainFreshBeanFactory:创建 BeanFactory,解析 XML/注解为 BeanDefinition(此时还没实例化 Bean)。
- invokeBeanFactoryPostProcessors:执行 BFPP,最关键的
ConfigurationClassPostProcessor在这里扫@Configuration/@ComponentScan/@Import,@Bean也注册成 BeanDefinition——自动配置的入口。 - registerBeanPostProcessors:注册后置处理器(如
AutowiredAnnotationBeanPostProcessor,为后面依赖注入做准备)。 - onRefresh:web 应用在这里创建内嵌 Tomcat(SpringBoot 的 ServletWebServerApplicationContext)。
- finishBeanFactoryInitialization:实例化所有非懒加载单例 Bean(依赖注入、初始化回调都在这),一般是启动最耗时的阶段。
排障经验:启动慢先开 spring-main.logy 或 Actuator 的 startup endpoint(ApplicationStartup)看 timeline,我定位过一次启动 3 分钟的问题——是某个 @Bean 里同步调远端接口,改懒加载后 40s。启动报 BeanNotFound 大多发生在第 3 步扫描路径不对(@ComponentScan 漏包)。