快手一面:Spring @Qualifier 能解决 Bean 冲突吗?

开发
本文我们分析了 @Qualifier​的工作原理。@Qualifier​ 是 Spring 中用于解决 Bean 冲突的有力工具,尤其在多实现类的场景下。

这篇文章,我们将深度分析一道快手的面试题: Spring 的@Qualifier注解能解决 Bean冲突吗?

一、功能概要

@Qualifier注解是 Spring中用于在依赖注入时明确指定要注入的 Bean 的工具,特别是在容器中存在多个相同类型的 Bean 时。它帮助开发者解决由于 Bean 名称冲突或多重实现导致的歧义问题,从而确保注入正确的 Bean 实例。

比如:当容器中存在多个同类型的 Bean 时,Spring 无法确定应该注入哪一个 Bean,这时 @Qualifier 就派上用场了。它通过指定 Bean 的名称或自定义限定符来告知 Spring 具体应该注入哪个 Bean。

@Qualifier 注解的源码如下图:

通过源码,我们可以看出,@Qualifier 只能用于字段或参数。接下来,我们将从三个角度来分析@Qualifier的使用。

二、使用方法

1. 按 Bean 名称指定

@Qualifier 通常与 @Autowired 一起使用,通过指定 Bean 的名称来选择具体的实现,如下代码示例:

@Autowired
@Qualifier("ServiceImpl2")
private Service Service;
  • 1.
  • 2.
  • 3.

确保 @Qualifier 中的名称与目标 Bean 的名称(默认是类名首字母小写,或者通过 @Component("customName") 指定的名称)相匹配。

2. 在构造函数中使用

对于构造函数注入,也可以使用 @Qualifier,如下代码示例:

@Component
publicclass Controller {

    privatefinal Service Service;

    @Autowired
    public Controller(@Qualifier("ServiceImpl2") Service Service) {
        this.Service = Service;
    }

    public void execute() {
        Service.performService();
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.

3. 结合自定义限定符

我们还可以创建自定义的限定符注解,以提高代码的可读性和可维护性,如下代码示例:

@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface ServiceType {}
  • 1.
  • 2.
  • 3.
  • 4.

然后在 Bean 和注入点使用这个自定义注解:

@Component
@ServiceType
public class ServiceImpl implements Service {
    // 实现细节
}

@Autowired
@ServiceType
private Service Service;
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

三、示例分析

为了更好地理解 @Qualifier 的用法,这里以一个接口 Service 以及两个实现类 ServiceImpl1 和 ServiceImpl2的使用为例,如下代码示例:

public interface Service {
    void performService();
}

@Component
publicclass ServiceImpl1 implements Service {
    @Override
    public void performService() {
        System.out.println("Service Implementation 1");
    }
}

@Component
publicclass ServiceImpl2 implements Service {
    @Override
    public void performService() {
        System.out.println("Service Implementation 2");
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.

如果我们想在另一个组件中尝试注入 Service:

@Component
public class Controller {

    @Autowired
    private Service Service;

    public void execute() {
        Service.performService();
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

此时,Spring 会抛出以下异常,因为存在多个 Service 的实现:

NoUniqueBeanDefinitionException: No qualifying bean of type 'com.yuanjava.Service' available: expected single bean, but found 2
  • 1.

因此,我们可以通过使用 @Qualifier,明确指定要注入的 Bean,如下代码示例:

@Component
public class Controller {

    @Autowired
    @Qualifier("ServiceImpl1")
    private Service Service;

    public void execute() {
        Service.performService();
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

这样,Spring 就会直接注入 ServiceImpl1,避免了歧义。到此,Bean 冲突问题就完美解决。

四、与 @Primary 的区别

在分析完 @Qualifier注解后,我们再分析一下和它一样,可以影响 Bean优先级的 @Primary注解,该注解用于标记一个 Bean 为首选 Bean,当存在多个相同类型的 Bean 时,Spring 会默认注入标记了 @Primary 的 Bean,除非另有指定(如使用 @Qualifier)。

@Component
@Primary
public class PrimaryService implements Service {
    // 实现
}

@Component
public class SecondaryService implements Service {
    // 实现
}

@Autowired
private Service Service; // 注入 PrimaryService
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.

如果我们想注入 SecondaryService,可以使用 @Qualifier:

@Autowired
@Qualifier("secondaryService")
private Service Service; // 注入 SecondaryService
  • 1.
  • 2.
  • 3.

五、总结

本文,我们分析了 @Qualifier的工作原理。@Qualifier 是 Spring 中用于解决 Bean 冲突的有力工具,尤其在多实现类的场景下。通过明确指定要注入的 Bean,@Qualifier 确保了依赖注入的准确性和可维护性。结合 @Primary、自定义限定符等,开发者可以灵活地管理和注入所需的 Bean 实例,从而构建更清晰、可管理的应用结构。

责任编辑:赵宁宁 来源: 猿java
相关推荐

2021-04-29 07:18:21

Spring IOC容器单例

2022-05-24 08:09:00

HadoopHiveSpark

2022-08-13 12:07:14

URLHTTP加密

2022-05-11 22:15:51

云计算云平台

2024-05-15 16:41:57

进程IO文件

2024-10-15 10:59:18

Spring MVCJava开发

2022-08-18 17:44:25

HTTPS协议漏洞

2020-09-19 17:46:20

React Hooks开发函数

2009-07-30 14:38:36

云计算

2024-04-01 00:00:00

Redis缓存服务消息队列

2011-12-22 20:53:40

Android

2011-12-23 09:43:15

开源开放

2013-09-16 10:52:09

2022-09-16 08:42:23

JavaAPI变量

2023-08-04 08:25:03

客户配置Spring

2022-01-17 07:59:13

SpringSpringMVCSpringBoot

2022-05-10 08:11:15

MySQL技巧结构

2022-03-30 10:10:17

字节码栈空间

2012-12-19 09:04:29

2021-11-03 09:03:09

面试链接http
点赞
收藏

51CTO技术栈公众号