Как именно работает Spring BeanPostProcessor?

98

Я изучаю сертификацию Spring Core, и у меня есть некоторые сомнения относительно того, как Spring обрабатывает жизненный цикл bean-компонентов и, в частности, постпроцессор bean-компонентов .

Итак, у меня есть эта схема:

введите описание изображения здесь

Для меня довольно ясно, что это значит:

На этапе загрузки определений компонентов выполняются следующие шаги :

  • В @Configuration классы обрабатываются и / или @Components проверяются на наличие и / или файлы XML обрабатываются.

  • Определения компонентов, добавленные в BeanFactory (каждое проиндексировано под своим идентификатором)

  • Вызываются специальные bean- компоненты BeanFactoryPostProcessor , они могут изменять определение любого bean-компонента (например, для замены значений свойств-заполнителей).

Затем на этапе создания bean-компонентов выполняются следующие шаги :

  • Каждый bean-компонент активно создается по умолчанию (создается в правильном порядке с введенными зависимостями).

  • После внедрения зависимости каждый компонент проходит стадию постобработки, на которой может происходить дальнейшая настройка и инициализация.

  • После постобработки компонент полностью инициализирован и готов к использованию (отслеживается по его идентификатору до тех пор, пока контекст не будет уничтожен)

Хорошо, для меня это довольно ясно, и я также знаю, что есть два типа постпроцессоров bean-компонентов :

  • Инициализаторы: инициализируйте bean-компонент, если это указано (например, @PostConstruct).

  • и все остальное: которые позволяют дополнительную настройку и могут выполняться до или после шага инициализации.

И выкладываю этот слайд:

введите описание изображения здесь

Поэтому мне очень ясно, что инициализаторы bean- постпроцессоры (это методы, аннотированные аннотацией @PostContruct и автоматически вызываемые сразу после методов установки (то есть после внедрения зависимости), и я знаю, что могу использовать для выполнить некоторый пакет инициализации (как и заполнить кеш, как в предыдущем примере).

Но что именно представляет собой другой постпроцессор bean-компонентов? Что мы имеем в виду, когда говорим, что эти шаги выполняются до или после фазы инициализации ?

Итак, мои bean-компоненты создаются, и их зависимости вводятся, поэтому фаза инициализации завершается (путем выполнения аннотированного метода @PostContruct ). Что мы имеем в виду, говоря, что Bean Post Processor используется до фазы инициализации? Значит, это происходит до выполнения аннотированного метода @PostContruct ? Означает ли это, что это могло произойти до внедрения зависимости (до этого вызываются методы установки)?

И что именно мы имеем в виду, когда говорим, что это выполняется после этапа инициализации . Значит, это происходит после выполнения аннотированного метода @PostContruct , что ли?

Я легко могу понять, почему мне нужен аннотированный метод @PostContruct, но я не могу представить типичный пример другого типа постпроцессора bean, не могли бы вы показать мне типичный пример того, когда они используются?

Андреа Нобили
источник
Я почти уверен, что вы не должны делиться изображениями слайдов :)
Reg
@Reg Из какого именно курса / презентации взяты эти изображения?
Malvon 07
@Malvon Это было из предыдущего выпуска официального основного курса Spring от Pivotal. И, кстати, если вы готовитесь к экзамену, игнорируйте что-либо с XML :)
Reg
@Reg Есть ли способ купить курс, не посещая учебные классы?
Malvon 09
Мне интересно, что происходит в фиолетовой части диаграммы «Определения компонентов постобработки»?
Акшай Хиремат,

Ответы:

50

Документ Spring объясняет BPP в разделе Настройка bean-компонентов с помощью BeanPostProcessor . Бины BPP - это особый вид бинов, которые создаются раньше любых других бинов и взаимодействуют с вновь созданными бинами. Благодаря этой конструкции Spring дает вам возможность подключиться и настроить поведение жизненного цикла, просто реализовав BeanPostProcessorсобственный.

Имея собственный BPP, например

public class CustomBeanPostProcessor implements BeanPostProcessor {

    public CustomBeanPostProcessor() {
        System.out.println("0. Spring calls constructor");
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName)
            throws BeansException {
        System.out.println(bean.getClass() + "  " + beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {
        System.out.println(bean.getClass() + "  " + beanName);
        return bean;
    }
}

будет вызываться и распечатывать имя класса и bean для каждого созданного bean.

Чтобы понять, как метод соответствует жизненному циклу bean-компонента и когда именно вызывается метод, проверьте документацию

postProcessBeforeInitialization (Object bean, String beanName) Примените этот BeanPostProcessor к данному новому экземпляру bean-компонента перед любыми обратными вызовами инициализации bean-компонента (например, afterPropertiesSet InitializingBean или пользовательский метод инициализации).

postProcessAfterInitialization (Object bean, String beanName) Примените этот BeanPostProcessor к данному новому экземпляру bean-компонента после любых обратных вызовов инициализации bean-компонента (например, afterPropertiesSet InitializingBean или настраиваемый метод инициализации).

Важным моментом также является то, что

Компонент уже будет заполнен значениями свойств.

Что касается связи с @PostConstructпримечанием, что эта аннотация является удобным способом объявления postProcessAfterInitializationметода, и Spring узнает об этом, когда вы либо регистрируете, CommonAnnotationBeanPostProcessorлибо указываете <context:annotation-config />файл конфигурации in bean. Будет ли @PostConstructметод выполняться до или после любого другого, postProcessAfterInitializationзависит от orderсвойства

Вы можете настроить несколько экземпляров BeanPostProcessor, и вы можете контролировать порядок, в котором эти BeanPostProcessor выполняются, установив свойство order.

Мастер Раб
источник
31

Типичный пример постпроцессора bean - это когда вы хотите обернуть исходный bean-компонент в экземпляр прокси, например, при использовании @Transactionalаннотации.

Постпроцессору bean-компонента будет передан исходный экземпляр bean-компонента, он может вызывать любые методы на цели, но он также должен возвращать фактический экземпляр bean-компонента, который должен быть привязан в контексте приложения, что означает, что он может фактически вернуть объект он хочет. Типичный сценарий, когда это полезно, - это когда постпроцессор bean-компонента оборачивает цель в экземпляр прокси. Все вызовы bean-компонента, привязанного к контексту приложения, будут проходить через прокси, а затем прокси-сервер сможет выполнить некоторую магию до и / или после вызовов целевого bean-компонента, например, АОП или управление транзакциями.

Мартурссон
источник
6
Престижность за реальный пример!
raiks
спасибо за предоставленный реальный вариант использования, а не только за теорию
Амол Аггарвал
5

Разница в том, что BeanPostProcessorбудет подключаться инициализация контекста, а затем вызов postProcessBeforeInitializationи postProcessAfterInitializationдля всех определенных компонентов.

Но @PostConstructиспользуется только для конкретного класса, для которого вы хотите настроить создание компонента после конструктора или метода установки.

Там Ле
источник