Почему в Spring не рекомендуется использовать field injection?

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

Ответ

Внедрение зависимостей через аннотацию @Autowired над полем (field injection) считается антипаттерном по нескольким ключевым причинам:

Недостатки field injection:

  • Нарушение инкапсуляции: Делает поля неявно обязательными и изменяемыми, что усложняет поддержку.
  • Сложность тестирования: Для юнит-тестов требуется рефлексия или Spring-контекст, чтобы установить мок-зависимость.
  • Неявность зависимостей: Класс не сигнализирует о своих зависимостях через публичный API (конструктор/сеттеры).
  • Проблемы с final полями: Поля не могут быть final, что снижает безопасность в многопоточном контексте.

Пример (антипаттерн):

@Service
public class UserService {
    @Autowired // Плохо: field injection
    private UserRepository userRepository;
}

Рекомендуемый подход — Constructor Injection:

@Service
public class UserService {
    private final UserRepository userRepository;
    // Зависимости явно объявлены и обязательны
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
}

Преимущества constructor injection:

  1. Неизменяемость: Поля можно сделать final.
  2. Явность: Конструктор четко определяет обязательные зависимости.
  3. Простота тестирования: Легко создать экземпляр класса в тесте, передав моки.
  4. Безопасность от NPE: Все зависимости гарантированно проинициализированы при создании бина.