Зачем в Spring использовать внедрение зависимостей через конструктор?

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

Ответ

Внедрение зависимостей через конструктор (Constructor Injection) — это предпочтительный и рекомендуемый подход в Spring, обеспечивающий явное, безопасное и неизменяемое создание компонентов.

Основные преимущества:

  • Неизменяемость (Immutability): Зависимости можно объявить как final. Это гарантирует, что они будут инициализированы один раз при создании бина и не могут быть изменены впоследствии, что делает объект потокобезопасным.
  • Явность и обязательность: Все зависимости видны в сигнатуре конструктора. Это делает контракт класса понятным и гарантирует, что объект не может быть создан в неполностью инициализированном состоянии.
  • Упрощение тестирования: Класс легко протестировать в изоляции (unit-тесты), так как зависимости можно передать через конструктор без необходимости Spring-контекста.
  • Избегание циклических зависимостей: Spring обнаруживает циклические зависимости на этапе создания контекста, если они реализованы через конструктор, что способствует более чистой архитектуре.

Пример:

@Service
public class OrderService {
    private final OrderRepository orderRepository;
    private final PaymentService paymentService;

    // Spring автоматически внедрит бины через этот конструктор
    public OrderService(OrderRepository orderRepository, 
                        PaymentService paymentService) {
        this.orderRepository = orderRepository;
        this.paymentService = paymentService;
    }
    // ... бизнес-логика
}

Начиная с Spring 4.3, для бинов с единственным конструктором аннотация @Autowired может быть опущена.