В чем преимущество внедрения зависимостей через конструктор по сравнению с полями или сеттерами
Что проверяют
Понимаете ли вы, почему Spring сам рекомендует конструктор, и видите ли за этим не стиль, а свойства кода: неизменяемость, честный контракт, тестируемость.
Как отвечать
Через конструктор зависимости приходят в момент создания объекта, поэтому:
- объект не существует в неполном состоянии: нельзя получить экземпляр, у которого половина зависимостей ещё
null. При внедрении в поля такой момент есть; - поля становятся
final: зависимость нельзя подменить после создания, это защищает от случайной перезаписи и делает объект безопаснее в многопоточной среде; - контракт виден: список параметров конструктора и есть перечень того, что классу нужно для работы. Разросшийся список это честный сигнал, что класс делает слишком много, а при внедрении в поля тот же рост незаметен;
- тест не требует контейнера и рефлексии:
new OrderService(repo, clock)и всё, тогда как поля приходится заполнять черезReflectionTestUtilsили поднимать контекст; - циклические зависимости обнаруживаются сразу: Spring падает на старте с понятным сообщением, а при внедрении в поля цикл разрешается лениво и живёт незамеченным.
С весны 4.3 у класса с одним конструктором даже не нужна аннотация, контейнер выбирает его сам.
Когда сеттеры уместны: необязательная зависимость с разумным значением по умолчанию, изменяемая настройка, разрыв редкого цикла в унаследованном коде.
Где спотыкаются
Считают внедрение в поля просто «короче». Оно короче ровно до первого теста без контекста.
Оправдывают поля обходом циклической зависимости, вместо того чтобы разорвать сам цикл.
Не знают про @Autowired на конструкторе как необязательную аннотацию и спорят о том, чего в современном Spring уже нет.