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

На каком этапе инициализации бина вызывается 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);
    // Доступ к: готовому объекту
}
ХарактеристикаBeanFactoryPostProcessorBeanPostProcessor
Когда вызываетсяДО создания биновПОСЛЕ создания бинов
Что получает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");
    }
}

Выводы

  1. BeanFactoryPostProcessor вызывается ПЕРВЫМ в жизненном цикле контейнера
  2. Это происходит ДО создания самих бинов, на этапе конфигурирования
  3. Имеет доступ к BeanDefinition, но не к готовым объектам
  4. Может модифицировать определения бинов до их создания
  5. Встроенные примеры: PropertyPlaceholderConfigurer, PropertySourcesPlaceholderConfigurer
  6. Order имеет значение, если несколько BeanFactoryPostProcessor
На каком этапе инициализации бина вызывается BeanFactoryPostProcessor | PrepBro