@Autowired 和 @Qualifier 详解

发布时间:2026/9/30 20:16:30
@Autowired 和 @Qualifier 详解 Autowired 和 Qualifier 详解一、Autowired 是什么Autowired是 Spring 提供的依赖注入注解默认按类型byType自动装配。它告诉 Spring 容器这个字段、构造方法或 Setter 方法需要一个依赖请从容器中找一个匹配的 Bean 注入进来。ServicepublicclassUserService{AutowiredprivateUserDaouserDao;}Spring 在创建UserService时扫描到Autowired标记的字段从容器中查找UserDao类型的 Bean通过反射赋值给该字段。二、Autowired 的三种注入位置构造器注入ServicepublicclassUserService{privatefinalUserDaouserDao;publicUserService(UserDaouserDao){this.userDaouserDao;}}如果类只有一个构造方法Autowired可以省略。Spring 4.3 之后默认使用唯一的构造方法进行注入。多个构造方法时必须显式标注ServicepublicclassUserService{privatefinalUserDaouserDao;privatefinalEmailServiceemailService;AutowiredpublicUserService(UserDaouserDao,EmailServiceemailService){this.userDaouserDao;this.emailServiceemailService;}publicUserService(UserDaouserDao){this(userDao,null);}}字段注入ServicepublicclassUserService{AutowiredprivateUserDaouserDao;}代码最简洁但不利于单元测试也无法使用final修饰字段。Setter 注入ServicepublicclassUserService{privateUserDaouserDao;AutowiredpublicvoidsetUserDao(UserDaouserDao){this.userDaouserDao;}}适合依赖可选的场景可以在对象创建后动态替换依赖。三、Autowired 的匹配规则第一步按类型查找Spring 首先在容器中查找与目标类型匹配的 Bean。如果只找到一个直接注入。第二步按名称匹配如果找到多个同类型的 BeanSpring 会用字段名或参数名去匹配 Bean 的名称。ServicepublicclassOrderService{AutowiredprivatePaymentServicealiPayService;// 字段名 aliPayService}如果容器中有aliPayService和wechatPayService两个PaymentService类型的 Bean字段名aliPayService会匹配到对应的 Bean。第三步Primary 优先如果按名称也没有匹配到Spring 会查找标记了Primary的 Bean。ServicePrimarypublicclassAliPayServiceimplementsPaymentService{}第四步Qualifier 指定如果以上都无法确定使用Qualifier显式指定 Bean 名称。AutowiredQualifier(aliPayService)privatePaymentServicepaymentService;匹配流程图按类型查找 ├── 找到一个 → 注入 ├── 找到多个 │ ├── 按字段名/参数名匹配 Bean 名称 │ │ ├── 匹配成功 → 注入 │ │ └── 匹配失败 │ │ ├── 有 Primary → 注入 Primary 标记的 Bean │ │ └── 有 Qualifier → 按 Qualifier 指定的名称注入 │ │ └── 都没有 → 抛 NoUniqueBeanDefinitionException └── 没找到 ├── required true默认→ 抛 NoSuchBeanDefinitionException └── required false → 注入 null四、Autowired 的 required 属性Autowired(requiredfalse)privateUserDaouserDao;默认required true找不到匹配的 Bean 时启动报错。设置为false时找不到则注入null不报错。required false适合可选依赖的场景但要注意使用前判空。五、Qualifier 的作用Qualifier配合Autowired使用在同类型多 Bean 时按名称指定具体注入哪一个。ServicepublicclassOrderService{AutowiredQualifier(aliPayService)privatePaymentServicepaymentService;}Qualifier的值就是目标 Bean 的名称。Bean 名称默认是类名首字母小写也可以显式指定Service(aliPayService)publicclassAliPayServiceimplementsPaymentService{}六、Qualifier 的使用位置字段上AutowiredQualifier(aliPayService)privatePaymentServicepaymentService;构造器参数上ServicepublicclassOrderService{privatefinalPaymentServicepaymentService;publicOrderService(Qualifier(aliPayService)PaymentServicepaymentService){this.paymentServicepaymentService;}}Setter 方法参数上AutowiredpublicvoidsetPaymentService(Qualifier(aliPayService)PaymentServicepaymentService){this.paymentServicepaymentService;}方法参数上Bean 方法BeanpublicOrderServiceorderService(Qualifier(aliPayService)PaymentServicepaymentService){returnnewOrderService(paymentService);}七、Qualifier 与 Primary 的优先级当两者同时存在时Qualifier的优先级更高。ServicePrimarypublicclassAliPayServiceimplementsPaymentService{}ServicepublicclassWechatPayServiceimplementsPaymentService{}ServicepublicclassOrderService{AutowiredQualifier(wechatPayService)// 显式指定覆盖 PrimaryprivatePaymentServicepaymentService;// 注入 WechatPayService}Qualifier是精确指定Primary是默认首选。精确指定优先于默认。八、Qualifier 用于集合注入当注入集合类型时Qualifier可以筛选特定名称的 BeanAutowiredQualifier(aliPayService)privateListPaymentServicepaymentServices;但这只对按名称匹配的 Bean 有效。更常见的做法是给 Bean 加上自定义注解然后用Qualifier筛选。九、自定义 Qualifier 注解Spring 支持通过自定义注解扩展Qualifier的能力Target({ElementType.FIELD,ElementType.PARAMETER})Retention(RetentionPolicy.RUNTIME)QualifierpublicinterfaceAliPay{}使用ServiceAliPaypublicclassAliPayServiceimplementsPaymentService{}ServicepublicclassOrderService{AutowiredAliPayprivatePaymentServicepaymentService;}这种方式比字符串名称更类型安全重构时 IDE 能自动更新。十、底层原理处理类Autowired和Qualifier由AutowiredAnnotationBeanPostProcessor处理。它实现了BeanPostProcessor接口在 Bean 实例化后、初始化前介入。处理时机实例化 → 属性填充populateBean └── AutowiredAnnotationBeanPostProcessor.postProcessProperties() ├── 扫描字段和方法上的 Autowired ├── 解析依赖类型 ├── DefaultListableBeanFactory.resolveDependency() │ ├── 按类型查找 │ ├── 按 Qualifier 筛选 │ ├── 按 Primary 选择 │ └── 按名称匹配 └── 反射注入核心方法// AutowiredAnnotationBeanPostProcessorpublicPropertyValuespostProcessProperties(PropertyValuespvs,Objectbean,StringbeanName){// 1. 查找注入元数据InjectionMetadatametadatafindAutowiringMetadata(beanName,bean.getClass(),pvs);// 2. 执行注入metadata.inject(bean,beanName,pvs);returnpvs;}// DefaultListableBeanFactorypublicObjectresolveDependency(DependencyDescriptordescriptor,StringrequestingBeanName,SetStringautowiredBeanNames,TypeConvertertypeConverter){// 1. 如果字段类型是 Optional、ObjectProvider 等特殊处理// 2. 查找匹配的 BeanObjectresultdoResolveDependency(descriptor,requestingBeanName,autowiredBeanNames,typeConverter);returnresult;}doResolveDependency()中会检查Qualifier注解的值如果有就按名称匹配如果没有走类型匹配逻辑。十一、Autowired vs Resource对比维度AutowiredResource来源SpringJSR-250JDK默认匹配按类型按名称指定名称Qualifiername属性required 属性支持不支持构造器注入支持不支持处理类AutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor// Autowired QualifierAutowiredQualifier(userDaoImpl)privateUserDaouserDao;// ResourceResource(nameuserDaoImpl)privateUserDaouserDao;两者功能等价Resource写起来更简洁但Autowired功能更丰富支持构造器注入、required false。十二、常见问题1. NoUniqueBeanDefinitionExceptionNoUniqueBeanDefinitionException: expected single matching bean but found 2容器中有多个同类型 Bean且无法按名称匹配。解决方案用Qualifier指定名称用Primary标记首选将字段名改为与目标 Bean 名称一致2. NoSuchBeanDefinitionExceptionNoSuchBeanDefinitionException: No qualifying bean of type UserDao available容器中没有匹配的 Bean。检查目标类是否被 Spring 管理包路径是否在ComponentScan范围内是否设置了required false3. 构造器注入循环依赖构造器注入无法解决循环依赖启动报BeanCurrentlyInCreationException。应通过重构消除循环依赖或改用字段注入。4. Qualifier 值写错Qualifier的值必须与 Bean 名称完全一致大小写敏感。Bean 默认名称是类名首字母小写显式指定时以指定值为准。5. 自定义 Qualifier 注解不生效检查自定义注解是否标注了Qualifier元注解且Retention为RUNTIME。十三、最佳实践优先使用构造器注入。保证依赖不可变、完全就绪便于单元测试。同类型多 Bean 时优先用自定义 Qualifier 注解。比字符串名称更类型安全重构友好。Qualifier 的粒度要细。一个Qualifier只对应一个 Bean不要一个名称对应多个。避免字段注入。不利于测试容易积累过多依赖而不自知。Primary 用于设置合理的默认值。当大多数场景都用某个实现时标记它为Primary特殊情况再用Qualifier指定。Qualifier 与 Primary 配合使用。Primary提供默认Qualifier处理例外。十四、总结维度AutowiredQualifier作用标记需要注入的依赖指定注入的具体 Bean匹配方式先按类型再按名称按名称单独使用可以通常配合 Autowired优先级低于 Qualifier高于 Primary支持位置字段、构造器、Setter、参数字段、构造器参数、Setter 参数、方法参数处理类AutowiredAnnotationBeanPostProcessor同上Autowired负责“需要一个依赖”Qualifier负责“要哪一个”。当容器中只有一个匹配类型的 Bean 时Autowired就能完成注入当有多个时Qualifier用来消除歧义。两者配合使用是 Spring 依赖注入中最常见的组合。理解它们的匹配规则和优先级能帮你快速定位注入异常写出更清晰的依赖关系。f