Spring 源码系列(8): 依赖注入(DI)在源码里如何发生
引子你只写了Autowired private UserService userService;对象就自动出现了。这背后 Spring 到底做了什么本篇回答三件事① DI 发生在哪一步②Autowired和Resource的区别在源码层如何体现③字段 / 构造器 / setter 注入为何出生在不同阶段——这直接决定了第 9 篇循环依赖为何只有字段注入能解。一句话结论字段/setter 注入发生在populateBean阶段由AutowiredAnnotationBeanPostProcessor.postProcessProperties找到注入点经resolveDependency → getBean(依赖)递归拿到或创建依赖对象最后field.set注入。构造器注入则更早在createBeanInstance推断构造器时就解析依赖。前置知识DI 的本质是在合适时机把依赖对象 set 进当前 Bean。处理 DI 的是InstantiationAwareBeanPostProcessor一类特殊的BeanPostProcessorAutowiredAnnotationBeanPostProcessor处理Autowired/ValueCommonAnnotationBeanPostProcessor处理Resource/PostConstruct/PreDestroy这些 BPP 在第 5 篇第 6 步registerBeanPostProcessors被注册进容器。一、字段注入发生在 populateBean// AbstractAutowireCapableBeanFactory.populateBean精简protectedvoidpopulateBean(StringbeanName,RootBeanDefinitionmbd,BeanWrapperbw){// 遍历 InstantiationAwareBeanPostProcessor触发注入for(InstantiationAwareBeanPostProcessorbp:getBeanPostProcessors()){PropertyValuespvsbp.postProcessProperties(pvs,bw.getWrappedInstance(),beanName);// Autowired 就是在这一行完成的}// XML property 配置的值应用applyPropertyValues(beanName,mbd,bw,pvs);}二、AutowiredAnnotationBeanPostProcessor 如何注入postProcessProperties→ 找注入点 → 逐个注入// AutowiredAnnotationBeanPostProcessorpublicPropertyValuespostProcessProperties(PropertyValuespvs,Objectbean,StringbeanName){// 1. 取出缓存的注入元数据Autowired 字段/方法InjectionMetadatametadatafindAutowiringMetadata(beanName,bean.getClass());// 2. 逐个注入metadata.inject(bean,beanName,pvs);returnpvs;}注入一个字段时AutowiredFieldElement.injectprotectedvoidinject(Objectbean,StringbeanName,PropertyValuespvs){Fieldfieldthis.field;ObjectvalueresolveFieldValue(field,bean,beanName);// ← 关键解析依赖ReflectionUtils.makeAccessible(field);field.set(bean,value);// 反射设值}resolveFieldValue最终会走到DefaultListableBeanFactory.resolveDependencyresolveFieldValue └─ beanFactory.resolveDependency(descriptor, beanName, ...) └─ doResolveDependency(...) ├─ 按类型找到候选 Bean可能有多个再按 Qualifier / 名称筛选 └─ resolveCandidate(beanName, ...) └─ beanFactory.getBean(beanName) // ← 递归依赖没创建就先创建它⚠️关键getBean(依赖)这一行就是依赖注入的本质——也是循环依赖产生的根源A 注入 BB 又注入 A二者互相等待。第 9 篇专门解决它。三、Autowired vs Resource维度AutowiredResource来源Spring 自带org.springframework.beans.factory.annotationJSR-250 标准javax.annotation默认匹配按类型byType**按名称byName**优先失败再 byType配合限定Qualifier(name)指定名称name属性直接指定必需性required属性默认 true无 required找不到直接报错处理类AutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor四、三种注入方式的出生阶段注入方式发生在哪源码位置能否解循环依赖字段注入populateBeanAutowiredFieldElement.inject✅ 能靠三级缓存setter 注入populateBeanAutowiredMethodElement.inject✅ 能构造器注入createBeanInstancedetermineCandidateConstructors 构造时getBean依赖❌ 不能为什么构造器注入不能解循环依赖构造器注入在createBeanInstance实例化阶段就要求依赖对象已经存在而此时当前 Bean 还没执行到addSingletonFactory三级缓存注册依赖方取不到提前暴露的引用只能再去创建当前 Bean形成无限递归 →BeanCurrentlyInCreationException。五、DI 流程图六、常见误区误区正解Autowired按名称注入默认按类型需配合Qualifier才按名称Resource是 Spring 注解是 JSR-250 标准注解由CommonAnnotationBeanPostProcessor处理构造器注入也能解循环依赖不能见上文DI 发生在initializeBean字段/setter 注入在populateBean早于初始化七、面试题自测Autowired在 Bean 生命周期的哪一步注入resolveDependency最终调用了什么方法创建依赖Autowired与Resource的核心区别字段、setter、构造器三种注入分别发生在哪个阶段为什么只有前两种能解循环依赖有多个同类型 Bean 时Autowired如何筛选出目标提示Qualifier/ 优先级八、Debug 小技巧在AutowiredAnnotationBeanPostProcessor.postProcessProperties打断电Step Intometadata.inject→resolveFieldValue看value是如何从getBean拿到的。故意制造循环依赖A 构造器注入 BB 构造器注入 A观察异常栈最顶端是BeanCurrentlyInCreationException且发生在createBeanInstance阶段。在resolveCandidate的getBean处打条件断点beanName.equals(依赖名)验证注入即触发依赖的创建。下篇预告第 9 篇爆款预定循环依赖终极拷问——为什么用三级缓存而不是二级。把本篇埋下的getBean递归与提前暴露彻底讲透。如果这篇对你有帮助欢迎点赞 · 收藏 · 关注三连支持。Spring 源码系列共 30 篇由浅入深持续更新中。有疑问或想深挖的源码点评论区告诉我下篇见。

