ZetCode

Spring Boot @Qualifier

最后修改时间:2023年7月20日

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

Spring 是一个流行的 Java 应用框架,而 Spring Boot 是 Spring 的一个演进,它有助于以最小的努力创建独立的、生产级的基于 Spring 的应用程序。

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

区分 Person Bean

在我们的应用程序中,我们有两个 Person 类型的 Bean:StudentManager。我们使用 @Qualifier 注解来区分它们。

build.gradle
...
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           │   Application.java
│   │           │   MyRunner.java
│   │           └───model
│   │                   Manager.java
│   │                   Person.java
│   │                   Student.java
│   └───resources
└───test
    └───java

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

build.gradle
plugins {
    id 'org.springframework.boot' version '3.1.1'
    id 'io.spring.dependency-management' version '1.1.0'
    id 'java'
}

group = 'com.zetcode'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter'
}

这是 Gradle 构建文件。spring-boot-starter 是核心启动器,包括自动配置支持、日志记录和 YAML。应用程序被打包成一个 JAR 文件。

com/zetcode/model/Person.java
package com.zetcode.model;

public interface Person {

    String info();
}

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

com/zetcode/model/Student.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
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
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 接口指示 Bean 应该在包含在 SpringApplication 中时运行。它可用于在 Spring Boot 中创建命令行应用程序。

@Component
public class MyRunner implements CommandLineRunner {

CommandLineRunner 也是一个 Spring Bean,并使用 @Component 注解进行修饰;它由 Spring 自动检测。

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

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

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

同样,我们将 Manager Bean 注入到 p2 字段中。

com/zetcode/Application.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。 build.gradlePerson.javaApplication.javaMyRunner.java 保持不变。

build.gradle
...
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
package com.zetcode.model;

public class Manager implements Person {

    @Override
    public String info() {

        return "Manager";
    }
}

注解从 Manager 类中删除。

com/zetcode/model/Student.java
package com.zetcode.model;

public class Student implements Person {

    @Override
    public String info() {

        return "Student";
    }
}

同样,Student 类也没有注解。

com/zetcode/conf/PersonFactory.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();
    }
}

在上一个例子中,Bean 由 Spring 自动检测。在这里,PersonFactory 借助 @Bean 注解创建了两个 Bean。

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

    return new Student();
}

@Bean 注解标记定义 Bean 的方法。 @Qualifier("student") 告诉要创建哪个 Person 的实现。

创建自定义 @Qualifier 注解

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

build.gradle
...
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

这是项目结构;我们列出除 build.gradle 之外的所有文件,该文件在第一个应用程序中列出。

com/zetcode/model/Person.java
package com.zetcode.model;

public interface Person {

    String info();
}

这是 Person 类型。

com/zetcode/model/Manager.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
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
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 限定符。

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

@Targer 注解告诉注解可以应用于何处。在我们的例子中,它可以应用于字段、方法和参数。

@Retention(RetentionPolicy.RUNTIME)

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

public @interface PersonQ {

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

com/zetcode/conf/PersonFactory.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
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
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 应用程序。

在本文中,我们使用了 @Qualifier 注解。

作者

我的名字是 Jan Bodnar,我是一位充满激情的程序员,拥有丰富的编程经验。自 2007 年以来,我一直在撰写编程文章。到目前为止,我撰写了 1,400 多篇文章和 8 本电子书。我拥有超过十年的编程教学经验。

列出 所有 Spring Boot 教程