Способы внедрения зависимостей Spring
Constructor injection
Основной вариант для обязательных зависимостей:
@Service
class OrderService {
private final OrderRepository repository;
private final Clock clock;
OrderService(OrderRepository repository, Clock clock) {
this.repository = repository;
this.clock = clock;
}
}Если конструктор один, @Autowired не требуется. Объект можно создать в unit-тесте без контейнера, а поля остаются final.
Setter injection
Подходит для действительно необязательной или изменяемой настройки:
@Autowired(required = false)
void setAuditSink(AuditSink auditSink) {
this.auditSink = auditSink;
}Объект некоторое время существует в неполном состоянии, поэтому обязательные зависимости так передавать не стоит.
Field injection
@Autowired
private OrderRepository repository;Работает, но скрывает контракт класса, мешает final и усложняет простой unit-тест. В прикладном коде лучше конструктор.
Как выбирается кандидат
- Сначала совместимость типа.
@Qualifierуточняет имя/метку.@Primaryзадаёт предпочтительный bean.- Имя параметра может использоваться как дополнительный вариант, но на него не стоит полагаться вместо явного qualifier.
- Коллекция
List<Handler>получает все подходящие бины; порядок задают@Order.
Опциональность выражают Optional<T> или ObjectProvider<T>, когда отложенное получение действительно нужно.
Циклические зависимости
Constructor cycle невозможно корректно построить. Это полезный сигнал, что обязанности сцеплены. @Lazy или setter могут отложить проблему, но сначала следует пересмотреть границы сервисов.
Вопросы для повторения
- Почему constructor injection предпочтительнее? Зависимости явны, обязательны и удобны для тестов.
- Когда нужен
@Qualifier? Когда кандидатов одного типа несколько. - Чем
ObjectProviderотличается от прямой зависимости? Позволяет получить её позже или многократно. - Почему field injection мешает тесту? Объект нельзя нормально создать обычным конструктором.
- Что означает цикл конструкторов? Часто неверное разделение обязанностей.
Связано: IoC контейнер, Виды бинов, Conditional и Profile.