Ответ
Constructor Injection (внедрение через конструктор) является предпочтительным и рекомендованным способом в Spring.
Причины:
- Неизменяемость (Immutability): Поля зависимостей можно объявить как
final, гарантируя их инициализацию только один раз и потокобезопасность. - Явность и обязательность: Все зависимости явно указаны в конструкторе. Объект не может быть создан в невалидном состоянии с отсутствующими зависимостями.
- Упрощение тестирования: Класс легко протестировать в изоляции, передавая моки (Mockito) или заглушки напрямую в конструктор.
- Соответствие принципам SOLID: В частности, принципу инверсии зависимостей (Dependency Inversion Principle).
Пример:
@Service
public class OrderService {
private final PaymentGateway paymentGateway;
private final InventoryService inventoryService;
private final NotificationService notificationService;
// Spring автоматически внедрит зависимости, начиная с версии 4.3+
public OrderService(PaymentGateway paymentGateway,
InventoryService inventoryService,
NotificationService notificationService) {
this.paymentGateway = paymentGateway;
this.inventoryService = inventoryService;
this.notificationService = notificationService;
}
// Бизнес-логика
}
Альтернативы и их недостатки:
- Field Injection (полевое): Использование
@Autowiredнад полем. Не рекомендуется, так как скрывает зависимости, усложняет тестирование (требует рефлексии или Spring-контекста) и нарушает инкапсуляцию. - Setter Injection (через сеттер): Допустим, но делает зависимость опциональной, что может привести к ошибкам времени выполнения (
NullPointerException).