2022-04-19 10:13:33
Spring: где ставить Autowired
Аннотацию
Autowired можно ставить над конструктором, сеттером и просто над полем.
Есть популярная рекомендация, что через конструктор — самое правильное. На эту тему написаны сотни(!) статей и ответов на StackOverflow. Даже Intellij IDEA подсказывает, что "
Field injection is not recommended"
В большинстве моих проектов
Autowired ставили над полем, потому что так короче. В этом посте разберёмся, откуда взялась эта рекомендация, и насколько она актуальна.
В чём разница между способами с точки зрения Spring?
Только в порядке установки для каждого бина:
Конструктор→поля→сеттеры
В остальном механизмы спринга работают одинаково:
Циклические зависимости возможны везде
Прокси создаются корректно
Отсутствующие зависимости обнаруживаются при компиляции или на старте приложения
Откуда взялась эта рекомендация?
Большинство авторов ссылаются на документацию. В разделе Dependency Injection указаны только два способа — конструктор и сеттер. Они универсальны и для XML конфигурации, и для аннотаций.
В этом же разделе стоит рекомендация — использовать конструктор для обязательных и final полей, сеттер — для необязательных.
Autowired над полями относится только к annotation-based конфигурации, поэтому находится в другом разделе. В документации нет ни единого упоминания, что
Autowired над полями — это грех и хуже конструкторов и сеттеров.
Рассмотрим основные аргументы против
Autowired над полем:
Слишком просто добавлять новые зависимости. Класс легко может потерять единственную ответственность. А когда в конструкторе 10 параметров, это сразу заметно
Единственная ответственность Autowired — внедрить зависимость. Следить за дизайном — задача программиста
Зависимость от DI-контейнера. Класс с аннотациями нельзя использовать за пределами проекта
Ни разу не было такой потребности
Полям нельзя добавить final
Жаль, конечно, но мало кто в рантайме заменяет сервисы и репозитории
Autowired поля проставляются через Reflection
Если вам важно, что делает фреймворк под капотом, посмотрите на класс Constructor Resolver, там рефлекшена в 10 раз больше
Непонятно, какие зависимости обязательные, а какие нет
По умолчанию все
Autowired зависимости обязательные. Если что-то необязательно, то можно поставить флажок (required=false)
Непонятно, как тестировать такие классы без поднятия контекста
10 лет назад было действительно никак. Сейчас юнит-тесты легко писать с помощью Mockito аннотаций
@InjectMocks и
@MockBean Итого
Autowired над полями — самый лаконичный способ внедрить зависимость. Я не нашла ни одного весомого аргумента против. Для типичного энтерпрайз приложения этот способ идеально подходит.
Лучшие практики и рекомендации формируются в своём контексте. Когда контекст меняется, практика может стать неактуальной. И это норм
2.8K views07:13