1. 概述

在 Spring 框架中,**@Qualifier 注解是一个非常实用的工具,它能帮助我们在多个相同类型的 Bean 中,明确指定要注入哪一个 Bean**。

本文将带你了解:

@Autowired 在多 Bean 场景下的局限性
@Qualifier 是如何解决这种歧义的
@Qualifier@Primary 的区别
✅ 与“按名称自动装配”的对比

如果你在实际开发中遇到过“多个 Bean 导致注入失败”的问题,那这篇文章一定能帮你踩坑避雷⚡


2. 为什么需要歧义消除?

Spring 默认是按类型自动装配(Autowire by Type)的,也就是说,只要你写上 @Autowired,Spring 会尝试根据变量类型自动找到合适的 Bean。

但问题来了:

✅ 如果有多个相同类型的 Bean,Spring 就不知道该选哪一个了!

这时候,Spring 会抛出一个异常:
NoUniqueBeanDefinitionException,意思是:Bean 类型不唯一,无法自动装配

来看一个例子:

@Component("fooFormatter")
public class FooFormatter implements Formatter {
    public String format() {
        return "foo";
    }
}

@Component("barFormatter")
public class BarFormatter implements Formatter {
    public String format() {
        return "bar";
    }
}

@Component
public class FooService {
     
    @Autowired
    private Formatter formatter;
}

上面这段代码中,FooService 想注入一个 Formatter 类型的 Bean,但 Spring 发现有两个候选者:fooFormatterbarFormatter,于是直接报错。


3. 使用 @Qualifier 解决歧义

3.1 基本用法

@Qualifier 的作用就是:告诉 Spring 我要哪个 Bean

我们可以这样修改上面的代码:

@Component
public class FooService {
     
    @Autowired
    @Qualifier("fooFormatter")
    private Formatter formatter;
}

加上 @Qualifier("fooFormatter") 后,Spring 就知道:哦,用户要的是名字为 fooFormatter 的那个 Bean。

3.2 注解可以加在类上

你也可以把 @Qualifier 加在实现类上,而不是 @Component 注解里,效果是一样的:

@Component
@Qualifier("fooFormatter")
public class FooFormatter implements Formatter {
    // ...
}

@Component
@Qualifier("barFormatter")
public class BarFormatter implements Formatter {
    // ...
}

这样写的好处是:Bean 名称与类定义更紧密耦合,方便后期维护。


4. @Qualifier vs @Primary

除了 @Qualifier,还有一个常用的注解叫 @Primary

4.1 @Primary 的作用

当你有多个相同类型的 Bean 时,给其中一个加上 @Primary,Spring 就会优先使用这个 Bean。

举个例子:

@Configuration
public class Config {
 
    @Bean
    public Employee johnEmployee() {
        return new Employee("John");
    }
 
    @Bean
    @Primary
    public Employee tonyEmployee() {
        return new Employee("Tony");
    }
}

此时,Spring 默认会注入 tonyEmployee

4.2 优先级关系

⚠️ 如果 @Qualifier@Primary 同时存在,@Qualifier 优先级更高

也就是说:

  • @Primary 定义的是“默认值”
  • @Qualifier 则是“精确指定”

4.3 示例对比

@Component
@Primary
public class FooFormatter implements Formatter {
    // ...
}

@Component
public class BarFormatter implements Formatter {
    // ...
}

在这种情况下,Spring 默认会注入 FooFormatter,除非你用 @Qualifier("barFormatter") 明确指定。


5. @Qualifier vs 按名称注入

Spring 还有一种机制叫“按字段名自动装配”,也就是:

如果字段名和 Bean 名一致,Spring 会自动匹配。

来看例子:

public class FooService {
     
    @Autowired
    private Formatter fooFormatter;
}

这里字段名是 fooFormatter,而我们之前定义了一个 @Component("fooFormatter"),Spring 会自动匹配,不需要加 @Qualifier

这种方式虽然简单,但不够明确,容易引起歧义,尤其是字段名和 Bean 名不一致时。


6. 总结

特性 @Qualifier @Primary 按名称注入
是否明确指定 Bean ✅ 是 ❌ 否 ❌ 否
是否可控制注入哪个 Bean ✅ 是 ✅ 是(默认) ❌ 否
是否需要额外配置 ✅ 是 ✅ 是 ❌ 否
是否适用于复杂场景 ✅ 是 ⚠️ 有限 ⚠️ 有限

✅ 最佳实践建议:

  • 多个 Bean 时,**优先使用 @Qualifier**,避免歧义
  • @Primary 适合定义“默认 Bean”,比如日志、配置等
  • 按名称注入简单但不推荐用于复杂项目,容易出错

附:完整代码示例

所有代码示例都可以在 GitHub 上找到:
👉 Spring DI 示例代码

如果你觉得这篇文章有帮助,欢迎点赞或集合,后续将持续更新更多 Spring 高级用法实战解析。


原始标题:Spring @Qualifier Annotation