相关新闻

iPhone17护眼钢化膜避坑:悟赫德拆解四大套路

iPhone17护眼钢化膜避坑:悟赫德拆解四大套路

iPhone17护眼钢化膜避坑指南:2026年这四大套路别再信了新买的iPhone 17到手,第一张膜往往踩坑最多。市面上关于“护眼钢化膜”的说法五花八门,蓝光膜、绿光膜、紫光膜,每个都声称自己护眼,但真正用起来不是偏色就是反光…

2026/7/24 0:48:45 阅读更多 →
栈在表达式中求值的应用(中缀表达式的结算机算——用栈实现)

栈在表达式中求值的应用(中缀表达式的结算机算——用栈实现)

文章目录中缀表达式 转 后缀表达式(机算,用栈实现)中缀表达式的机算(用栈实现)中缀表达式 转 后缀表达式(机算,用栈实现) 初始化一个栈,用于保存暂时还不能确定运算顺序…

2026/7/24 0:47:45 阅读更多 →
从 Qwen-2.5 到 Qwen-4:企业级后端集成架构的代际跨越与兼容性重构

从 Qwen-2.5 到 Qwen-4:企业级后端集成架构的代际跨越与兼容性重构

从 Qwen-2.5 到 Qwen-4:企业级后端集成架构的代际跨越与兼容性重构上周处理一个遗留的订单服务时,我们遇到了严重的上下文截断导致的逻辑错误。虽然通过增加重试机制勉强稳住,但那种“把大模型当黑盒调”的粗糙感让我意识到,随着通…

2026/7/24 0:47:45 阅读更多 →

最新新闻

LangChain Runnable 完整深度解读

LangChain Runnable 完整深度解读

LangChain Runnable 完整深度解读适配:LangChain 0.1.x/ 0.2.x 新版体系,LCEL(LangChain Expression Language)的底层基石 前置认知:所有你写的 prompt | llm | parser | retriever,每一环都是 Runnable一、…

2026/7/24 0:58:46 阅读更多 →
2026年实战指南:图片格式图纸识别技术在质量检验计划中的应用

2026年实战指南:图片格式图纸识别技术在质量检验计划中的应用

