← Назад к вопросам

Что такое жизненный цикл Bean?

2.0 Middle🔥 201 комментариев
#Spring Boot и Spring Data#Spring Framework

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Жизненный цикл Bean в Spring Framework

Bean Lifecycle — это набор этапов, через которые проходит объект (bean) от создания до удаления в контейнере Spring. Понимание этого процесса критично для правильного использования Spring Framework.

Основные этапы жизненного цикла

1. Instantiation (создание объекта)

Spring создаёт экземпляр класса через конструктор (с параметрами или без).

@Component
public class MyBean {
    // Spring вызывает конструктор
    public MyBean() {
        System.out.println("1. Instantiation - Bean создан");
    }
}

2. Populate Properties (установка свойств)

Spring устанавливает значения полей через setter-методы или поля с аннотацией @Autowired.

@Component
public class MyBean {
    @Autowired
    private SomeService service;  // Будет инжектирован здесь
    
    @Value("${app.name}")
    private String appName;  // Будет установлено здесь
}

3. setBeanName (установка имени bean)

Если bean имплементирует BeanNameAware, Spring передаёт имя bean.

@Component
public class MyBean implements BeanNameAware {
    @Override
    public void setBeanName(String name) {
        System.out.println("3. BeanNameAware.setBeanName: " + name);
    }
}

4. setBeanFactory (установка factory)

Если bean имплементирует BeanFactoryAware.

@Component
public class MyBean implements BeanFactoryAware {
    @Override
    public void setBeanFactory(BeanFactory beanFactory) 
            throws BeansException {
        System.out.println("4. BeanFactoryAware.setBeanFactory вызван");
    }
}

5. setApplicationContext (установка context)

Если bean имплементирует ApplicationContextAware.

@Component
public class MyBean implements ApplicationContextAware {
    @Override
    public void setApplicationContext(ApplicationContext context) 
            throws BeansException {
        System.out.println("5. ApplicationContextAware.setApplicationContext вызван");
    }
}

6. BeanPostProcessor.postProcessBeforeInitialization

Вызывается после инъекции зависимостей, но ДО инициализации bean.

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) 
            throws BeansException {
        if (bean instanceof MyBean) {
            System.out.println("6. postProcessBeforeInitialization для " + beanName);
        }
        return bean;
    }
}

7. @PostConstruct / afterPropertiesSet

Вызывается ПОСЛЕ инъекции всех зависимостей. Это идеальное место для инициализации.

@Component
public class MyBean implements InitializingBean {
    private List<String> data;
    
    // Вариант 1: с помощью @PostConstruct
    @PostConstruct
    public void init() {
        System.out.println("7a. @PostConstruct init вызван");
        data = new ArrayList<>();
        data.add("initialized");
    }
    
    // Вариант 2: с помощью InitializingBean
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("7b. InitializingBean.afterPropertiesSet вызван");
    }
    
    // Вариант 3: initMethod в @Bean
    public void customInit() {
        System.out.println("7c. Кастомный initMethod");
    }
}

8. BeanPostProcessor.postProcessAfterInitialization

Вызывается ПОСЛЕ инициализации bean.

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) 
            throws BeansException {
        if (bean instanceof MyBean) {
            System.out.println("8. postProcessAfterInitialization для " + beanName);
        }
        return bean;
    }
}

9. Ready to Use

Bean полностью инициализирован и готов к использованию.

@Component
public class MyBean {
    public void doSomething() {
        System.out.println("9. Bean готов к использованию");
    }
}

10. @PreDestroy / destroy

Вызывается ДО уничтожения bean (при закрытии context). Используется для очистки ресурсов.

@Component
public class MyBean implements DisposableBean {
    private Connection dbConnection;
    
    @PostConstruct
    public void init() {
        // Открываем соединение
        dbConnection = createConnection();
    }
    
    // Вариант 1: @PreDestroy
    @PreDestroy
    public void cleanup() {
        System.out.println("10a. @PreDestroy cleanup вызван");
        if (dbConnection != null) {
            dbConnection.close();
        }
    }
    
    // Вариант 2: DisposableBean
    @Override
    public void destroy() throws Exception {
        System.out.println("10b. DisposableBean.destroy вызван");
    }
    
    // Вариант 3: destroyMethod в @Bean
    public void customDestroy() {
        System.out.println("10c. Кастомный destroyMethod");
    }
}

Полный пример с демонстрацией

@Component
public class FullLifecycleBean implements 
        BeanNameAware,
        BeanFactoryAware,
        ApplicationContextAware,
        InitializingBean,
        DisposableBean {
    
    private String name;
    
    public FullLifecycleBean() {
        System.out.println("1. Instantiation");
    }
    
    @Autowired
    public void setName(String appName) {
        this.name = appName;
        System.out.println("2. Property injected: " + appName);
    }
    
    @Override
    public void setBeanName(String name) {
        System.out.println("3. setBeanName: " + name);
    }
    
    @Override
    public void setBeanFactory(BeanFactory factory) {
        System.out.println("4. setBeanFactory");
    }
    
    @Override
    public void setApplicationContext(ApplicationContext context) {
        System.out.println("5. setApplicationContext");
    }
    
    @PostConstruct
    public void postConstruct() {
        System.out.println("7. @PostConstruct");
    }
    
    @Override
    public void afterPropertiesSet() {
        System.out.println("7b. afterPropertiesSet");
    }
    
    @PreDestroy
    public void preDestroy() {
        System.out.println("10. @PreDestroy");
    }
    
    @Override
    public void destroy() {
        System.out.println("10b. destroy");
    }
}

Вывод при запуске:

1. Instantiation
2. Property injected: myapp
3. setBeanName: fullLifecycleBean
4. setBeanFactory
5. setApplicationContext
7. @PostConstruct
7b. afterPropertiesSet
[Bean готов к использованию]
10. @PreDestroy
10b. destroy

Конфигурирование через @Bean

@Configuration
public class BeanConfig {
    @Bean(initMethod = "init", destroyMethod = "cleanup")
    public MyService myService() {
        return new MyService();
    }
}

public class MyService {
    public void init() {
        System.out.println("Инициализация через initMethod");
    }
    
    public void cleanup() {
        System.out.println("Очистка через destroyMethod");
    }
}

Scope и жизненный цикл

Длительность жизни bean зависит от scope:

// Singleton (по умолчанию)
@Component  // или @Bean
public class SingletonBean {}
// Один экземпляр на весь контекст

// Prototype
@Component
@Scope("prototype")
public class PrototypeBean {}
// Новый экземпляр каждый раз

// Request scope (web)
@Component
@Scope("request")
public class RequestBean {}
// Новый экземпляр на каждый HTTP request

Лучшие практики

  1. Используй @PostConstruct вместо конструктора — для инициализации логики
  2. Используй @PreDestroy — для освобождения ресурсов
  3. Избегай сложной логики в конструкторе — конструктор должен быть простым
  4. Будь осторожен с BeanPostProcessor — может замедлить инициализацию
  5. Помни о порядке — @PostConstruct вызывается после инъекции зависимостей

Заключение

Жизненный цикл Bean — это сложная, но мощная система, позволяющая Spring фреймворку полностью управлять объектами. Глубокое понимание этапов критично для написания правильного Spring кода и избежания проблем с инициализацией и очисткой ресурсов.