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

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

Ответ

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

Принцип работы:

  1. Spring анализирует конструктор класса (начиная с версии 4.3, для единственного конструктора аннотация @Autowired не обязательна).
  2. Для каждого параметра конструктора контейнер ищет подходящий бин по типу (и, при необходимости, по имени @Qualifier).
  3. Создает экземпляр класса, передавая найденные бины в качестве аргументов конструктора.

Пример:

@Service
public class OrderService {
    private final PaymentProcessor paymentProcessor;
    private final NotificationService notificationService;

    // Spring автоматически внедрит зависимости
    public OrderService(PaymentProcessor paymentProcessor, 
                        NotificationService notificationService) {
        this.paymentProcessor = paymentProcessor;
        this.notificationService = notificationService;
    }
}

Ключевые преимущества:

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

Разрешение неоднозначности: Если есть несколько бинов одного типа, необходимо использовать @Qualifier:

public OrderService(@Qualifier("payPalProcessor") PaymentProcessor processor) {
    this.paymentProcessor = processor;
}