Какие способы выбора реализации существуют в Spring кроме @Qualifier и @Primary
Что проверяют
Знаете ли вы, как Spring разрешает неоднозначность, когда подходящих бинов несколько, и умеете ли убрать саму неоднозначность, а не только подписать нужный бин. Следом часто просят показать паттерн «стратегия» через внедрение коллекции.
Как отвечать
Сначала механизм: квалификатор сужает список кандидатов, из оставшихся Spring берёт @Primary, затем бин с наибольшим @Priority, затем совпадающий по имени. Отсюда способы:
- имя поля или параметра: если оно совпадает с именем бина, аннотации не нужны. Для параметров конструктора нужен флаг компилятора
-parameters, плагины сборки Spring Boot включают его сами; @Resource(name = "..."): внедрение по имени из Jakarta Annotations;- коллекция:
List<PaymentProvider>получит все реализации в порядке@Order, аMap<String, PaymentProvider>даст словарь, где ключ это имя бина. Выбор делается в коде по ключу, это и есть стратегия; ObjectProvider<T>:getIfAvailable(),getIfUnique(),orderedStream()и ленивое получение;- условная регистрация:
@Profile,@Conditional, в Boot@ConditionalOnPropertyи@ConditionalOnMissingBean. В контексте остаётся один бин, и выбирать не из чего; @Bean-метод: читает настройку и возвращает нужную реализацию;- обобщённые типы:
Repository<User>иRepository<Order>различаются по параметру типа без всяких аннотаций; @Fallback: появилась в Spring Framework 6.2, это пометка, обратная@Primary, бин берётся, только если других кандидатов нет;- своя аннотация-квалификатор: помеченная
@Qualifier, читается лучше строк.
Где спотыкаются
Делают свою аннотацию без мета-аннотации @Qualifier, например помечая её @Autowired. Spring её квалификатором не считает.
Путают выбор при внедрении и выбор при регистрации. @Profile ничего не выбирает в точке внедрения, он решает, попадёт ли бин в контекст вообще.
Предлагают ObjectFactory как лекарство от циклических зависимостей. Начиная со Spring Boot 2.6 циклы запрещены по умолчанию, и правильный ответ здесь переделать связи, а не прятать цикл за ленивым получением.