@Autowired自动装配类型冲突

如果SpringBoot中@Autowired注入的类有多个实现类,那么应该如何指定注入哪个实现类?

面试速记

三种注解方案

1.Qualifier指定通过byName来注入

2.Primiary:带有该注解的bean会被优先注入

3.EnableAutoConfiguration(exclude...)直接不加载某个类,比较极端

三种注入的优先级:@Qualifier>@Primary>按字段名称匹配

@Qualifier

@Qualifier 是 Spring 提供的用于 消除歧义 的注解,常与 @Autowired 一起使用。当有多个符合条件的 Bean 时,@Qualifier 用于指定要注入的具体 Bean。

原理

Spring 容器在执行依赖注入时,会根据 类型匹配 查找候选 Bean:

  1. 如果只有一个匹配的 Bean,则直接注入。
  2. 如果有多个 Bean 实现了同一个接口,Spring 会抛出 NoUniqueBeanDefinitionException,因为它不知道该注入哪一个。
  3. 使用 @Qualifier("beanName"),可以告诉 Spring 注入 指定名称的 Bean,避免歧义。
public interface ServiceInterface {
    void execute();
}


@Service("serviceA")
public class ServiceImplA implements ServiceInterface {
    @Override
    public void execute() {
        System.out.println("Executing Service A");
    }
}


@Service("serviceB")
public class ServiceImplB implements ServiceInterface {
    @Override
    public void execute() {
        System.out.println("Executing Service B");
    }
}


@Service
public class MyService {
    
    @Autowired
    @Qualifier("serviceA")  // 指定注入 "serviceA" 的实现
    private ServiceInterface service;

    public void performTask() {
        service.execute();
    }
}

在上面的例子中,@Qualifier("serviceA") 指定了 ServiceImplA 作为要注入的 Bean,否则 Spring 无法区分 ServiceImplAServiceImplB

@Primary

概念

@Primary 用于 指定默认 Bean,当有多个候选 Bean 时,Spring 会优先注入 @Primary 标注的 Bean,而不需要使用 @Qualifier

原理

  1. Spring 进行依赖注入时,默认会根据 类型匹配 查找可用的 Bean。
  2. 如果找到多个符合条件的 Bean:
    • 没有 @Primary → Spring 抛出 NoUniqueBeanDefinitionException,需要手动指定 @Qualifier
    • @Primary → Spring 会优先选择 @Primary 标注的 Bean,作为默认注入的 Bean。

示例:

@Service
@Primary // 默认优先注入此实现类
public class DefaultServiceImpl implements ServiceInterface {
    @Override
    public void execute() {
        System.out.println("Executing Default Service");
    }
}


@Service
public class AlternativeServiceImpl implements ServiceInterface {
    @Override
    public void execute() {
        System.out.println("Executing Alternative Service");
    }
}


@Service
public class MyService {
    
    @Autowired
    private ServiceInterface service; // 默认注入 @Primary 标注的 DefaultServiceImpl

    public void performTask() {
        service.execute();
    }
}

说明:

  • DefaultServiceImpl@Primary 标记,因此即使 MyService 依赖 ServiceInterface,Spring 也会默认注入 DefaultServiceImpl
  • 如果希望使用 AlternativeServiceImpl,可以手动使用 @Qualifier 指定。

@EnableAutoConfiguration

概念

当 Spring Boot 启动时,@EnableAutoConfiguration 会根据 classpath 中的依赖 自动加载相关的 Bean。但有时,不同的自动配置可能会 发生冲突,或者 我们不希望某些自动配置被加载,这时就可以使用 excludeexcludeName 参数手动排除不需要的自动配置类

/**
 * 排除特定的自动配置类,以便它们永远不会被应用。
 * @return 要排除的类
 */
Class<?>[] exclude() default {};

/**
 * 排除特定的自动配置类名,以便它们永远不会被应用。
 * @return 要排除的类名
 * @since 1.3.0
 */
String[] excludeName() default {};

比较极端,会直接不加载这个类

语法:

@EnableAutoConfiguration(exclude = {要排除的自动配置类})

示例:

@Configuration
@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})
public class MyConfig {
}

在上面的代码中,我们 排除了 DataSourceAutoConfiguration,这样 Spring Boot 不会自动配置数据源

@Autowired注入Bean过程

@Autowired 的依赖注入流程是一个典型的 “按类型优先,结合名称匹配” 的机制。

  1. 按类型查找(byType)
    • 如果唯一,直接注入。
    • 如果多个,进入下一步。
  2. 检查 @Qualifier 注解
    • 如果存在 @Qualifier,按指定名称注入。
  3. 检查 @Primary 注解
    • 如果存在 @Primary,注入该 Bean。
  4. 按字段名匹配(byName)
    • 如果字段名与某个 Bean 名称一致,注入该 Bean。
  5. 以上均不满足:抛出异常。

由此可见三种注入的优先级:@Qualifier>@Primary>按字段名称匹配

  • 优先使用 @Primary:适用于定义“默认实现”(如默认数据库配置)。
  • 灵活使用 @Qualifier:需要明确指定时使用(如多数据源场景)。
  • 避免依赖字段名:字段名变化会导致注入失败,代码可维护性差。
#java#
全部评论

相关推荐

头像
03-26 13:44
南华大学 Java
在看面经的花生米很野蛮:这种情况下你当然要回答,你也是吗!!!!我超喜欢他的XXXXX
点赞 评论 收藏
分享
评论
1
1
分享

创作者周榜

更多
牛客网
牛客企业服务