当 Spring 容器中存在同一接口的多个实现类时,有哪些方式可以决定某个场景调用哪个实现?
Spring 默认按类型注入会报 NoUniqueBeanDefinitionException。下面按使用频率和适用场景,梳理常见的解决方式。
- @Primary:指定默认首选
在某个实现类上加@Primary,当注入点没有其他限定信息时,优先选它
java
public interface PayService {
void pay();
}
@Service
@Primary
public class AlipayService implements PayService { ... }
@Service
public class WechatPayService implements PayService { ... }
@Service
public class OrderService {
@Autowired
private PayService payService; // 注入 AlipayService
}
适用于有一个明确默认实现,少数场景才用其他实现
- @Qualifier:按Bean名称精确指定
配合 @Autowired 使用,指定要注入的 Bean 名称(默认是类名首字母小写)。
java
@Service
public class OrderService {
@Autowired
@Qualifier("wechatPayService")
private PayService payService;
}
- 按字段名/参数名匹配
Spring在按类型找到多个候选后,会退一步用注入点的名称去匹配Bean名称
java
@Service
public class OrderService {
@Autowired
private PayService wechatPayService; // 字段名匹配 Bean 名,注入 WechatPayService
}
- 注入集合或Map:拿到全部实现
java
@Service
public class PayFactory {
// 注入所有实现
@Autowired
private List<PayService> services;
// key 是 Bean 名称,value 是实现
@Autowired
private Map<String, PayService> serviceMap;
public PayService get(String name) {
return serviceMap.get(name);
}
}
这是策略模式 + 工厂的经典写法,配合Map可以做到按名称路由。
还有其他方式等。