Ответ
При наличии нескольких бинов, реализующих один интерфейс, Spring по умолчанию не сможет однозначно разрешить зависимость при автоматическом связывании (@Autowired), что приведет к исключению NoUniqueBeanDefinitionException.
Проблема:
interface PaymentService { void pay(); }
@Service
class CreditCardService implements PaymentService { ... }
@Service
class PayPalService implements PaymentService { ... }
@Component
class OrderProcessor {
@Autowired // ОШИБКА: NoUniqueBeanDefinitionException
private PaymentService paymentService; // Какой бин выбрать? CreditCardService или PayPalService?
}
Способы разрешения неоднозначности:
-
Использование
@Primary: Помечает один бин как предпочтительный по умолчанию.@Service @Primary // Этот бин будет выбран по умолчанию class CreditCardService implements PaymentService { ... } -
Использование
@Qualifier: Прямое указание имени конкретного бина.@Component class OrderProcessor { @Autowired @Qualifier("payPalService") // Ссылается на бин с именем 'payPalService' private PaymentService paymentService; } @Service("payPalService") // Явное задание имени бина class PayPalService implements PaymentService { ... } -
Внедрение всех бинов (коллекции): Если логика требует использования всех реализаций.
@Component class PaymentRouter { @Autowired // Внедряется List из всех бинов типа PaymentService private List<PaymentService> allPaymentServices; } -
Использование
@Resource(JSR-250): Аналог@Autowired+@Qualifier, но работает по имени.@Component class OrderProcessor { @Resource(name = "creditCardService") private PaymentService paymentService; }
Выбор стратегии: @Primary подходит для выделения реализации по умолчанию. @Qualifier обеспечивает точный контроль и необходим, когда контекст определяет, какая реализация должна быть использована.