# Spring Boot `@Qualifier`教程

> 原文： [http://zetcode.com/springboot/qualifier/](http://zetcode.com/springboot/qualifier/)

Spring Boot `@Qualifier`教程展示了如何使用`@Qualifier`来区分相同类型的 bean。 它也可以用于注解其他自定义注解，这些注解随后可以用作限定符。

Spring 是流行的 Java 应用框架，而 Spring Boot 是 Spring 的演进，可帮助您以最少的精力创建独立的，生产级的基于 Spring 的应用。

以下三个应用是命令行 Spring Boot 应用。

## `@Qualifier` `Person` bean

在我们的应用中，我们有两个`Person`类型的 bean：`Student`和`Manager`。 我们使用`@Qualifier`注解来区分它们。

```java
pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           │   Application.java
│   │           │   MyRunner.java
│   │           └───model
│   │                   Manager.java
│   │                   Person.java
│   │                   Student.java
│   └───resources
└───test
    └───java

```

这是 Spring Boot 应用的项目结构。

`pom.xml`

```java
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>springbootqualifier</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
    </parent>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

```

这是 Maven 构建文件。 `spring-boot-starter`是包括自动配置支持，日志记录和 YAML 在内的核心启动器。 该应用打包到一个 JAR 文件中。

`com/zetcode/model/Person.java`

```java
package com.zetcode.model;

public interface Person {

    String info();
}

```

我们有一个定义`Person`类型的接口。

`com/zetcode/model/Student.java`

```java
package com.zetcode.model;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
@Qualifier("student")
public class Student implements Person {

    @Override
    public String info() {

        return "Student";
    }
}

```

`Student`继承自`Person`。 `@Component`是基本的 Spring 注解，它允许 Spring 容器检测`Student`。 `@Qualifier("student")`用`"student"`字符串唯一标识此 bean。

`com/zetcode/model/Manager.java`

```java
package com.zetcode.model;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
@Qualifier("manager")
public class Manager implements Person {

    @Override
    public String info() {
        return "Manager";
    }
}

```

我们还有另一个名为`Manager`的 bean。 该 bean 也用`@Qualifier("manager")`注解标识。

`com/zetcode/MyRunner.java`

```java
package com.zetcode;

import com.zetcode.model.Person;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class MyRunner implements CommandLineRunner {

    private static final Logger logger = LoggerFactory.getLogger(MyRunner.class);

    @Autowired
    @Qualifier("student")
    private Person p1;

    @Autowired
    @Qualifier("manager")
    private Person p2;

    @Override
    public void run(String... args) throws Exception {

        logger.info("{}", p1.info());
        logger.info("{}", p2.info());
    }
}

```

`CommandLineRunner`接口指示当`SpringApplication`中包含 bean 时应运行它。 它可以用来在 Spring Boot 中创建命令行应用。

```java
@Component
public class MyRunner implements CommandLineRunner {

```

`CommandLineRunner`也是一个 Spring bean，并用`@Component`注解装饰。 它由 Spring 自动检测。

```java
@Autowired
@Qualifier("student")
private Person p1;

```

我们将`Person` bean 注入`p1`字段。 `@Qualifier("student")`指定它是一个`Student` bean。

```java
@Autowired
@Qualifier("manager")
private Person p2;

```

同样，我们将`Manager` bean 注入`p2`字段。

`com/zetcode/Application.java`

```java
package com.zetcode;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

```

`Application`设置 Spring Boot 应用。 `@SpringBootApplication`注解启用自动配置和组件扫描。

## 使用工厂创建 bean

在第二个应用中，我们使用工厂类来生成 bean。 `pom.xml`，`Person.java`，`Application.java`和`MyRunner.java`保持不变。

```java
pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           │   Application.java
│   │           │   MyRunner.java
│   │           ├───conf
│   │           │       PersonFactory.java
│   │           └───model
│   │                   Manager.java
│   │                   Person.java
│   │                   Student.java
│   └───resources
└───test
    └───java

```

这是项目结构。

`com/zetcode/model/Manager.java`

```java
package com.zetcode.model;

public class Manager implements Person {

    @Override
    public String info() {

        return "Manager";
    }
}

```

注解已从`Manager`类中删除。

`com/zetcode/model/Student.java`

```java
package com.zetcode.model;

public class Student implements Person {

    @Override
    public String info() {

        return "Student";
    }
}

```

同样，`Student`类没有注解。

`com/zetcode/conf/PersonFactory.java`

```java
package com.zetcode.conf;

import com.zetcode.model.Manager;
import com.zetcode.model.Person;
import com.zetcode.model.Student;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class PersonFactory {

    @Bean
    @Qualifier("student")
    public Person createStudent() {

        return new Student();
    }

    @Bean
    @Qualifier("manager")
    public Person createManager() {

        return new Manager();
    }    
}

```

在前面的示例中，Spring 会自动检测到这些 bean。 在这里，`PersonFactory`借助`@Bean`注解创建了两个 bean。

```java
@Bean
@Qualifier("student")
public Person createStudent() {

    return new Student();
}

```

`@Bean`注解标记了定义 bean 的方法。 `@Qualifier("student")`指示要创建`Person`的哪个实现。

## 创建自定义`@Qualifier`注解

为了减少代码，我们可以创建自定义`@Qualifier`注解。

```java
pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           │   Application.java
│   │           │   MyRunner.java
│   │           ├───conf
│   │           │       PersonFactory.java
│   │           ├───model
│   │           │       Manager.java
│   │           │       Person.java
│   │           │       Student.java
│   │           └───qualifier
│   │                   PersonQ.java
│   └───resources
└───test
    └───java

```

这是项目结构； 我们列出了第一个应用中列出的`pom.xml`以外的所有文件。

`com/zetcode/model/Person.java`

```java
package com.zetcode.model;

public interface Person {

    String info();
}

```

这是`Person`类型。

`com/zetcode/model/Manager.java`

```java
package com.zetcode.model;

import org.springframework.stereotype.Component;

@Component
public class Manager implements Person {

    @Override
    public String info() {

        return "Manager";
    }
}

```

`Manager`类装饰有`@Component`注解； 它将由 Spring 自动检测。

`com/zetcode/model/Student.java`

```java
package com.zetcode.model;

import org.springframework.stereotype.Component;

@Component
public class Student implements Person {

    @Override
    public String info() {

        return "Student";
    }
}

```

`Student`的情况相同。

`com/zetcode/qualifier/PersonQ.java`

```java
package com.zetcode.qualifier;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.annotation.Qualifier;

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface PersonQ {

    String value();
}

```

在这里，我们定义了一个新的`@PersonQ`限定符。

```java
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})

```

`@Targer`注解指出可以在何处应用注解。 在我们的情况下，它可以应用于字段，方法和参数。

```java
@Retention(RetentionPolicy.RUNTIME)

```

`@Retention`注解指定标记的注解的存储方式。 使用`RetentionPolicy.RUNTIME`，标记的注解将由 JVM 保留，因此可以由运行时环境使用。

```java
public @interface PersonQ {

```

`@interface`关键字用于声明新的注解类型。

`com/zetcode/conf/PersonFactory.java`

```java
package com.zetcode.conf;

import com.zetcode.model.Manager;
import com.zetcode.model.Person;
import com.zetcode.model.Student;
import com.zetcode.qualifier.PersonQ;
import org.springframework.context.annotation.Configuration;

@Configuration
public class PersonFactory {

    @PersonQ("student")
    public Person createStudent() {

        return new Student();
    }

    @PersonQ("manager")
    public Person createManager() {

        return new Manager();
    }
}

```

在`PersonFactory`中，我们使用`@PersonQ`识别创建了哪种类型的 bean。

`com/zetcode/MyRunner.java`

```java
package com.zetcode;

import com.zetcode.model.Person;
import com.zetcode.qualifier.PersonQ;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class MyRunner implements CommandLineRunner {

    private static final Logger logger = LoggerFactory.getLogger(MyRunner.class);

    @Autowired
    @PersonQ("student")
    private Person p1;

    @Autowired
    @PersonQ("manager")
    private Person p2;

    @Override
    public void run(String... args) throws Exception {

        logger.info("{}", p1.info());
        logger.info("{}", p2.info());
    }
}

```

在`MyRunner`中，我们注入带有`@Autowired`和`@PersonQ`注解的 bean。

`com/zetcode/Application.java`

```java
package com.zetcode;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

```

在`Application`中，我们设置了 Spring Boot 应用。

您可能也对 [Java 教程](/lang/java/)感兴趣，或列出[所有 Spring Boot 教程](/all/#springboot)。