@Autowired自动装配类型冲突
如果SpringBoot中@Autowired注入的类有多个实现类,那么应该如何指定注入哪个实现类?
面试速记
三种注解方案
1.Qualifier指定通过byName来注入
2.Primiary:带有该注解的bean会被优先注入
3.EnableAutoConfiguration(exclude...)直接不加载某个类,比较极端
三种注入的优先级:@Qualifier>@Primary>按字段名称匹配
@Qualifier
@Qualifier
是 Spring 提供的用于 消除歧义 的注解,常与 @Autowired
一起使用。当有多个符合条件的 Bean 时,@Qualifier
用于指定要注入的具体 Bean。
原理
Spring 容器在执行依赖注入时,会根据 类型匹配 查找候选 Bean:
- 如果只有一个匹配的 Bean,则直接注入。
- 如果有多个 Bean 实现了同一个接口,Spring 会抛出
NoUniqueBeanDefinitionException
,因为它不知道该注入哪一个。 - 使用
@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 无法区分 ServiceImplA
和 ServiceImplB
。
@Primary
概念
@Primary
用于 指定默认 Bean,当有多个候选 Bean 时,Spring 会优先注入 @Primary
标注的 Bean,而不需要使用 @Qualifier
。
原理
- Spring 进行依赖注入时,默认会根据 类型匹配 查找可用的 Bean。
- 如果找到多个符合条件的 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。但有时,不同的自动配置可能会 发生冲突,或者 我们不希望某些自动配置被加载,这时就可以使用 exclude
或 excludeName
参数 来 手动排除不需要的自动配置类。
/**
* 排除特定的自动配置类,以便它们永远不会被应用。
* @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
的依赖注入流程是一个典型的 “按类型优先,结合名称匹配” 的机制。
- 按类型查找(byType)
- 如果唯一,直接注入。
- 如果多个,进入下一步。
- 检查
@Qualifier
注解- 如果存在
@Qualifier
,按指定名称注入。
- 如果存在
- 检查
@Primary
注解- 如果存在
@Primary
,注入该 Bean。
- 如果存在
- 按字段名匹配(byName)
- 如果字段名与某个 Bean 名称一致,注入该 Bean。
- 以上均不满足:抛出异常。
由此可见三种注入的优先级:@Qualifier>@Primary>按字段名称匹配
- 优先使用
@Primary
:适用于定义“默认实现”(如默认数据库配置)。 - 灵活使用
@Qualifier
:需要明确指定时使用(如多数据源场景)。 - 避免依赖字段名:字段名变化会导致注入失败,代码可维护性差。