Как в Spring разрешить неоднозначность при внедрении бинов (Autowired)?

«Как в Spring разрешить неоднозначность при внедрении бинов (Autowired)?» — вопрос из категории Spring, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Когда Spring находит несколько бинов, подходящих для инъекции, возникает неоднозначность. Её можно разрешить несколькими способами.

Основные методы:

  1. Аннотация @Qualifier: Прямое указание имени конкретного бина.

    @Component("firstService")
    public class FirstServiceImpl implements MyService {}
    
    @Component("secondService")
    public class SecondServiceImpl implements MyService {}
    
    @Service
    public class ClientService {
        @Autowired
        @Qualifier("secondService") // Явно указываем, какой бин внедрить
        private MyService service;
    }
  2. Аннотация @Primary: Помечает один из кандидатов как бин по умолчанию.

    @Component
    @Primary // Этот бин будет выбран, если нет других указаний
    public class PrimaryServiceImpl implements MyService {}
    
    @Component
    public class SecondaryServiceImpl implements MyService {}
  3. Имя поля/параметра: Если имя поля совпадает с именем одного из бинов (при использовании @Autowired).

    @Component
    public class MyServiceImpl implements MyService {}
    
    @Service
    public class ClientService {
        @Autowired
        private MyService myServiceImpl; // Будет внедрен бин с именем 'myServiceImpl'
    }
  4. Кастомная аннотация: Создание своей аннотации, мета-аннотированной @Qualifier.

    @Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Qualifier
    public @interface DatabaseType {
        String value();
    }
    
    @Component
    @DatabaseType("mysql")
    public class MySqlService implements DataService {}
    
    @Service
    public class BusinessService {
        @Autowired
        @DatabaseType("mysql")
        private DataService dataService;
    }