发布时间:2026/7/24 0:48:14
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 篇由浅入深持续更新中。有疑问或想深挖的源码点评论区告诉我下篇见。

相关新闻

2026/7/24 0:48:14

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

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

2026/7/24 0:43:13

C语言基础学习——二维数组

二维数组用于解决类似表格的数据,几行几列int[6] group[5]; //定义了一个 包含有5个int[6]类型的 一维数组数组也是一种数据类型---int[6] //数组长度6C语言二维数组的定义语法:类型说明符 数组名[常量表达式][常量表达式];1 2 3 …

2026/7/24 2:33:18

YOLO26与ACmix注意力机制融合优化目标检测

1. YOLO26与注意力机制融合的背景与价值目标检测领域近年来最显著的突破之一,就是注意力机制与卷积神经网络的深度融合。作为YOLO系列的最新迭代,YOLO26在保持实时检测优势的同时,通过引入ACmix这类混合注意力模块,实现了特征提取…

2026/7/24 2:33:18

5.10华为OD机试真题 新系统 - 美观的灯笼 (JavaPyCC++JsGo)

美观的灯笼 2026 华为OD机试真题 5月10日华为OD上机新系统考试真题 100 分题型 点击查看华为 OD 机试真题完整目录:2026最新华为OD机试新系统卷 双机位C卷 真题题库目录|全覆盖题库 逐点算法考点详解 题目描述 春节将至,工人要在古镇老街…

2026/7/24 2:33:18

LLama-Factory多模态大模型LoRA微调实战指南

1. 项目背景与核心价值在多模态大模型技术快速发展的当下,如何高效地针对特定视觉任务进行模型适配成为关键挑战。LLama-Factory作为开源训练框架,通过模块化设计解决了传统微调过程中的三大痛点:首先是降低了多模态模型微调的技术门槛&#…

2026/7/24 2:33:18

UART高级协议实战:LIN、RS-485、DALI与硬件流控深度解析

1. UART高级协议支持:从基础到实战的深度解析在嵌入式开发领域,UART(通用异步收发传输器)就像一位沉默寡言但极其可靠的老朋友。几乎所有微控制器都标配这个接口,用来和传感器、蓝牙模块、GPS模组或者另一块MCU“说说话…

2026/7/24 2:28:18

AI如何革新论文数据分析:NAS-RL与MARL技术解析

1. 项目概述:当论文写作遇上AI数据分析在学术写作的战场上,数据分析往往是最耗费精力的环节。传统的数据处理流程需要研究者手动清洗数据、选择算法、调试参数、可视化结果,这个过程可能占据整个研究周期的60%以上时间。而"书匠策AI&quo…

2026/7/23 12:54:51

Unity与Python本地通信:基于Flask的跨语言数据交换实战

1. 项目概述:为什么我们需要一个本地通信服务器?在游戏开发、数字孪生、仿真训练等众多领域,Unity作为强大的实时3D内容创作平台,其核心逻辑通常由C#驱动。然而,当我们需要进行复杂的数据分析、机器学习推理、科学计算…

2026/7/24 0:03:10

不同品牌斜齿行星减速机如何替换?以PX与PAG系列为例

不同品牌斜齿行星减速机如何替换?以 PX 与 PAG 系列为例 一、系列对应不等于型号直接互换 PX 与 PAG 都属于斜齿、方法兰、输出轴式精密行星减速机,结构形式和应用方向具有对应关系。 原设备使用PX系列时,可以优先从PAG系列中寻找替换型号。但…

2026/7/24 0:03:10

jdk8 把list 扁平化成String 多个以逗号分隔

在 JDK 8 中&#xff0c;将 List 扁平化为以逗号分隔的 String&#xff0c;有几种非常简洁且高效的方法。&#x1f680; 推荐方案&#xff1a;使用 Collectors.joining()这是最标准的 Java 8 写法&#xff0c;适用于 List<String>。javaimport java.util.stream.Collecto…

2026/7/24 0:03:10

java 两个 long id 怎么合并成一个long id 并且不重复

“把两个 Long ID 合并成一个唯一的 Long ID&#xff0c;且保证不重复”这个需求&#xff0c;在 Java 里直接做数学上的“完美合并”是不可能的。因为两个 Long&#xff08;各 64 位&#xff09;要合并成一个 Long&#xff08;64 位&#xff09;&#xff0c;在信息论上是有损压…

2026/7/23 23:42:43

3个高效策略:快速掌握Axure中文界面配置

3个高效策略&#xff1a;快速掌握Axure中文界面配置 【免费下载链接】axure-cn Chinese language file for Axure RP. Axure RP 简体中文语言包。支持 Axure 11、10、9。不定期更新。 项目地址: https://gitcode.com/gh_mirrors/ax/axure-cn 还在为Axure RP的英文界面感…