В чем разница между аннотациями @Primary и @Qualifier в Spring?

Ответ

@Primary и @Qualifier — это два механизма разрешения неоднозначностей (ambiguity) при внедрении зависимостей, когда Spring находит несколько бинов, подходящих по типу.

@Primary указывает предпочтительный (primary) бин.

  • Когда Spring видит несколько кандидатов одного типа, он выберет тот, который помечен @Primary.
  • Это декларативный и глобальный способ указать бин по умолчанию.

@Qualifier позволяет явно указать имя (qualifier) конкретного бина.

  • Вы используете @Qualifier вместе с @Autowired для точного выбора.
  • Это императивный и локальный способ, дающий больше контроля в точке инъекции.

Пример:

// Два бина одного типа
@Component("smsService") // Имя бина - "smsService"
class SmsService implements NotificationService { /*...*/ }

@Component
@Primary // Этот бин будет выбран по умолчанию
class EmailService implements NotificationService { /*...*/ }

// Класс, использующий внедрение
@Component
public class MyClient {

    // Spring выберет EmailService, так как он @Primary
    @Autowired
    private NotificationService defaultService;

    // Явно запрашиваем бин с именем "smsService"
    @Autowired
    @Qualifier("smsService")
    private NotificationService specificService;
}
Ключевые отличия: Критерий @Primary @Qualifier
Стратегия Объявление бина по умолчанию Явное указание в точке инъекции
Уровень На уровне определения бина (@Component, @Bean) На уровне инъекции (@Autowired)
Гибкость Менее гибкий (один бин по умолчанию) Более гибкий (разный выбор в разных местах)
Приоритет Ниже: @Qualifier всегда побеждает @Primary**. | **Выше**: Если указан@Qualifier,@Primary` игнорируется.

Практическое правило: Используйте @Primary для обозначения наиболее распространенной реализации. Используйте @Qualifier, когда в разных частях приложения нужны разные реализации одного интерфейса.

Ответ 18+ 🔞

Давай разберём эту дичь с @Primary и @Qualifier, а то у меня уже глаза на лоб лезут, как у Герасима, когда он Муму топил. Весринг, сука, находит два бина одного типа и впадает в ступор, как будто впервые видит хуй в пальто.

Вот смотри, представь, у тебя есть интерфейс Уведомлятор. А реализаций — две: СМС-шляпа и Имейл-говно. Весринг смотрит на это и говорит: «Ёпта, а какую из двух пизд я тебе воткнуть?». Вот тут-то и начинается цирк.

@Primary — это как поставить на одну из этих пизд табличку «ОФИЦИАЛЬНАЯ ПИЗДА ПО УМОЛЧАНИЮ». Глобально. На весь колхоз.

  • Весринг видит две подходящие сущности, хватает ту, на которой висит @Primary, и довольный такой идёт дальше. Делает вид, что другой вообще не существует. Просто и тупо.

@Qualifier — это когда ты, ебаный царь, в каждой конкретной точке говоришь: «Слушай сюда, блядь, мне в это поле воткни не первую попавшуюся пизду, а именно ту, которая называется, например, "смсШлюха"».

  • Это точечный, императивный пиздец. Ты берёшь управление на себя и тыкаешь фреймворк мордой в нужный бин.

Пример, чтобы вообще всё стало ясно, как божий день:

// Две реализации одного интерфейса. Классика жанра.
@Component("смсРассылка") // Бин с именем "смсРассылка"
class SmsService implements NotificationService { /*...*/ }

@Component
@Primary // А ЭТО, БЛЯДЬ, ОФИЦИАЛЬНАЯ ДЕФОЛТНАЯ ПИЗДА!
class EmailService implements NotificationService { /*...*/ }

// Клиент, который всё это потребляет
@Component
public class MyClient {

    // Сюда Весринг воткнёт EmailService. Почему? Потому что на нём @Primary!
    // Он же дефолтный, его и суют везде, куда просят просто NotificationService.
    @Autowired
    private NotificationService сервисПоУмолчанию;

    // А сюда, блядь, мы говорим чётко: "Да мне похуй на твой @Primary!
    // Дай мне ту, что зовётся 'смсРассылка'!".
    // И он, скрипя зубами, суёт SmsService.
    @Autowired
    @Qualifier("смсРассылка")
    private NotificationService конкретныйСервис;
}

Ключевые отличия, если по-простому:

Критерий @Primary @Qualifier
Что делает Вешает на бин бирку «Бери меня, я главный!» Ты в каждом месте орёшь: «Дай мне вот ЭТУ конкретную штуку!»
Где вешается На саму реализацию, где @Component или @Bean Рядом с @Autowired, там, где ты эту хуйню используешь
Кто кого перебивает Проигрывает, как лох. Если есть @Qualifier, про @Primary все забывают. Побеждает всегда. Царь и бог в точке инъекции.

Практический совет, чтобы не выебать себе мозг: Ставь @Primary на ту реализацию, которую ты используешь в 95% случаев — типа основной, дефолтной. А @Qualifier пускай будет у тебя как аварийный люк, когда в каком-то особом, ебучем месте тебе вдруг понадобилась другая реализация. Так и живём.