Spring Boot @Qualifier
最后修改时间:2023年7月20日
Spring Boot @Qualifier 教程展示了如何使用 @Qualifier 区分相同类型的Bean。它也可以用于注释其他自定义注解,然后这些注解可以用作限定符。
Spring 是一个流行的 Java 应用框架,而 Spring Boot 是 Spring 的一个演进,它有助于以最小的努力创建独立的、生产级的基于 Spring 的应用程序。
以下三个应用程序是命令行 Spring Boot 应用程序。
区分 Person Bean
在我们的应用程序中,我们有两个 Person 类型的 Bean:Student 和 Manager。我们使用 @Qualifier 注解来区分它们。
build.gradle
...
src
├───main
│ ├───java
│ │ └───com
│ │ └───zetcode
│ │ │ Application.java
│ │ │ MyRunner.java
│ │ └───model
│ │ Manager.java
│ │ Person.java
│ │ Student.java
│ └───resources
└───test
└───java
这是 Spring Boot 应用程序的项目结构。
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 文件。
package com.zetcode.model;
public interface Person {
String info();
}
我们有一个定义 Person 类型的接口。
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。
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") 注解进行标识。
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 字段中。
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.gradle、Person.java、Application.java、MyRunner.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
这是项目结构。
package com.zetcode.model;
public class Manager implements Person {
@Override
public String info() {
return "Manager";
}
}
注解从 Manager 类中删除。
package com.zetcode.model;
public class Student implements Person {
@Override
public String info() {
return "Student";
}
}
同样,Student 类也没有注解。
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 之外的所有文件,该文件在第一个应用程序中列出。
package com.zetcode.model;
public interface Person {
String info();
}
这是 Person 类型。
package com.zetcode.model;
import org.springframework.stereotype.Component;
@Component
public class Manager implements Person {
@Override
public String info() {
return "Manager";
}
}
Manager 类使用 @Component 注解进行修饰;它将由 Spring 自动检测。
package com.zetcode.model;
import org.springframework.stereotype.Component;
@Component
public class Student implements Person {
@Override
public String info() {
return "Student";
}
}
这同样适用于 Student。
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 关键字用于声明新的注解类型。
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。
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。
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 注解。