Что делать, если есть несколько бинов одного типа?
Если 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]]