Что произойдет в Spring, если для одного типа интерфейса существует несколько bean-компонентов?

«Что произойдет в Spring, если для одного типа интерфейса существует несколько bean-компонентов?» — вопрос из категории Spring, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

При попытке внедрения зависимости по типу (например, с помощью @Autowired) Spring выбросит исключение NoUniqueBeanDefinitionException, так как не сможет однозначно определить, какой именно bean нужно инжектировать.

Пример проблемы:

@Component
class SmsService implements NotificationService { ... }

@Component
class EmailService implements NotificationService { ... }

@Service
class OrderProcessor {
    @Autowired // ОШИБКА: NoUniqueBeanDefinitionException - 2 бина типа NotificationService
    private NotificationService notifier;
}

Стратегии разрешения неоднозначности:

  1. Использование @Qualifier: Указание конкретного имени бина.

    @Autowired
    @Qualifier("smsService")
    private NotificationService notifier;
  2. Аннотация @Primary: Помечает один бин как предпочтительный по умолчанию.

    @Component
    @Primary // Этот бин будет выбран, если нет @Qualifier
    class EmailService implements NotificationService { ... }
  3. Внедрение по имени (@Resource): Внедрение происходит по имени бина (из аннотации @Component("myName") или имени метода @Bean).

    @Resource(name = "smsService")
    private NotificationService notifier;
  4. Внедрение всех бинов (List/Map): Получить коллекцию всех подходящих бинов.

    @Autowired
    private List<NotificationService> allNotifiers; // Внедрятся оба бина
    
    @Autowired
    private Map<String, NotificationService> notifiersMap; // Ключ - имя бина