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

Що таке Bean в Spring?

4. BeanDefinition можна змінювати через BeanFactoryPostProcessor 5. Сканування повільне на великих проектах → обмежте пакети

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

🟢 Junior Level

Bean (Бін) — це об’єкт, яким управляє Spring Container (ApplicationContext).

«Управляє» означає: Spring сам створює об’єкт, впроваджує його залежності, може обгорнути в проксі для додавання поведінки (транзакції, безпека, кешування), і викликає методи ініціалізації/очищення. Ви не робите new Bean() — це робить Spring.

Проста аналогія: Spring — це готель. Бін — це гість, який зареєстрований і отримує всі послуги від готелю.

Звичайний об’єкт:

User user = new User();  // Ви самі створюєте

Bean:

@Service  // ← Spring сам створить і буде управляти
public class UserService { }

Чим відрізняється:

Звичайний об’єкт Spring Bean
Ви створюєте через new Spring створює сам
Ви управляєте життям Spring управляє життям
Немає залежностей Залежності впроваджуються автоматично
Немає проксі Може бути обгорнутий в Proxy

🟡 Middle Level

BeanDefinition

BeanDefinition = "рецепт" для створення біна
  → Ім'я класу
  → Scope (Singleton, Prototype)
  → Залежності
  → Init/Destroy методи

→ Spring спочатку створює BeanDefinition
→ Потім за ним створює бін

Як створити Bean

1. Стереотипні анотації:

@Component       // Базовий
@Service         // Бізнес-логіка
@Repository      // Робота з БД
@Controller      // Web контролер

2. Java Config:

@Configuration
public class Config {
    @Bean
    public ObjectMapper mapper() {
        return new ObjectMapper();
    }
}

Проксирування

@Transactional  // ← Spring створить Proxy навколо біна
public void save() { }

// Ви отримуєте не об'єкт, а Proxy!
// Proxy → перехоплює виклик → додає транзакцію → викликає метод

Способи оголошення

1. @Component + @ComponentScan → автоматичне сканування
2. @Bean в @Configuration → ручне налаштування
3. @Import → імпорт конфігурацій

🔴 Senior Level

DefaultListableBeanFactory

Серце Spring:
  → BeanDefinitionRegistry → зберігає рецепти
  → Singleton Objects Cache → зберігає створені біни

→ ConcurrentHashMap для потокобезпеки
→ Лінива ініціалізація (крім Singleton за замовчуванням)

Proxy types

JDK Dynamic Proxy — вбудований механізм Java для проксирування ЛИШЕ за інтерфейсами. Створює об'єкт, який реалізує той самий інтерфейс, і делегує виклики реальному об'єкту.

JDK Dynamic Proxy:
  → Якщо клас реалізує інтерфейс
  → Проксирує лише методи інтерфейсу

CGLIB — бібліотека для створення підкласів у рантаймі. Spring використовує її, коли клас не реалізує інтерфейси. Підклас перехоплює виклики методів і додає поведінку.

CGLIB:
  → Якщо немає інтерфейсу
  → Створює підклас у рантаймі
  → Не може проксирувати final методи!

Bean vs POJO

POJO і Bean — це НЕ різні типи класів. Один і той самий клас може бути POJO (створений через `new`) або Bean (створений Spring). Різниця в тому, ХТО створив об'єкт і хто ним управляє.

POJO:
  → new User()
  → Ви управляєте

Bean:
  → Створюється через Reflection/CGLIB
  → DI залежностей
  → Може бути Proxy
  → Lifecycle: @PostConstruct, @PreDestroy
  → Управляється контейнером

Production Experience

Реальний сценарій: CGLIB не може проксирувати final

@Service
public class UserService {
    public final void save() { }  // final!
}

// @Transactional на save() НЕ спрацює!
// CGLIB не може перевизначити final метод
 Без транзакції  баг у production

Коли НЕ робити об’єкт біном

  1. DTO / Entity / Value Objects — це звичайні об’єкти даних, їх створюють через new або ORM
  2. Локальні утиліти — статичні методи не потребують біна
  3. Об’єкти з коротким життєвим циклом — створюються і видаляються в межах одного запиту

Best Practices

  1. @Component/@Service для свого коду
  2. @Bean для сторонніх бібліотек
  3. Пам’ятайте про Proxy — final методи не проксируються (CGLIB створює підклас, final не можна перевизначити). У Spring Boot 2.2+ @Configuration може використовувати proxyBeanMethods = false для відключення CGLIB — це прискорює старт.
  4. BeanDefinition можна змінювати через BeanFactoryPostProcessor
  5. Сканування повільне на великих проектах → обмежте пакети

Резюме для Senior

  • Bean = керований Spring об’єкт
  • BeanDefinition = мета-інформація для створення
  • Proxy → @Transactional, @Async, @Cacheable
  • CGLIB → підклас, не проксирує final
  • JDK Proxy → лише інтерфейси
  • BeanFactory → серце контейнера

🎯 Шпаргалка для співбесіди

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

  • Bean — об’єкт, яким управляє Spring Container (ApplicationContext): створює, впроваджує залежності, проксирує, викликає init/destroy
  • Ви не робите new Bean() — це робить Spring через Reflection або CGLIB
  • BeanDefinition = «рецепт» біна: ім’я класу, scope, залежності, init/destroy методи
  • Стереотипні анотації: @Component, @Service, @Repository, @Controller
  • @Bean в @Configuration — для сторонніх бібліотек і складних налаштувань
  • Spring може обгорнути бін в Proxy для @Transactional, @Async, @Cacheable
  • CGLIB не може проксирувати final методи — @Transactional на них не спрацює
  • DTO, Entity, Value Objects — НЕ повинні бути бінами

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

  • Чим Bean відрізняється від POJO? Один і той самий клас може бути POJO (new User()) або Bean (створений Spring). Різниця — хто створив і хто управляє.
  • Коли CGLIB vs JDK Dynamic Proxy? JDK Proxy — якщо є інтерфейс, CGLIB — якщо немає. JDK проксирує лише методи інтерфейсу.
  • Чи можна змінювати BeanDefinition до створення? Так, через BeanFactoryPostProcessor.
  • Чому final метод не працює з @Transactional? CGLIB створює підклас, final не можна перевизначити — транзакція не додасться.

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

  • «Всі об’єкти повинні бути бінами» (DTO, Entity, Value Objects — звичайні об’єкти)
  • «Spring Bean — це окремий тип класу» (Bean і POJO — не різні типи класів, різниця в управлінні)
  • «@Transactional працює на будь-якому методі» (не на final — CGLIB не перевизначить)
  • «Proxy — це той самий об’єкт» (Proxy — обгортка, що перехоплює виклики і додає поведінку)

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

  • [[1. Що таке Dependency Injection]]
  • [[5. Як створити Bean в Spring]]
  • [[6. Що таке Bean Lifecycle]]
  • [[7. Які етапи є у Bean lifecycle]]
  • [[8. Що таке BeanPostProcessor]]