2026 年,在制造业数字化转型步入深水区的背景下,图片格式图纸识别(image format drawing recognition)已成为质量管理部门提升效率的关键技术。尽管 3D MBD(基于模型的定义)在高端制造领域普及,…

2026/7/24 0:58:46 阅读更多 →
在天津挑选专业标书制作机构,这些实用判断技巧很值得大家参考

在天津挑选专业标书制作机构,这些实用判断技巧很值得大家参考

对于天津不少工程服务商、政企供应商、中小微企业经营者来说,投标过程里最可惜的事,莫过于前期攒资质、跑对接、做测算花了几个月功夫,最后因为标书制作的疏漏,要么直接被废标,要么差两三分与项目失之交臂。来自天津公…

2026/7/24 0:54:46 阅读更多 →
400电话多场景架构适配与企业选型实战:从热线接待、中转分流到风控合规落地

400电话多场景架构适配与企业选型实战:从热线接待、中转分流到风控合规落地

标签:#400电话 #企业热线 #语音中继 #呼叫路由 #客服架构 #通信场景化落地阅读对象:后端开发、通信架构师、IT运维、系统集成、企业客服项目交付人员摘要:大部分企业对400电话的认知仅停留在“品牌热线”层面,忽略了其路由架构、并…

2026/7/24 0:53:46 阅读更多 →
面试官:大模型怎么决定 长期记忆是否需要召回?

面试官:大模型怎么决定 长期记忆是否需要召回?

先说结论: 严格来说,并不是大模型单独决定是否召回长期记忆,而是由 Agent Runtime、记忆管理器和大模型共同完成决策。 一、面试时可以这样回答 在一个完整的 AI Agent 系统中,长期记忆是否需要召回,一般不是简单地每…

2026/7/24 0:52:46 阅读更多 →
ADAS1021KCBZ-RL,集成脉冲 / 阻抗检测的 5 通道低电位采集前端

ADAS1021KCBZ-RL,集成脉冲 / 阻抗检测的 5 通道低电位采集前端

型号介绍ADAS1021KCBZ-RL 是一款高度集成的 5 通道模拟前端,它具备直流导联脱落检测与交流电极接触质量检测两套电路。直流检测覆盖全部 ECG 通道与 RLD 参考电极,检测激励电流、输出极性、脱落判定阈值全部可编程;交流阻抗检测用于评估电极与…

2026/7/24 0:51:45 阅读更多 →

日新闻

用Highcharts 创建可拖拽三维散点立方体3D图表

用Highcharts 创建可拖拽三维散点立方体3D图表

该案例基于Highcharts scatter3d 三维散点图实现空间立方体散点可视化,核心特色:三维 X/Y/Z 三轴空间,所有散点分布在 0~10 立方体空间内;散点使用径向渐变实现立体 3D 圆球质感;支持鼠标 / 触屏拖拽画布,…

2026/7/24 0:00:29 阅读更多 →
AppCertDlls:进程创建路径上的 DLL 入口

AppCertDlls:进程创建路径上的 DLL 入口

AppCertDlls:进程创建路径上的 DLL 入口 AppCertDlls 位于 HKLM\System\CurrentControlSet\Control\Session Manager\AppCertDlls。本文的程序功能是只读列出这个键在 64 位和 32 位注册表视图中的全部值,并显示每条值的来源、名称、类型和可安全显示的数…

2026/7/24 0:00:29 阅读更多 →
我的编程之路:第一篇博客

我的编程之路:第一篇博客

大家好,我是一名编程初学者,同时这也是我编程学习之路上的第一篇博客。在这里,我想要向大家介绍我的一些想法和规划。a.自我介绍我是一个刚刚接触编程的新手,目前在学习c语言,我对编程世界充满了强烈的好奇。当然&…

2026/7/24 0:00:29 阅读更多 →

周新闻

Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/22 8:58:19 阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/22 19:43:43 阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/23 17:49:47 阅读更多 →

月新闻