title: Spring注入bean发现多个候选bean错误
author: 红豆刨冰
1.问题描述
报错信息
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 1 of constructor in com.hmall.trade.service.impl.OrderServiceImpl required a single bean, but 2 were found:
- orderDetailServiceImpl: defined in file [/Users/tom/Desktop/SpringCloud微服务—资料/day03-微服务01/资料/hmall/trade-service/target/classes/com/hmall/trade/service/impl/OrderDetailServiceImpl.class]
- IOrderDetailService: defined in file [/Users/tom/Desktop/SpringCloud微服务—资料/day03-微服务01/资料/hmall/trade-service/target/classes/com/hmall/trade/service/IOrderDetailService.class]
这个错误信息表明在 Spring 容器中有两个候选的 Bean 满足 OrderController 的构造函数参数要求,而 Spring 无法确定应该注入哪一个。这两个候选的 Bean 是 orderServiceImpl 和 IOrderService。
2.解决方法
在 Spring 依赖注入过程中,OrderDetailServiceImpl 类是 IOrderDetailService 接口的一个实现类,当使用接口类型(IOrderDetailService)进行注入时,Spring 容器中可能有多个该接口的实现类,而 Spring 无法自动决定使用哪一个实现类,所以会报错
解决方法有三种,推荐前两种
方法一:使用 @Qualifier 注解
在 OrderController 中使用 @Qualifier 注解明确指定要注入的实现类
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService {
private final ItemClient itemClient;
// private final OrderDetailServiceImpl detailService;
private final IOrderDetailService detailService;
private final CartClient cartClient;
public OrderServiceImpl(ItemClient itemClient, @Qualifier("orderDetailServiceImpl") IOrderDetailService orderDetailService, CartClient cartClient) {
this.itemClient = itemClient;
this.detailService = orderDetailService;
this.cartClient = cartClient;
}
//...
}
方法二:使用 @Primary 注解
在 OrderServiceImpl 类上添加 @Primary 注解,指定它为默认实现。
@Primary
@Service
public class OrderDetailServiceImpl extends ServiceImpl<OrderDetailMapper, OrderDetail> implements IOrderDetailService {
}
方法三:直接使用实现类创建(不推荐)
@Service
@RequiredArgsConstructor
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService {
private final ItemClient itemClient;
private final OrderDetailServiceImpl detailService;
// private final IOrderDetailService detailService;
private final CartClient cartClient;
//...
}
直接找到该具体类型的 Bean 并注入,不会有歧义,所以不会报错.
虽然直接注入具体实现类可以解决问题,但从设计上考虑,通常推荐依赖接口而不是具体实现类。
3.疑问
为何一个接口一个实现类也会报错,黑马视频里就没有报错???