Spring Boot @Qualifier
教程展示了如何使用@Qualifier
来区分相同类型的 bean。 它也可以用于注解其他自定义注解,这些注解随后可以用作限定符。
Spring 是流行的 Java 应用框架,而 Spring Boot 是 Spring 的演进,可帮助您以最少的精力创建独立的,生产级的基于 Spring 的应用。
以下三个应用是命令行 Spring Boot 应用。
@Qualifier
Person
bean
在我们的应用中,我们有两个Person
类型的 bean:Student
和Manager
。 我们使用@Qualifier
注解来区分它们。
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
<?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
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
接口指示当SpringApplication
中包含 bean 时应运行它。 它可以用来在 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。 pom.xml
,Person.java
,Application.java
和MyRunner.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
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();
}
}
在前面的示例中,Spring 会自动检测到这些 bean。 在这里,PersonFactory
借助@Bean
注解创建了两个 bean。
@Bean
@Qualifier("student")
public Person createStudent() {
return new Student();
}
@Bean
注解标记了定义 bean 的方法。 @Qualifier("student")
指示要创建Person
的哪个实现。
创建自定义@Qualifier
注解
为了减少代码,我们可以创建自定义@Qualifier 注解。
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
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 应用。