Spring 核心知识地图、学习顺序与排查入口
Spring 的知识点不是互相独立的注解集合。@Transactional 依赖 AOP 代理,AOP 代理依赖 BeanPostProcessor,BeanPostProcessor 依赖容器先完成定义注册,依赖注入又发生在 Bean 创建过程中的特定阶段。
本页负责把这些专题连接成完整路线。每个原理、Demo 和生产 Runbook 都保留在独立知识页,本页提供前置关系、进入条件、验收目标和精确跳转。
一、全局主线
mermaid
flowchart TD
A["配置类、扫描、Import或XML"] --> B["注册BeanDefinition"]
B --> C["BDRPP与BFPP修改定义"]
C --> D["注册BeanPostProcessor"]
D --> E["getBean触发实例化"]
E --> F["Merged定义处理与early factory"]
F --> G["populateBean依赖注入"]
G --> H["Aware与初始化回调"]
H --> I["BPP后置与AOP代理"]
I --> J["最终Bean进入scope缓存"]
J --> K["外部调用进入代理拦截器链"]
K --> L["事务、缓存、权限等增强"]
L --> M["MVC接收和返回HTTP数据"]
M --> N["容器关闭并有序销毁"]任何知识点都能放回这条主线:
- 自动配置主要发生在 BeanDefinition 注册和条件判断阶段;
- Autowired/Resource 主要发生在依赖解析和属性填充阶段;
- PostConstruct 在初始化前处理链中;
- AOP 代理常在初始化后处理阶段;
- Transactional 的 TransactionInterceptor 位于代理方法调用链;
- DispatcherServlet 和 Controller 也是容器管理的 Bean;
- PreDestroy 和 destroy-method 位于容器关闭阶段。
二、为什么必须按照依赖顺序学习
text
BeanDefinition都不理解
↓
无法理解自动配置怎样注册Bean
↓
不了解Bean创建
↓
无法理解Autowired和生命周期
↓
不了解BeanPostProcessor
↓
无法理解AOP代理怎样产生
↓
不了解代理入口
↓
无法理解Transactional为什么失效
↓
不了解Servlet和MVC组件
↓
无法按阶段定位HTTP问题所以学习顺序不是按照注解使用频率,而是按照原理依赖关系。
三、第一阶段:容器、定义和依赖解析
学习目标
- 区分 IoC 与 DI;
- 区分 BeanDefinition 与 Bean;
- 区分 BeanFactory 与 ApplicationContext;
- 理解 refresh、getBean 和 doCreateBean;
- 理解 singleton、prototype、FactoryBean和父子容器;
- 理解构造器、字段和Setter注入阶段;
- 能分析多候选选择结果。
页面顺序
不掌握会怎样
- 手工 new 的对象没有注入和事务;
- 多实现注入错误;
- FactoryBean 工厂和产品混淆;
- 父子容器中找错 Bean;
- 把字段名回退当作业务契约;
- 遇到 UnsatisfiedDependencyException 不知道沿哪条依赖链排查。
四、第二阶段:生命周期
核心主线
text
实例化
↓
MergedBeanDefinitionPostProcessor
↓
early reference工厂
↓
属性填充
↓
Aware
↓
BPP前置
↓
PostConstruct / afterPropertiesSet / init-method
↓
BPP后置与代理
↓
业务使用
↓
PreDestroy / destroy / destroy-method进入:Bean生命周期与回调顺序全过程。
必须能回答
- 构造器中为什么字段注入为 null;
- BeanNameAware 与 ApplicationContextAware 谁处理;
- 三种初始化方法顺序;
- BPP 返回 null 的语义;
- SmartInitializingSingleton 与 SmartLifecycle 区别;
- prototype 为什么不统一销毁;
- A 依赖 B 时为什么先销毁 A。
五、第三阶段:Lazy、作用域和循环依赖
页面顺序
关键区别
| 问题 | 正确结论 |
|---|---|
| 定义级Lazy | 预实例化阶段跳过BeanDefinition |
| 注入点Lazy | 先注入延迟解析代理 |
| singleton属性循环 | 特定条件下可能通过early reference完成 |
| 构造器循环 | 实例产生前互相需要,三级缓存无能为力 |
| prototype循环 | 不进入singleton三缓存,通常失败 |
| Lazy构造器代理 | 改变依赖解析时机,不是三级缓存解决 |
| Boot 2.6+ | 默认禁止循环引用,开启只适合遗留过渡 |
生产风险
- Lazy 把配置错误推迟到首个请求;
- 循环依赖造成原始对象和代理不一致;
- 多层代理组合无法保证 early reference;
- 为启动把构造器改字段会隐藏设计问题;
- prototype 持有资源却无人销毁。
六、第四阶段:扩展点
| 目标 | 扩展点 | 操作对象 |
|---|---|---|
| 动态注册定义 | BeanDefinitionRegistryPostProcessor | 注册表 |
| 修改定义 | BeanFactoryPostProcessor | BeanDefinition/BeanFactory |
| 干预实例化和注入 | InstantiationAwareBeanPostProcessor | Bean创建过程 |
| 缓存合并定义元数据 | MergedBeanDefinitionPostProcessor | RootBeanDefinition和class |
| 生成早期引用 | SmartInstantiationAwareBeanPostProcessor | early reference |
| 初始化前后包装 | BeanPostProcessor | Bean实例或代理 |
| 销毁前处理 | DestructionAwareBeanPostProcessor | 待销毁Bean |
| 创建复杂产品 | FactoryBean | 工厂产品 |
| 导入配置 | ImportSelector / DeferredImportSelector | 配置候选 |
| 编程注册 | ImportBeanDefinitionRegistrar | BeanDefinition |
| 容器启停 | SmartLifecycle | 长运行组件 |
| 事件通知 | ApplicationListener | 事件 |
判断扩展点的方法
先问“需要干预哪个阶段”,再选接口。不要为了复用几行业务逻辑就写 BPP;框架级扩展会影响大量 Bean,必须考虑顺序、线程安全、异常和版本兼容。
七、第五阶段:AOP
mermaid
flowchart TD
A["AutoProxyCreator检查Bean"] --> B["查找匹配Advisor"]
B --> C["ProxyFactory创建代理"]
C --> D["业务持有代理引用"]
D --> E["外部方法调用"]
E --> F["MethodInterceptor.proceed链"]
F --> G["目标方法"]
G --> H["按Java调用栈反向退出"]必须掌握:
- Aspect、Advisor、Pointcut、Advice;
- JDK 代理与 CGLIB;
- MethodInterceptor;
- Around 的 proceed 语义;
- 切面顺序;
- 异常和返回值;
- final/private/static;
- self-invocation;
- early proxy;
- Spring AOP 与 AspectJ。
八、第六阶段:事务
进入:
原理依赖
text
Bean进入容器
↓
AutoProxyCreator创建事务代理
↓
外部调用进入TransactionInterceptor
↓
解析TransactionAttribute
↓
PlatformTransactionManager获取或创建事务
↓
资源绑定当前线程
↓
执行目标方法
↓
提交、回滚和清理必须掌握:
- 声明式与编程式;
- REQUIRED、REQUIRES_NEW、NESTED;
- 逻辑事务与物理事务;
- rollback-only;
- UnexpectedRollbackException;
- checked exception;
- TransactionSynchronization;
- 连接池风险;
- afterCommit 与可靠消息区别;
- 数据库事务不能覆盖 MQ、Redis、ES。
九、第七阶段:MVC
text
Servlet容器与Filter
↓
DispatcherServlet
↓
HandlerMapping
↓
HandlerAdapter
↓
参数解析、转换、绑定和校验
↓
Controller调用Service代理
↓
返回值处理
↓
内容协商和HttpMessageConverter
↓
异常解析和响应提交必须能区分:
- 404:映射路径;
- 400:转换、JSON读取或校验;
- 415:服务端不能读取 Content-Type;
- 406:Accept 与可写类型无交集;
- 500:Controller前、业务中、序列化或视图阶段;
- response committed:无法重新生成统一错误响应。
十、源码阶段
源码阅读顺序:
AbstractApplicationContext.refresh();invokeBeanFactoryPostProcessors();registerBeanPostProcessors();finishBeanFactoryInitialization();preInstantiateSingletons();doGetBean();createBean();doCreateBean();populateBean();initializeBean();close()与destroySingletons()。
源码目标是解释真实状态变化,不是背类名和行号。
十一、一条商业调用链如何串起全部知识
mermaid
flowchart TD
A["HTTP创建订单请求"] --> B["MVC解析JSON并校验"]
B --> C["Controller调用OrderService代理"]
C --> D["TransactionInterceptor开启事务"]
D --> E["Service调用Repository"]
E --> F["写订单和Outbox"]
F --> G["事务提交"]
G --> H["异步任务发送MQ"]
H --> I["消费者幂等处理"]
I --> J["失败重试、补偿和监控"]涉及:
- IoC 组装 Controller、Service、Repository和客户端;
- 生命周期初始化、启动和关闭连接及消费者;
- AOP 生成事务代理;
- 事务保证订单和 Outbox 本地一致;
- MVC 负责协议输入输出;
- 扩展点提供异常、参数、监控和 Starter;
- 分布式模块负责 MQ 可靠性和补偿。
十二、已验证 Demo 地图
| 专题 | 验证内容 | 关键输出 |
|---|---|---|
| IoC | Qualifier、singleton、依赖注入 | BANK:ORDER-1001:99.90等 |
| Autowired/Resource | 显式Qualifier、Resource name、Primary | EMAIL+SMS |
| 手写Resource | 名称、类型回退、歧义和显式缺失 | SMS+EMAIL+AUDIT |
| Lazy | 代理先注入、首次调用创建目标 | proxyClass=$Proxy... |
| 生命周期 | 15个创建和销毁事件 | constructor ... customDestroy |
| 循环依赖 | 字段成功、构造失败、禁用失败、Lazy成功 | 四个passed |
| AOP | Advisor顺序和JDK代理 | [outer-before ...] |
| Spring MVC | 路径、JSON校验和415 | Tests run: 3, Failures: 0 |
| 容器源码 | BFPP、BPP、SmartInitializingSingleton和destroy | 12事件列表 |
这些 Demo 使用 JDK 8 语法或 --release 8 验证;Spring 6/Boot 3 差异在各专题版本章节说明。
十三、按异常进入知识页
| 异常或现象 | 首先进入 |
|---|---|
| NoSuchBeanDefinitionException | 依赖注入异常诊断 |
| NoUniqueBeanDefinitionException | Autowired候选算法 |
| UnsatisfiedDependencyException | 依赖注入生产Runbook |
| BeanCurrentlyInCreationException | 循环依赖生产Runbook |
| BeanCreationException | 生命周期创建失败 |
| PostConstruct不执行 | PostConstruct排查 |
| Bean没有代理 | 生命周期代理缺失 |
| Transactional不生效 | Spring事务 |
| 启动很慢 | 容器启动慢 |
| 首个请求很慢 | Lazy生产Runbook |
| HTTP 400/404/415/406 | MVC错误阶段 |
| 关闭卡住 | 生命周期销毁Runbook |
十四、按目标选择路线
零基础后端开发
text
总览 → IoC → 注入 → 生命周期 → Lazy/循环 → AOP → 事务 → MVC → Boot面试准备
text
知识页理解原理
↓
运行Demo
↓
故意制造错误
↓
阅读面试标准回答
↓
回到知识锚点补追问进入:Spring面试知识点。
基础组件或 Starter 开发
text
IoC/源码 → 扩展点 → AOP → Boot自动配置 → Starter → 版本兼容与测试生产故障排查
从异常和阶段进入,不从“Spring大全”第一页开始顺序翻。先确定定义、创建、代理、事务、MVC还是关闭阶段,再进入对应 Runbook。
十五、容易混淆的概念对照
| 概念A | 概念B | 核心区别 |
|---|---|---|
| IoC | DI | 控制权思想 vs 实现IoC的注入方式 |
| BeanDefinition | Bean | 创建元数据 vs 运行对象 |
| BeanFactory | ApplicationContext | 基础工厂契约 vs 完整应用上下文 |
| BeanFactory | FactoryBean | 容器接口 vs 创建特殊产品的Bean |
| BFPP | BPP | 修改定义/工厂 vs 处理实例 |
| 实例化 | 初始化 | 产生对象 vs Aware、回调和后处理 |
| 原始对象 | 代理 | target vs 拦截调用的外层对象 |
| 定义级Lazy | 注入点Lazy | 跳过预实例化 vs 注入延迟代理 |
| early reference | 完整singleton | 创建中的引用 vs 生命周期完成对象 |
| 逻辑事务 | 物理事务 | Spring方法语义层 vs 数据库连接事务 |
| Filter | Interceptor | Servlet链 vs MVC Handler链 |
| Spring AOP | AspectJ | 代理式方法拦截 vs 更广泛织入能力 |
十六、版本边界
| 版本线 | 重点 |
|---|---|
| JDK 7 + Spring 4 | 存量基础,不能使用lambda和record |
| JDK 8 + Spring 5.3 | 本栏目主要可运行Demo基线 |
| Boot 2.7 | JDK 8兼容,javax生态 |
| Spring 6 / Boot 3 | Java 17基线,Jakarta生态 |
跨版本学习要区分稳定原理和内部实现。BeanDefinition、生命周期阶段和代理入口是稳定主线;具体缓存锁、默认路径匹配、内部类名和默认配置可能变化。
十七、学习验收
完成核心知识后,应能够:
- 画出定义到代理再到销毁的流程;
- 解释构造器和字段注入的阶段差异;
- 分析 Autowired 与 Resource 候选;
- 解释三缓存和 early proxy;
- 选择正确 Spring 扩展点;
- 画出 MethodInterceptor 链;
- 复现 self-invocation 事务失效;
- 区分传播行为和连接池风险;
- 从 Content-Type、Accept 区分 415 和 406;
- 沿 refresh、doGetBean、doCreateBean 设置断点;
- 根据异常进入准确 Runbook;
- 说明 JDK 8 与 Spring 6 的边界。
完整逐项验收:Spring从零到精通验收清单。
十八、下一步
按顺序进入:
