Как работает инъекция зависимостей в Spring
Что проверяют
Понимаете ли вы, как контейнер находит и подставляет бины, и знаете ли, что делать при нескольких кандидатах.
Как отвечать
Контейнер собирает граф объектов сам. Он находит классы (сканированием пакетов по @Component и его специализациям или по методам @Bean в конфигурации), создаёт их и подставляет зависимости.
Способы внедрения:
- через конструктор: предпочтительный. Зависимость обязательна, поле можно сделать
final, класс создаётся в тестах без Spring. С одним конструктором@Autowiredне нужен; - через сеттер: для необязательных зависимостей;
- в поле: короче всех, но скрывает зависимости, мешает делать поля
finalи не даёт создать объект без контейнера. В новом коде не используют.
Как выбирается бин: сначала по типу. Кандидат один, значит он и подставляется. Кандидатов несколько, тогда решают @Primary, @Qualifier("имя") или совпадение имени параметра с именем бина. Не нашлось ни одного, значит ошибка на старте, если зависимость не помечена как необязательная (Optional, @Autowired(required = false)).
Полезные детали: можно внедрить сразу List<T> или Map<String, T> всех реализаций интерфейса; ObjectProvider даёт ленивое получение и решает проблему prototype внутри синглтона; циклическая зависимость между конструкторами приводит к ошибке на старте, и это правильно, потому что она указывает на проблему в проектировании.
Где спотыкаются
Внедряют в поле и потом не могут написать тест без контекста.
Не знают, как разрулить нескольких кандидатов.
Решают циклическую зависимость через @Lazy вместо того, чтобы исправить архитектуру.
Считают, что @Autowired обязателен на конструкторе.