当前位置: 首页 > news >正文

Spring 容器注入时查找 Bean 的完整规则

Spring 容器注入时查找 Bean 的完整规则

彻底搞懂 Spring IoC 在运行时到底“先找谁、再找谁、如何决策”,一文掌握源码级细节。


一、为什么要谈“查找规则”?

在 Spring 应用中,我们最常见的代码是:

@Autowired
private OrderService orderService;

容器启动后,Spring 必须回答两个问题:

  1. 有哪些候选 Bean?
  2. 最终注入哪一个?

这两个问题的答案,就是 Spring 容器注入时查找 Bean 的完整规则


二、整体流程(源码视角)

AbstractBeanFactory#doGetBean└── DefaultListableBeanFactory#resolveDependency├── 1️⃣ 按类型找候选   (findAutowireCandidates)├── 2️⃣ 过滤歧义       (QualifierAnnotationAutowireCandidateResolver)├── 3️⃣ 确定唯一       (determineAutowireCandidate)└── 4️⃣ 创建或返回     (getBean → createBean)

三、四步查找规则详解

① 按类型找候选(findAutowireCandidates)

  • 输入:接口/类 Class<?> requiredType
  • 输出Map<String, Object> —— beanName → Bean 实例
  • 规则
    • 递归 所有父容器(父子上下文场景)
    • 包含 FactoryBean#getObjectType 返回的类型
    • 过滤 抽象、非单例、非自动装配候选 (isAutowireCandidate)

② 过滤歧义(QualifierAnnotationAutowireCandidateResolver)

  • @Qualifier 精确匹配
  • @Primary 标记首选
  • 自定义限定符注解(元注解 @Qualifier
  • 变量名与 beanName 匹配

③ 确定唯一(determineAutowireCandidate)

候选数决策路径结果
0NoSuchBeanDefinitionException注入失败
1直接返回唯一 Bean成功
>1继续 ② 规则,直到只剩 1 个成功
仍 >1NoUniqueBeanDefinitionException注入失败

④ 创建或返回(getBean)

  • 单例已存在 → 直接返回
  • 单例不存在 → 走 完整生命周期(实例化 → 依赖注入 → 初始化 → 暴露)

四、候选来源总览

来源如何注册默认 beanName
@Component 扫描类路径扫描首字母小写类名
@Bean 方法@Configuration 解析方法名
XML <bean>BeanDefinitionReaderid 或类名
spring.factoriesImportSelector全限定类名
手动注册BeanDefinitionRegistry显式指定

五、歧义消除的 4 种官方姿势

方式示例优先级
@Qualifier@Qualifier("stripe")最高
变量名匹配PaymentService stripe;次高
@Primary@Primary @Service兜底
List/MapList<PaymentService>全部注入

六、一张脑图速记

注入点 @Autowired↓
resolveDependency(requiredType)├─ 1️⃣ findAutowireCandidates()│    ├─ 扫描所有 BeanDefinition│    ├─ FactoryBean 代理类型│    └─ 过滤非候选├─ 2️⃣ checkQualifiers()│    ├─ @Qualifier│    ├─ @Primary│    └─ 变量名├─ 3️⃣ determineAutowireCandidate()│    ├─ 0 → NoSuch│    ├─ 1 → OK│    └─ >1 → NoUnique└─ 4️⃣ getBean()├─ 已存在单例 → 直接返回└─ 不存在 → 创建

七、一句话总结

Spring 容器注入时查找 Bean 的完整规则 就是:
“先按类型找出所有候选,再用 @Qualifier/@Primary/变量名 逐级过滤,最终只剩一个 Bean 才注入;否则抛异常。”
记住这 4 步,任何注入失败都能 30 秒内定位。

http://www.dtcms.com/a/301377.html

相关文章:

  • Flutter中 Provider 的基础用法超详细讲解(二)之ChangeNotifierProvider
  • 力扣热题100----------53最大子数组和
  • 咨询进阶——解读40页公司战略解码方法【附全文阅读】
  • sed命令
  • 通信名词解释:I2C、USART、SPI、RS232、RS485、CAN、TCP/IP、SOCKET、modbus
  • 【通识】设计模式
  • catkin_make生成的编译文件夹目录结构说明
  • uart通信
  • python---类型转换
  • Milvus 实战全流程
  • Deja Vu: 利用上下文稀疏性提升大语言模型推理效率
  • Spring 解析 XML 配置文件的过程(从读取 XML 到生成 BeanDefinition)
  • 扩展组件(uni-ui)之uni-group
  • 「iOS」————消息传递和消息转发
  • 26.删除有序数组中的重复项
  • MyBatis-Plus高效开发实战
  • 内存管理和垃圾收集-02: 操作系统如何管理内存?
  • Linux驱动开发笔记(五)——设备树(中)——节点的标准属性
  • 益莱储:明智地投资测试仪器
  • S7-1500 与 S7-1200 存储区域保持性设置特点详解
  • 电子板原理功能区解析与PlantUML图示
  • 3,Windows11安装docker保姆级教程
  • 轻量化多模态文档处理利器SmolDocling:技术原理与场景落地引言:文档智能处理的范式革命
  • 数据结构基础内容(第六篇:二叉搜索与平衡二叉树)
  • MySQL锁机制与MVCC原理剖析
  • 直播带货工具About v1.5.10 免费版
  • GEO优化实战:如何在DeepSeek、豆包等AI平台抢占推荐位?
  • MOE架构详解:原理、应用与PyTorch实现
  • 计算圆周率(π)代码实现【c++】
  • Java中排序规则详解