Что такое BeanPostProcessor и как он работает в Spring
Что проверяют
Понимаете ли вы, в какой момент жизненного цикла бина вмешивается контейнер, и знаете ли, что через этот механизм работает вся аннотационная магия Spring.
Как отвечать
BeanPostProcessor это интерфейс с двумя методами, которые контейнер вызывает для каждого бина:
postProcessBeforeInitializationпосле создания объекта и внедрения зависимостей, но до методов инициализации;postProcessAfterInitializationпосле@PostConstruct,InitializingBean.afterPropertiesSetиinit-method.
Порядок для одного бина: создание объекта, внедрение зависимостей, before, инициализация, after.
Главное в этом механизме то, что оба метода возвращают объект, и вернуть можно не тот, что пришёл. Именно так появляются прокси: AnnotationAwareAspectJAutoProxyCreator это BeanPostProcessor, который на шаге after подменяет бин обёрткой. Отсюда работают @Transactional, @Async, @Cacheable, а заодно и объяснение, почему самовызов метода внутри класса эти аннотации игнорирует.
Другие примеры из самого Spring: AutowiredAnnotationBeanPostProcessor обрабатывает @Autowired и @Value, CommonAnnotationBeanPostProcessor отвечает за @PostConstruct и @Resource.
Обязательно отличайте от BeanFactoryPostProcessor: тот работает раньше и не с объектами, а с описаниями бинов, до их создания. Классический представитель это PropertySourcesPlaceholderConfigurer, подставляющий значения свойств.
Практическая тонкость: сам BeanPostProcessor создаётся очень рано, поэтому всё, что в него внедрено, тоже инициализируется досрочно и может не попасть под обработку другими постпроцессорами. В логе это видно как предупреждение «is not eligible for getting processed by all BeanPostProcessors». Лечится ленивым получением зависимости через ObjectProvider.
Где спотыкаются
Путают с BeanFactoryPostProcessor.
Не знают, что через этот механизм создаются прокси AOP.
Возвращают null из метода и теряют бин.
Внедряют в постпроцессор тяжёлые зависимости и ломают порядок инициализации.