Что произойдет в Spring, если в контексте существуют два бина одного типа с разной реализацией?

Ответ

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

Способы разрешения неоднозначности:

  1. Аннотация @Primary — помечает один бин как предпочтительный.

    @Configuration
    public class AppConfig {
    @Bean
    @Primary // Этот бин будет выбран по умолчанию
    public MyService primaryService() {
        return new PrimaryServiceImpl();
    }
    @Bean
    public MyService secondaryService() {
        return new SecondaryServiceImpl();
    }
    }
  2. Аннотация @Qualifier — явное указание имени конкретного бина.

    @Component
    public class ClientComponent {
    @Autowired
    @Qualifier("secondaryService") // Указываем конкретное имя бина
    private MyService service;
    }
  3. Совпадение имени поля с именем бина (работает в некоторых случаях, но ненадежно).

    @Autowired
    private MyService secondaryService; // Может инжектиться бин с именем "secondaryService"
  4. Инжекция всех бинов этого типа в коллекцию.

    @Autowired
    private List<MyService> allServices; // Инжектит оба бина

Рекомендация: Используйте @Qualifier для явного и понятного выбора нужной реализации.

Ответ 18+ 🔞

А, ну это же классика, блядь! Весна, такая вся из себя умная, а тут — бац, и не может выбрать, какую хуйню тебе впендюрить. Представь: сидит контейнер, чешет репу, а перед ним два одинаковых бина, как близнецы-пиздюки, и он такой: «Ну ёпта, а какую же, блядь, из них сувать-то?» И швыряет тебе в рожу NoUniqueBeanDefinitionException. Красота, да?

Но не ссы, есть способы этого долбоёба направить на путь истинный.

Варианты, как выкрутиться:

  1. @Primary — типа главный пацан.
    Вешаешь эту приблуду на одного из кандидатов, и Spring сразу понимает: «А, ну этот, значит, по умолчанию, остальные — так, запасные хуи».

    @Configuration
    public class AppConfig {
       @Bean
       @Primary // Этот чувак теперь главный, его и будут совать везде, если не указано иное
       public MyService primaryService() {
           return new PrimaryServiceImpl();
       }
       @Bean
       public MyService secondaryService() {
           return new SecondaryServiceImpl();
       }
    }
  2. @Qualifier — точный прицел по имени.
    Тут уже ты сам, как снайпер, указываешь, какую именно реализацию тебе подсунуть. Никаких недопониманий, блядь.

    @Component
    public class ClientComponent {
       @Autowired
       @Qualifier("secondaryService") // Чётко говоришь: «Давай ту, что secondaryService, а не какую-то левую!»
       private MyService service;
    }
  3. Совпадение имени поля — автопилот, который может и в дерево въебать.
    Иногда, если повезёт, Spring может догадаться, если имя поля совпадёт с именем бина. Но надеяться на это — всё равно что играть в русскую рулетку, ёпта.

    @Autowired
    private MyService secondaryService; // Может, блядь, подтянет бин с именем "secondaryService", а может, и нет — как карта ляжет.
  4. Забрать всех скопом — автобус для бинов.
    А можно не париться и взять всех кандидатов разом, запихнуть в коллекцию — и пусть там сами разбираются.

    @Autowired
    private List<MyService> allServices; // Инжектит все бины типа MyService — и делов-то!

Что в итоге?
Если хочешь спать спокойно и не гадать, что тебе впендюрят — юзай @Qualifier. Чётко, ясно, без этих вот «авось пронесёт». А то потом сидишь и думаешь: «И какого хуя тут primaryService оказался, когда мне secondary был нужен?»