The Spring @Qualifier Annotation – Spring的@Qualifier注释

最后修改: 2019年 7月 6日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this tutorial, we’ll explore what the @Qualifier annotation can help us with, which problems it solves, and how to use it.

在本教程中,我们将探讨 @Qualifier 注释可以帮助我们,它可以解决哪些问题,以及如何使用它。

We’ll also explain how it’s different from the @Primary annotation, and from autowiring by name.

我们还将解释它与@Primary注解的区别,以及与自动布线的名称的区别。

2. Autowire Need for Disambiguation

2.自动线需要歧义

The @Autowired annotation is a great way of making the need to inject a dependency in Spring explicit. Although it’s useful, there are use cases for which this annotation alone isn’t enough for Spring to understand which bean to inject.

@Autowired注解是使Spring中注入依赖关系的需求明确化的一个好方法。尽管它很有用,但在一些用例中,仅靠这个注解还不足以让Spring理解要注入哪个Bean。

By default, Spring resolves autowired entries by type.

默认情况下,Spring按类型解析自动连接的条目。

If more than one bean of the same type is available in the container, the framework will throw NoUniqueBeanDefinitionException, indicating that more than one bean is available for autowiring.

如果容器中存在多个相同类型的 bean,框架将抛出 NoUniqueBeanDefinitionException表明有多个 bean 可供自动连接。

Let’s imagine a situation in which two possible candidates exist for Spring to inject as bean collaborators in a given instance:

让我们想象一下这样一种情况:在一个给定的实例中,Spring有两个可能的候选者被注入为Bean Collaborators。

@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;
}

If we try to load FooService into our context, the Spring framework will throw a NoUniqueBeanDefinitionException. This is because Spring doesn’t know which bean to inject. To avoid this problem, there are several solutions; the @Qualifier annotation is one of them.

如果我们试图将FooService加载到我们的上下文中,Spring框架会抛出一个NoUniqueBeanDefinitionException。这是因为Spring不知道要注入哪个Bean。为了避免这个问题,有几种解决方案;@Qualifier注解就是其中之一。

3. @Qualifier Annotation

3.@Qualify注释

By using the @Qualifier annotation, we can eliminate the issue of which bean needs to be injected.

通过使用@Qualifier annotation,我们可以消除需要注入哪个Bean的问题

Let’s revisit our previous example to see how we solve the problem by including the @Qualifier annotation to indicate which bean we want to use:

让我们重温一下之前的例子,看看我们是如何通过包含@Qualifier注解来表明我们要使用哪个bean来解决问题的。

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

By including the @Qualifier annotation, together with the name of the specific implementation we want to use, in this example Foo, we can avoid ambiguity when Spring finds multiple beans of the same type.

通过包括@Qualifier 注解,以及我们想要使用的具体实现的名称,在这个例子中是Foo,我们可以避免在Spring发现同一类型的多个Bean时出现歧义。

We need to take into consideration that the qualifier name to be used is the one declared in the @Component annotation.

我们需要考虑到,要使用的限定符名称是在@Component注解中声明的那个。

Note that we could have also used the @Qualifier annotation on the Formatter implementing classes, instead of specifying the names in their @Component annotations, to obtain the same effect:

请注意,我们也可以在@Qualifier实现类上使用Formatter注解,而不是在其@Component注解中指定名称,以获得相同的效果。

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

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

4. @Qualifier vs @Primary

4.@Qualifier@Primary对比

There’s another annotation called @Primary that we can use to decide which bean to inject when ambiguity is present regarding dependency injection.

还有一个注解叫做@Primary,我们可以用它来决定在依赖注入方面存在歧义时要注入哪个bean。

This annotation defines a preference when multiple beans of the same type are present. The bean associated with the @Primary annotation will be used unless otherwise indicated.

这个注解定义了在有多个相同类型的Bean时的偏好。除非另有说明,否则将使用与@Primary注解相关的Bean。

Let’s see an example:

让我们看一个例子。

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

In this example, both methods return the same Employee type. The bean that Spring will inject is the one returned by the method tonyEmployee. This is because it contains the @Primary annotation. This annotation is useful when we want to specify which bean of a certain type should be injected by default.

在这个例子中,两个方法都返回同一个Employee类型。Spring将注入的Bean是由tonyEmployee方法返回的那个。这是因为它包含@Primary注解。当我们想指定某种类型的Bean应该被默认注入时,这个注解很有用

If we require the other bean at some injection point, we would need to specifically indicate it. We can do that via the @Qualifier annotation. For instance, we could specify that we want to use the bean returned by the johnEmployee method by using the @Qualifier annotation.

如果我们在某个注入点上需要另一个Bean,我们需要特别指出它。我们可以通过 @Qualifier 注释来做到这一点。例如,我们可以通过使用@Qualifier注解来指定我们要使用由johnEmployee方法返回的bean。

It’s worth noting that if both the @Qualifier and @Primary annotations are present, then the @Qualifier annotation will have precedence. Basically, @Primary defines a default, while @Qualifier is very specific.

值得注意的是,如果@Qualifier@Primary注解都存在,那么@Qualifier注解将具有优先权。基本上,@Primary定义了一个默认值,而@Qualifier则非常具体。

Let’s look at another way of using the @Primary annotation, this time using the initial example:

让我们看看使用@Primary注解的另一种方式,这次是使用最初的例子。

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

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

In this case, the @Primary annotation is placed in one of the implementing classes, and will disambiguate the scenario.

在这种情况下,@Primary注解被放置在一个实现类中,并将消除这种情况的歧义。

5. @Qualifier vs Autowiring by Name

5.@Qualifier vs Autowiring by Name

Another way to decide between multiple beans when autowiring, is by using the name of the field to inject. This is the default in case there are no other hints for Spring. Let’s see some code based on our initial example:

在自动布线时,决定多个Bean的另一种方法是使用字段的名称来注入。这是在Spring没有其他提示的情况下的默认做法。让我们看看基于我们最初的例子的一些代码。

public class FooService {
     
    @Autowired
    private Formatter fooFormatter;
}

In this case, Spring will determine that the bean to inject is the FooFormatter one, since the field name is matched to the value that we used in the @Component annotation for that bean.

在这种情况下,Spring将确定要注入的Bean是FooFormatter之一,因为字段名与我们在@Component注解中为该Bean使用的值相匹配。

6. Conclusion

6.结论

In this article, we described the scenarios where we need to disambiguate which beans to inject. In particular, we examined the @Qualifier annotation, and compared it with other similar ways of determining which beans need to be used.

在这篇文章中,我们描述了我们需要明确哪些Bean需要注入的场景。特别是,我们研究了@Qualifier 注解,并将其与其他确定需要使用哪些Bean的类似方法进行了比较。

As usual, the complete code for this article is available over on GitHub.

像往常一样,本文的完整代码可以在GitHub上找到