大家好,老 J。
恭喜你追到了系列最后一期。
前面六期我们讲了启动流程、自动配置、IoC 容器、Bean 生命周期、循环依赖、SPI 机制。这一期不做新知识,而是完整复盘 + 面试指南 + 源码学习心法。
无论你是为了面试,还是为了真正理解 Spring Boot,这一期都会帮你把零散的知识点串成一张网。
一、全系列知识点全景图
┌─────────────────────────────────────────────────────────────────────────────┐
│ Spring Boot 源码全景图 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ SpringApplication.run() │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌─────────────────────────────────────────────────────────────┐ │ │
│ │ │ 阶段一:准备阶段 │ │ │
│ │ │ • 推断应用类型(SERVLET/REACTIVE/NONE) │ │ │
│ │ │ • 加载 SpringFactoriesLoader(SPI 机制) │ │ │
│ │ │ • 创建 Environment(加载配置文件) │ │ │
│ │ │ • 打印 Banner │ │ │
│ │ └─────────────────────────────────────────────────────────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌─────────────────────────────────────────────────────────────┐ │ │
│ │ │ 阶段二:容器创建阶段 │ │ │
│ │ │ • 根据应用类型创建 IOC 容器 │ │ │
│ │ │ • 准备容器(设置 Environment、添加 BeanPostProcessor) │ │ │
│ │ └─────────────────────────────────────────────────────────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌─────────────────────────────────────────────────────────────┐ │ │
│ │ │ 阶段三:容器刷新阶段(refresh() 12 步) │ │ │
│ │ │ │ │ │
│ │ │ 1. prepareRefresh —— 准备刷新 │ │ │
│ │ │ 2. obtainFreshBeanFactory —— 获取 BeanFactory │ │ │
│ │ │ 3. prepareBeanFactory —— 准备 BeanFactory │ │ │
│ │ │ 4. postProcessBeanFactory —— 子类扩展 │ │ │
│ │ │ 5. invokeBeanFactoryPostProcessors —— 执行 BeanFactory 后置 │ │ │
│ │ │ 6. registerBeanPostProcessors —— 注册 Bean 后置处理器 │ │ │
│ │ │ 7. initMessageSource —— 初始化国际化 │ │ │
│ │ │ 8. initApplicationEventMulticaster —— 初始化事件广播器 │ │ │
│ │ │ 9. onRefresh —— 启动 Web 容器(Tomcat) │ │ │
│ │ │10. registerListeners —— 注册监听器 │ │ │
│ │ │11. finishBeanFactoryInitialization —— 实例化单例 Bean(核心) │ │ │
│ │ │12. finishRefresh —— 发布刷新完成事件 │ │ │
│ │ └─────────────────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────┐ ┌───────────────────────────────────┐ │
│ │ Bean 生命周期 │ │ 循环依赖解决 │ │
│ │ │ │ │ │
│ │ 实例化 │ │ 一级缓存:成品 │ │
│ │ ↓ │ │ 二级缓存:半成品 │ │
│ │ 属性填充(@Autowired) │ │ 三级缓存:ObjectFactory │ │
│ │ ↓ │ │ │ │
│ │ Aware 接口 │ │ 原理:提前暴露半成品 │ │
│ │ ↓ │ │ │ │
│ │ @PostConstruct │ │ 注意:构造器注入无法解决 │ │
│ │ ↓ │ │ │ │
│ │ InitializingBean │ │ │ │
│ │ ↓ │ │ │ │
│ │ init-method │ │ │ │
│ │ ↓ │ │ │ │
│ │ AOP 代理生成 │ │ │ │
│ └───────────────────────────────┘ └───────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ @SpringBootApplication │ │
│ │ │ │ │
│ │ ┌─────────────┼─────────────┼─────────────┐ │ │
│ │ ▼ ▼ ▼ ▼ │ │
│ │ @SpringBoot @EnableAuto @ComponentScan @Configuration │ │
│ │ Configuration Configuration │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ AutoConfigurationImportSelector │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ SpringFactoriesLoader │ │
│ │ (加载 spring.factories) │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘二、面试高频 20 问
第一梯队:必考(⭐️⭐️⭐️)
1. Spring Boot 的启动流程是怎样的?
回答模板:
Spring Boot 启动分为三个阶段:
准备阶段:推断应用类型、加载
spring.factories、创建 Environment、打印 Banner容器创建阶段:根据应用类型创建 IOC 容器,准备容器基础设施
刷新阶段:执行
refresh()方法的 12 个步骤,其中最重要的是invokeBeanFactoryPostProcessors(解析 Bean 定义)和finishBeanFactoryInitialization(实例化单例 Bean)。Web 项目会在onRefresh中启动内嵌 Tomcat。
2. @SpringBootApplication 由哪些注解组成?
三个核心注解:
• @SpringBootConfiguration:本质是@Configuration• @EnableAutoConfiguration:开启自动配置• @ComponentScan:组件扫描,默认扫描当前包及子包
3. 自动配置的原理是什么?
1. @EnableAutoConfiguration导入AutoConfigurationImportSelector2. 通过 SpringFactoriesLoader加载META-INF/spring.factories中所有EnableAutoConfiguration配置类3. 通过 @Conditional条件注解过滤,决定哪些配置类生效4. 配置类中的 @Bean方法注册 Bean
4. Spring 如何解决循环依赖?
Spring 通过三级缓存解决单例 Bean 的循环依赖:
• 一级缓存:完全初始化好的 Bean(成品) • 二级缓存:早期暴露的 Bean(半成品) • 三级缓存:ObjectFactory(用于生成代理对象) 核心思路:提前暴露半成品 Bean。当 A 依赖 B、B 依赖 A 时,A 实例化后将 ObjectFactory 放入三级缓存,B 实例化时从缓存获取 A 的半成品注入,B 完成后回填 A。
5. Spring 中的 Bean 生命周期是怎样的?
实例化 → 属性填充 → Aware 接口 → BeanPostProcessor 前置 → @PostConstruct → InitializingBean → init-method → BeanPostProcessor 后置(AOP 代理) → 使用 → @PreDestroy → DisposableBean → destroy-method
第二梯队:常考(⭐️⭐)
6. BeanFactory 和 ApplicationContext 的区别?
7. @Component 和 @Bean 的区别?
8. @Autowired 和 @Resource 的区别?
9. 如何自定义 Starter?
1. 写一个自动配置类( @Configuration+@Conditional)2. 定义 @ConfigurationProperties接收配置3. 在 META-INF/spring.factories或AutoConfiguration.imports中注册自动配置类4. 可选:写一个 spring-boot-autoconfigure模块 +spring-boot-starter模块
10. Spring Boot 支持哪些外部配置方式?
优先级从高到低:
1. 命令行参数 2. 环境变量 3. application.properties/application.yml4. @PropertySource指定文件5. 默认配置 记住:约定大于配置,但覆盖也方便。
第三梯队:进阶(⭐)
11. @Conditional 条件注解有哪些?
@ConditionalOnClass、@ConditionalOnMissingClass、@ConditionalOnBean、@ConditionalOnMissingBean、@ConditionalOnProperty、@ConditionalOnWebApplication、@ConditionalOnExpression等。
12. @Import 注解有几种用法?
1. 直接导入配置类: @Import(XXXConfig.class)2. 实现 ImportSelector接口3. 实现 ImportBeanDefinitionRegistrar接口4. 导入 DeferredImportSelector(延迟导入,用于自动配置)
13. BeanPostProcessor 和 BeanFactoryPostProcessor 的区别?
@ComponentScan | @Autowired |
14. Spring 中的事件机制是如何工作的?
1. ApplicationEvent:定义事件2. ApplicationListener:监听事件3. ApplicationEventPublisher:发布事件4. 默认是同步的,可配置 ApplicationEventMulticaster改为异步
15. @Transactional 的工作原理?
通过 AOP 代理实现:
1. 代理对象调用目标方法 2. 判断该方法是否有 @Transactional3. 开启事务,执行目标方法 4. 如果发生异常且满足回滚条件,事务回滚;否则提交 5. 注意:同一个类内部方法调用,事务不生效(因为走的是原始对象,不是代理)
16. Spring Boot 如何实现启动后立即执行一段代码?
• CommandLineRunner:参数是 String 数组• ApplicationRunner:参数是封装好的ApplicationArguments• @PostConstruct:Bean 初始化完成后执行
17. Spring Boot 的异常处理机制?
1. 局部: @ExceptionHandler加在 Controller 内部2. 全局: @ControllerAdvice+@ExceptionHandler3. 自定义: ErrorController/BasicErrorController
18. Spring Boot 支持哪些 Web 容器?
默认 Tomcat,可以切换为 Jetty 或 Undertow:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>org.springframework.boot:spring-boot-starter-tomcat</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
19. @SpringBootApplication 的 exclude 属性有什么用?
用于排除特定的自动配置类:
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
20. SpringBoot 如何实现多环境配置?
使用 Profile:
• 文件命名: application-dev.yml、application-prod.yml• 激活方式: spring.profiles.active=dev、命令行--spring.profiles.active=prod、环境变量SPRING_PROFILES_ACTIVE
三、源码学习心法
1. 从哪里开始读?
入口一:SpringApplication.run()
├── 这是 Spring Boot 的大本营,启动流程全在这里
入口二:@EnableAutoConfiguration
├── 自动配置的门户,理解自动配置从这开始
入口三:refresh() 方法
├── Spring 的核心,每次看都会有新收获
入口四:getBean() 方法
├── 理解 Bean 的创建流程2. 怎么读源码不迷路?
| 结合调试 | |
| 画图 | |
| 抓住主干 | |
| 多问自己 | |
| 版本对比 |
3. 推荐阅读顺序
第一遍:启动流程(不求甚解,建立整体印象)
↓
第二遍:自动配置(理解 @EnableAutoConfiguration 的魔力)
↓
第三遍:refresh() 12 步(背下来!)
↓
第四遍:Bean 生命周期 + 循环依赖(面试重点)
↓
第五遍:SPI 机制 + 扩展点(理解 Spring Boot 的开放性)4. 调试技巧
# 设置 Spring Boot 的日志级别为 DEBUG,看启动过程
logging.level.org.springframework.boot=DEBUG
# 打印自动配置报告
--debug
# 在代码中加条件断点
# IDEA 中可以在条件断点里写表达式:beanName.equals("userService")四、系列总结
七期 Spring Boot 源码解析,从启动到 IoC,从自动配置到 SPI,从 Bean 生命周期到循环依赖,我们把这些“面试必考”的知识点扎扎实实过了一遍。
每一期的核心收获
SpringApplication.run() | ||
AutoConfigurationImportSelectorspring.factories | ||
refresh() | ||
SpringFactoriesLoader | ||
接下来的路
源码读完了,面试题也背了,接下来建议:
1. 动手写一个 Starter:把理论落地 2. 去 GitHub 读其他框架的源码:比如 Nacos、Sentinel 3. 关注 Spring Boot 3.x:看看新版本有什么变化 4. 把学到的知识写下来:输出是最好的输入
五、下个系列预告
Spring Boot 源码解析系列完结后,下个系列我想写:
《Spring Cloud 微服务实战 · 重修版》
• 用最新版本(Spring Cloud 2023.x + Spring Boot 3.x) • 补充遗漏的实战细节 • 增加更多生产案例
老铁们想看什么,评论区告诉我。
六、互动时间
七期跟下来的老铁,评论区扣个 1。
哪一期对你帮助最大?还有什么想了解的?
源码学习的路上,老 J 陪你。
我是老 J,下个系列见。
夜雨聆风