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
注解。