Питання 26 · Розділ 5

Що робить анотація @Autowired?

4. Уникайте static полів 5. Collection → усі біни типу 6. AOT → рефлексія замінюється на прямий код

Мовні версії: English Russian Ukrainian

🟢 Junior Level

@Autowired — вказує Spring впровадити залежність.

@Service
public class OrderService {

    @Autowired  // Spring сам знайде та впровадить OrderRepository
    private OrderRepository repo;
}

Де працює:

  • Конструктор
  • Поля
  • Сеттери

Правило:

  • Один бін типу → впровадить його
  • Кілька → помилка або @Qualifier

🟡 Middle Level

AutowiredAnnotationBeanPostProcessor

Обробка @Autowired:
  1. Сканує поля/методи/конструктори
  2. Створює InjectionMetadata (кеш)
  3. Шукає підходящі біни
  4. Впроваджує через рефлексію

Алгоритм пошуку

1. За типом (byType) — Spring знаходить усі біни цього типу
2. Якщо кілька — @Qualifier фільтрує за ім'ям
3. Якщо немає @Qualifier — перевіряється @Primary (глобальна мітка «за замовчуванням»)
4. Якщо немає @Primary — за ім'ям змінної (byName)

Constructor Injection (рекомендується)

@Service
public class OrderService {
    private final OrderRepository repo;

    // Один конструктор → @Autowired не потрібен!
    public OrderService(OrderRepository repo) {
        this.repo = repo;
    }
}

Впровадження колекцій

// Усі біни типу PaymentService
@Autowired
List<PaymentService> payments;

// Map: ім'я біна → бін
@Autowired
Map<String, PaymentService> paymentMap;

🔴 Senior Level

ObjectProvider

@Autowired
ObjectProvider<PaymentService> provider;

// Ліниве отримання
PaymentService service = provider.getIfAvailable();

// Stream усіх бінів
provider.stream().forEach(...);

// Вирішення циклів!

Reflection Overhead

Field Injection → setAccessible(true) → рефлексія
  → + overhead при ініціалізації

Constructor Injection → прямий виклик
  → Швидше

AOT (GraalVM) → рефлексія → прямий код
  → Немає overhead від рефлексії (setAccessible). Залежності вирішуються на етапі компіляції.

Production Experience

Реальний сценарій: static поле

@Autowired
private static Repo repo;  // НЕ працює!

// Spring впроваджує в екземпляри, не в класи
// → repo = null

Best Practices

  1. Constructor → за замовчуванням
  2. @Autowired не потрібен для одного конструктора
  3. ObjectProvider → для циклів та лінивості
  4. Уникайте static полів
  5. Collection → усі біни типу
  6. AOT → рефлексія замінюється на прямий код

Резюме для Senior

  • AutowiredAnnotationBeanPostProcessor (AABPP) → обробка @Autowired
  • Constructor → швидше, final поля
  • ObjectProvider → ліниве, цикли
  • static → не працює
  • Collection → усі біни типу
  • AOT → немає рефлексії в Native Image

🎯 Шпаргалка для інтерв’ю

Обов’язково знати:

  • @Autowired обробляється AutowiredAnnotationBeanPostProcessor — сканує поля/методи/конструктори
  • Алгоритм: byType → @Qualifier → @Primary → byName → помилка
  • Constructor Injection — рекомендований підхід; з одним конструктором @Autowired не потрібен
  • Впровадження колекцій: List — усі біни типу, Map<String, T> — ім'я біна → бін
  • ObjectProvider — ліниве отримання, stream усіх бінів, вирішення циклічних залежностей
  • @Autowired на static полях НЕ працює — Spring впроваджує в екземпляри, не в класи
  • Constructor Injection швидший за Field Injection: прямий виклик vs рефлексія (setAccessible)

Часті уточнюючі запитання:

  • Що буде, якщо два біни одного типу без @Qualifier? — NoUniqueBeanDefinitionException (якщо немає @Primary або збігу за ім’ям).
  • Як вирішити циклічну залежність? — ObjectProvider.getIfAvailable() або setter/field injection замість constructor.
  • Чому Constructor Injection рекомендується? — Immutable поля (final), немає рефлексії, легше тестувати, явні залежності.
  • Чи працює @Autowired в GraalVM Native Image? — Так, але рефлексія замінюється на прямий код при AOT-компіляції.

Червоні прапорці (НЕ говорити):

  • «@Autowired на static полі працює» — ні, Spring не впроваджує у статичні поля.
  • «Spring шукає бін за ім’ям в першу чергу» — ні, спочатку byType, потім byName.
  • «Field Injection краще Constructor Injection» — навпаки, constructor дає immutable та тестованість.
  • «@Autowired завжди обов’язковий» — ні, з одним конструктором Spring впроваджує автоматично.

Пов’язані теми:

  • [[27. Що робити, якщо є кілька бінів одного типу]]
  • [[28. Що таке @Qualifier]]
  • [[24. Що таке @Configuration клас]]
  • [[25. В чому різниця між @Component, @Service, @Repository, @Controller]]