Spring Boot依赖注入分预实例化和首次获取两阶段,核心流程为populateBean→postProcessProperties→resolveDependency,后者按类型匹配候选Bean并处理@Qualifier/@Primary等逻辑。

阅读 Spring Boot 依赖注入源码,核心是抓住“谁在什么时候、用什么方式把哪个 Bean 注入到哪个位置”这条主线。不建议从头逐行扫代码,而应聚焦关键入口和典型路径,结合调试验证逻辑。
明确注入触发的两个关键时机
依赖注入不是在容器启动时统一完成的,而是分阶段发生的:
-
预实例化阶段(early initialization):当 BeanDefinition 中设置了
lazy-init="false"(默认),Spring 在 refresh() 的 finishBeanFactoryInitialization 阶段主动创建单例 Bean,并在此过程中完成属性填充(即依赖注入) -
首次获取时(on-demand):若 Bean 是 lazy 或 prototype 类型,则直到调用
getBean()时才触发 doCreateBean → populateBean → resolveDependency 流程
锁定核心类与方法链
从字段注入(@Autowired)入手最直观,关键调用链如下:
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
-
AbstractAutowireCapableBeanFactory#populateBean():进入属性填充主流程 -
AutowiredAnnotationBeanPostProcessor#postProcessProperties():由它扫描并处理所有@Autowired字段/方法 -
DefaultListableBeanFactory#resolveDependency():真正执行类型匹配、候选 Bean 筛选、@Qualifier/@Primary 决策的核心方法 -
findAutowiringMetadata()(在 postProcessMergedBeanDefinition 中缓存元数据):只执行一次,为后续注入提速
重点关注 resolveDependency 的匹配逻辑
这个方法决定了“按类型找 Bean”如何落地,需细看三类分支:
- 当依赖类型是
Optional、ObjectProvider、javax.inject.Provider:走延迟解析路径,返回包装器而非真实实例 - 普通类型:调用
findAutowireCandidates()获取候选 Bean 名称集合,再经checkAutowireCandidate()过滤(检查 @Primary、@Qualifier、类型兼容性等) - 若候选超过一个且无 @Qualifier 明确限定,抛出
NoUniqueBeanDefinitionException
配合调试与日志快速定位
光读代码容易迷失,推荐实操方式:
- 在
resolveDependency方法首行加断点,启动应用后观察 descriptor 封装的字段类型、name、isRequired 等信息 - 开启 DEBUG 日志:
logging.level.org.springframework.beans.factory=DEBUG,可看到 “Creating shared instance of singleton bean 'xxx'” 和 “Autowiring by type from bean name 'yyy'” 等关键提示 - 对比
@Autowired与@Resource(name="xxx")的调用栈差异——后者由CommonAnnotationBeanPostProcessor处理,走的是名称驱动(byName)路径










