Що робити, якщо є кілька бінів одного типу?
Якщо Spring знаходить кілька бінів одного типу → помилка!
🟢 Junior Level
Якщо Spring знаходить кілька бінів одного типу → помилка!
Рішення:
1. @Primary — головний бін:
@Primary
@Bean
public PaymentService defaultPayment() { ... }
2. @Qualifier — явний вибір:
@Autowired
@Qualifier("stripePayment")
private PaymentService payment;
3. Ім’я змінної:
@Autowired
private PaymentService stripePayment; // За ім'ям біна!
🟡 Middle Level
Порядок вирішення
1. @Qualifier — явний фільтр за ім'ям (найвищий пріоритет)
2. @Primary — глобальна мітка «за замовчуванням»
3. Ім'я змінної (byName) — якщо немає @Qualifier та @Primary
4. @Priority (JSR-250) — числовий пріоритет на рівні класів
Впровадження всіх бінів
// Усі реалізації PaymentService
@Autowired
List<PaymentService> allPayments;
// Map: ім'я біна → бін
@Autowired
Map<String, PaymentService> paymentMap;
// Використання:
PaymentService service = paymentMap.get("stripe");
ObjectProvider
@Autowired
ObjectProvider<PaymentService> provider;
PaymentService service = provider.getIfAvailable(
() -> new DefaultPaymentService() // Фоллбек!
);
🔴 Senior Level
Кастомні кваліфікатори
@Qualifier
@Retention(RUNTIME)
public @interface StripePayment { }
@StripePayment
@Bean
public PaymentService stripePayment() { ... }
@Autowired
@StripePayment
private PaymentService payment;
// → Типобезпечно, немає одруків!
NoUniqueBeanDefinitionException діагностика
// FailureAnalyzer Spring Boot автоматично покаже всі знайдені біни
// при NoUniqueBeanDefinitionException — не потрібно лізти в стек-трейс.
Production Experience
Реальний сценарій: 10 реалізацій
Патерн Стратегія:
→ Map<String, Strategy> strategies
→ Вибір за ключем в рантаймі
→ Без if/else!
Best Practices
- @Primary → один головний бін
- @Qualifier → явний вибір
- Map → патерн Стратегія
- Кастомні кваліфікатори → типобезпечно
- ObjectProvider → фоллбек
- @ConditionalOnMissingBean → в стартерах
Резюме для Senior
- @Primary → бін за замовчуванням
- @Qualifier → точний вибір
- Map → усі біни, вибір за ключем
- Кастомні кваліфікатори → типобезпечно
- ObjectProvider → ліниве + фоллбек
- FailureAnalyzer → діагностика помилки
🎯 Шпаргалка для інтерв’ю
Обов’язково знати:
- Порядок вирішення: @Qualifier → @Primary → byName → @Priority (JSR-250)
- @Primary — глобальна мітка «бін за замовчуванням» для даного типу
- @Qualifier — явний фільтр за ім’ям, найвищий пріоритет
- Впровадження всіх бінів: List
(порядок) або Map<String, T> (ім'я → бін) — патерн Стратегія - ObjectProvider.getIfAvailable(fallback) — ліниве отримання з фоллбеком
- Кастомні кваліфікатори (@Qualifier + мета-анотація) — типобезпечно, без рядків
- FailureAnalyzer Spring Boot автоматично показує всі знайдені біни при NoUniqueBeanDefinitionException
Часті уточнюючі запитання:
- Що має пріоритет: @Primary чи @Qualifier? — @Qualifier, явний вибір завжди пріоритетніший.
- Як реалізувати патерн Стратегія в Spring? — Map<String, Strategy> — ключ = ім’я біна, вибір в рантаймі без if/else.
- Що буде, якщо немає ні @Primary, ні @Qualifier, ні збігу за ім’ям? — NoUniqueBeanDefinitionException.
- Навіщо потрібні кастомні кваліфікатори? — Типобезпечність: компілятор ловить помилки, немає одруків у рядках.
Червоні прапорці (НЕ говорити):
- «@Primary завжди перевизначить @Qualifier» — ні, @Qualifier має найвищий пріоритет.
- «Map впроваджує тільки один бін» — ні, Map містить ВСІ біни типу, ключ = ім’я.
- «Можна сміливо використовувати рядки в @Qualifier» — ризиковано: одруки ловляться тільки в рантаймі.
- «Якщо є @Primary, інших бінів цього типу не буде» — ні, усі біни зареєстровані, @Primary тільки вибирає default.
Пов’язані теми:
- [[28. Що таке @Qualifier]]
- [[26. Що робить анотація @Autowired]]
- [[24. Що таке @Configuration клас]]
- [[25. В чому різниця між @Component, @Service, @Repository, @Controller]]