引子你只写了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 篇由浅入深持续更新中。有疑问或想深挖的源码点评论区告诉我下篇见。
企业数字化 ERP 产品动态
相关推荐
iPhone17护眼钢化膜避坑:悟赫德拆解四大套路 iPhone17护眼钢化膜避坑指南:2026年这四大套路别再信了新买的iPhone 17到手,第一张膜往往踩坑最多。市面上关于“护眼钢化膜”的说法五花八门,蓝光膜、绿光膜、紫光膜,每个都声称自己护眼,但真正用起来不是偏色就是反光… · 2026/9/19 3:31:24
DC-Pi三合一工业控制器:PLC、HMI与边缘AI深度融合实践 1. 项目概述:当工业控制现场不再需要“三台设备堆成一座山”我第一次在客户车间看到宏集DC-Pi样机时,下意识摸了摸PLC柜里那台积灰的HMI触摸屏——它正连着一根冗长的RS485线,另一头插在隔壁的PLC模块上,而旁边还立着一台边缘AI盒… · 2026/9/26 9:10:28
工业Agent实时控制是伪命题,真正用武之地在控制回路外围 做了十几年工业控制,从DCS到PLC再到运动控制器,天天跟现场总线、硬实时任务打交道,这几年眼看着“工业Agent”这个词从概念走向风口,说实话心情挺复杂的。经常有客户跑来问:能不能把大模型接进控制系统,让系… · 2026/9/26 9:10:10
5G载波聚合不生效?A5测量开关配置与排查指南 简介:这份文档面向从事5G网络优化的工程师与运维人员,聚焦载波聚合A5测量事件开关的开启与验证,帮助解决CA终端在占用载波聚合小区时切换延迟、用户感知下降等实际问题。资源包内含1个docx文件,约987KB,以图文与脚本说… · 2026/9/26 9:10:10
昇腾Atlas 300V推理加速卡部署YOLOv5全流程指南 在昇腾生态里折腾了几个月 Atlas 加速卡之后,我最大的感受是:硬件本身并不难搞,难的是把“软件栈”这条路走通。网上关于“Atlas 300V 24G 是不是运算加速卡”的讨论一直不少,最近又有一批做视觉检测的团队开始把 YOLO 往 Atlas 3… · 2026/9/26 9:10:10
数据库课后习题答案别硬背:当测试用例集刷,效率翻倍 简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、… · 2026/9/26 0:00:21
OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 0:00:40
向下兼容与向上兼容:接口设计中的兼容性策略与工程实践 一次版本升级事故,是很多团队绕不过去的坎。线上环境里,服务端明明已经上线了新版接口,老的移动端还在照着旧文档传参数。请求一到网关,校验直接拒绝,用户操作失败,客服群炸了锅,开发群里开始互… · 2026/9/26 0:00:46