Что такое Bean в Spring?
4. BeanDefinition можно менять через BeanFactoryPostProcessor 5. Сканирование медленное на больших проектах → ограничьте пакеты
🟢 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
Когда НЕ делать объект бином
- DTO / Entity / Value Objects — это обычные объекты данных, их создают через
newили ORM - Локальные утилиты — статические методы не требуют бина
- Объекты с коротким жизненным циклом — создаются и удаляются в рамках одного запроса
Best Practices
- @Component/@Service для своего кода
- @Bean для сторонних библиотек
- Помните про Proxy — final методы не проксируются (CGLIB создаёт подкласс, final нельзя переопределить). В Spring Boot 2.2+ @Configuration может использовать
proxyBeanMethods = falseдля отключения CGLIB — это ускоряет старт. - BeanDefinition можно менять через BeanFactoryPostProcessor
- Сканирование медленное на больших проектах → ограничьте пакеты
Резюме для 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]]