Больше не нужно копаться в книгах или пересматривать длинные видео, чтобы вспомнить, как устроен жизненный цикл бина в Spring. Эта шпаргалка собрала всё самое главное в одном месте: создание, внедрение зависимостей, инициализация, пост-процессинг и уничтожение — коротко, чётко и с понятными примерами.
🟢 Этап 1. Создание бина (Instantiation)
Spring создает объект бина с помощью конструктора, но пока не внедряет в него зависимости.
📌 Пример из жизни: Вы купили кофеварку, но еще не подключили ее к сети и не залили воду.
🟢 Этап 2. Внедрение зависимостей (Dependency Injection)
Spring автоматически добавляет в бин все его зависимости.
📌 Аналогия: Вы подключили кофеварку к сети и залили воду.
Способы внедрения зависимостей:
Через конструктор – рекомендуется для обязательных зависимостей, в комбинации с модификатором final обеспечивает неизменяемость объекта.
Через поле - @Autowired можно ставить на поле, и Spring внедрит зависимость. Однако этот способ не рекомендуется, так как он усложняет тестирование и делает зависимость менее явной.
Через сеттеры – используется, если зависимость может изменяться после создания бина.
Через аннотации @Value, @Qualifier и др. – применяется для внедрения простых значений и указания конкретного бина при наличии нескольких кандидатов.
🟢 Этап 3. Aware-интерфейсы
Если бин реализует BeanNameAware, BeanFactoryAware, ApplicationContextAware, Spring передает ему информацию о контексте.
📌 Пример из жизни: Кофеварка проверяет напряжение в сети перед включением.
BeanNameAware — получает имя бина
BeanFactoryAware — доступ к BeanFactory
ApplicationContextAware — доступ ко всему контексту Spring
⚠️ Используйте их с осторожностью, так как это привязывает код к Spring API и усложняет тестирование.
🟢 Этап 4. BeanPostProcessor до инициализации
Spring вызывает postProcessBeforeInitialization у всех BeanPostProcessor.
Примеры использования:
Валидация бинов – проверка корректности данных перед их использованием.
Изменение свойств – настройка конфигурации бина в зависимости от профиля приложения (@Profile).
Логирование – запись информации о бине перед его инициализацией.
🟢 Этап 5. Инициализация (init)
Spring выполняет методы:
@PostConstruct
InitializingBean#afterPropertiesSet()
Метод, указанный в @Bean(initMethod = "init")
📌 Пример: Кофеварка прогревает воду перед приготовлением кофе.
Здесь можно проверять настройки бина и подключаться к ресурсам (например, БД).
🟢 Этап 6. BeanPostProcessor после инициализации
Spring вызывает postProcessAfterInitialization у BeanPostProcessor.
Где применяется:
Проксирование бинов – создание AOP-прокси для аннотаций @Transactional, @Async и подобных.
Кэширование – автоматическое добавление механизма кэширования для методов.
Изменение бинов – динамическое добавление новых методов или обертывание логикой безопасности.
⚠️ При использовании проксирования бин может подменяться Spring-оберткой (важно при instanceof).
🟢 Этап 7. Уничтожение бина (destroy)
Spring вызывает:
@PreDestroy
DisposableBean#destroy()
Метод, указанный в @Bean(destroyMethod = "cleanup")
📌 Пример: Вы выключаете кофеварку, сливаете воду, чистите фильтр и убираете ее.
⚠️ Для prototype-бинов этот этап не вызывается — их уничтожение нужно обрабатывать вручную.
📌 Пример кода
📌 Код
// Главный бин с логами всех этапов
@Component
class MyBean implements BeanNameAware, ApplicationContextAware, InitializingBean, DisposableBean {
private String beanName;
private ApplicationContext context;
public MyBean() {
System.out.println("1. Конструктор MyBean вызван (Instantiation)");
}
@Autowired
public void setDependency(MyDependency dependency) {
System.out.println("2. Зависимость MyDependency внедрена (DI)");
}
@Override
public void setBeanName(String name) {
this.beanName = name;
System.out.println("3. BeanNameAware: Имя бина - " + name);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = applicationContext;
System.out.println("3. ApplicationContextAware: Контекст передан");
}
@PostConstruct
public void postConstruct() {
System.out.println("5. @PostConstruct: Бин проинициализирован");
}
@Override
public void afterPropertiesSet() {
System.out.println("5. InitializingBean: Бин завершил инициализацию");
}
@PreDestroy
public void preDestroy() {
System.out.println("7. @PreDestroy: Перед уничтожением бина");
}
@Override
public void destroy() {
System.out.println("7. DisposableBean: Бин уничтожен");
}
}
// Дополнительный бин для DI
@Component
class MyDependency {
public MyDependency() {
System.out.println("1. Конструктор MyDependency вызван (Instantiation)");
}
}
// BeanPostProcessor для логирования этапов postProcessBeforeInitialization и postProcessAfterInitialization
@Component
class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
if (bean instanceof MyBean) {
System.out.println("4. BeanPostProcessor: Before Init - " + beanName);
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof MyBean) {
System.out.println("6. BeanPostProcessor: After Init - " + beanName);
}
return bean;
}
}
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
📌 Вывод в консоль
1. Конструктор MyDependency вызван (Instantiation)
1. Конструктор MyBean вызван (Instantiation)
2. Зависимость MyDependency внедрена (DI)
3. BeanNameAware: Имя бина - myBean
3. ApplicationContextAware: Контекст передан
4. BeanPostProcessor: Before Init - myBean
5. @PostConstruct: Бин проинициализирован
5. InitializingBean: Бин завершил инициализацию
6. BeanPostProcessor: After Init - myBean
>>> Контекст запущен
>>> Закрытие контекста
7. @PreDestroy: Перед уничтожением бина
7. DisposableBean: Бин уничтожен
Выводы:
BeanPostProcessor используется для оберток и проксирования.
Aware-интерфейсы дают доступ к Spring-контексту, но не злоупотребляйте ими.
Правильное использование @PostConstruct и @PreDestroy упрощает управление ресурсами.