Вопрос 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]]
  • [[8. Что такое BeanPostProcessor]]