← Назад к вопросам
На каком этапе инициализации бина вызывается BeanFactoryPostProcessor
2.8 Senior🔥 121 комментариев
#Spring Boot и Spring Data#Spring Framework
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
BeanFactoryPostProcessor в жизненном цикле Spring бина
Отличный вопрос о этапах инициализации Spring контейнера! Ответ: BeanFactoryPostProcessor вызывается на этапе конфигурирования BeanFactory, ДО создания самих бинов. Позвольте разобраться в полном жизненном цикле.
Жизненный цикл Spring контейнера
Полная схема инициализации Spring:
1. Конфигурирование BeanFactory
├── BeanFactoryPostProcessor.postProcessBeanFactory() ← ВОТ ОН!
└── ConfigurableListableBeanFactory.freezeConfiguration()
2. Создание и инициализация бинов
├── BeanPostProcessor.postProcessBeforeInitialization()
├── Вызов @PostConstruct методов
├── Вызов InitializingBean.afterPropertiesSet()
├── Вызов init-method из аннотации
├── BeanPostProcessor.postProcessAfterInitialization()
└── Бин готов
3. Завершение работы контейнера
├── @PreDestroy методы
├── DisposableBean.destroy()
└── destroy-method
BeanFactoryPostProcessor
Это интерфейс, вызываемый ПОСЛЕ создания BeanFactory, но ДО создания бинов:
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;
@Component
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {
System.out.println("[BFPP] Этап 1: BeanFactoryPostProcessor");
// Доступ к определениям бинов (БЕЗ самих объектов)
String[] beanNames = beanFactory.getBeanDefinitionNames();
System.out.println("[BFPP] Всего bean definitions: " + beanNames.length);
// Перебираем определения
for (String beanName : beanNames) {
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
System.out.println("[BFPP] Bean: " + beanName +
", Class: " + beanDef.getBeanClassName());
}
}
}
Когда это вызывается?
@SpringBootApplication
public class Application {
public static void main(String[] args) {
// Этап 1: Создание контекста
System.out.println("[MAIN] 1. Создание ApplicationContext");
ApplicationContext context = SpringApplication.run(Application.class, args);
// К этому моменту уже:
// - BeanFactoryPostProcessor вызван
// - Все бины созданы и инициализированы
System.out.println("[MAIN] 5. Контекст полностью инициализирован");
UserService userService = context.getBean(UserService.class);
userService.someMethod();
// Завершение
context.close();
}
}
Порядок инициализации - полный пример
// 1. BeanFactoryPostProcessor
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
System.out.println("[STAGE 1] BeanFactoryPostProcessor.postProcessBeanFactory()");
}
}
// 2. BeanPostProcessor
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
System.out.println("[STAGE 3] BeanPostProcessor.postProcessBeforeInitialization: " + beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println("[STAGE 5] BeanPostProcessor.postProcessAfterInitialization: " + beanName);
return bean;
}
}
// 3. Сам бин
@Component
public class UserService {
public UserService() {
System.out.println("[STAGE 2] UserService - Constructor (создание объекта)");
}
@PostConstruct
public void init() {
System.out.println("[STAGE 4a] @PostConstruct - инициализация");
}
public void afterPropertiesSet() {
System.out.println("[STAGE 4b] afterPropertiesSet() - инициализация");
}
@PreDestroy
public void cleanup() {
System.out.println("[STAGE 6] @PreDestroy - очистка");
}
}
// ВЫВОД:
// [STAGE 1] BeanFactoryPostProcessor.postProcessBeanFactory()
// [STAGE 2] UserService - Constructor
// [STAGE 3] BeanPostProcessor.postProcessBeforeInitialization: userService
// [STAGE 4a] @PostConstruct - инициализация
// [STAGE 5] BeanPostProcessor.postProcessAfterInitialization: userService
// [STAGE 6] @PreDestroy - очистка (при close())
Практический пример: Модификация BeanDefinition
@Component
public class PropertyModifyingBeanFactoryPostProcessor
implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Получаем определение бина ДО его создания
BeanDefinition dataSourceDef = beanFactory.getBeanDefinition("dataSource");
// Модифицируем свойства
MutablePropertyValues props = dataSourceDef.getPropertyValues();
props.addPropertyValue("maxPoolSize", 10);
props.addPropertyValue("minIdleConnections", 5);
System.out.println("[BFPP] DataSource bean definition модифицирован");
}
}
Разница между BeanFactoryPostProcessor и BeanPostProcessor
// BeanFactoryPostProcessor - работает с BeanDefinition
// Этап: КОНФИГУРИРОВАНИЕ бинов (ДО создания)
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory);
// Доступ к: BeanDefinition, но БЕЗ самого объекта
}
// BeanPostProcessor - работает с готовыми объектами
// Этап: ИНИЦИАЛИЗАЦИЯ бинов (ПОСЛЕ создания)
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object bean, String beanName);
Object postProcessAfterInitialization(Object bean, String beanName);
// Доступ к: готовому объекту
}
| Характеристика | BeanFactoryPostProcessor | BeanPostProcessor |
|---|---|---|
| Когда вызывается | ДО создания бинов | ПОСЛЕ создания бинов |
| Что получает | BeanDefinition | Готовый объект |
| Может ли изменить | Определение бина | Сам объект, его свойства |
| Количество вызовов | Один раз для контейнера | Один раз на каждый бин |
| Пример | PropertyPlaceholderConfigurer | Аннотация @Autowired |
Встроенные BeanFactoryPostProcessor
// PropertyPlaceholderConfigurer - замена ${} placeholders
@Configuration
public class PropertiesConfig {
@Bean
public static PropertyPlaceholderConfigurer propertyConfigurer() {
PropertyPlaceholderConfigurer configurer = new PropertyPlaceholderConfigurer();
configurer.setLocation(new ClassPathResource("app.properties"));
return configurer;
}
}
// PropertySourcesPlaceholderConfigurer - Java 5+
@Configuration
@PropertySource("classpath:app.properties")
public class PropertiesConfig2 {
@Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
// В классе:
@Component
public class DataSourceConfig {
@Value("${database.url}")
private String dbUrl; // Значение подставляется в BeanFactoryPostProcessor
}
Сложный пример: Кастомный BeanFactoryPostProcessor
@Component
public class AutowiringBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
String[] beanNames = beanFactory.getBeanDefinitionNames();
for (String beanName : beanNames) {
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
// Проверяем класс бина
if (beanDef.getBeanClassName() != null) {
try {
Class<?> beanClass = Class.forName(beanDef.getBeanClassName());
// Если класс имеет аннотацию @Component
if (beanClass.isAnnotationPresent(Component.class)) {
System.out.println("[BFPP] Found @Component: " + beanName);
// Можно добавить свойства
MutablePropertyValues props = beanDef.getPropertyValues();
// props.addPropertyValue("someProperty", "someValue");
}
} catch (ClassNotFoundException e) {
// ignore
}
}
}
}
}
Order/Ordered для нескольких PostProcessors
@Component
@Order(1) // Вызовется первым
public class FirstBFPP implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
System.out.println("[BFPP-1] First");
}
}
@Component
@Order(2) // Вызовется вторым
public class SecondBFPP implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
System.out.println("[BFPP-2] Second");
}
}
Выводы
- BeanFactoryPostProcessor вызывается ПЕРВЫМ в жизненном цикле контейнера
- Это происходит ДО создания самих бинов, на этапе конфигурирования
- Имеет доступ к BeanDefinition, но не к готовым объектам
- Может модифицировать определения бинов до их создания
- Встроенные примеры: PropertyPlaceholderConfigurer, PropertySourcesPlaceholderConfigurer
- Order имеет значение, если несколько BeanFactoryPostProcessor