Як саме працює Spring BeanPostProcessor?


94

Я навчаюсь на сертифікації Spring Core, і я маю деякі сумніви щодо того, як Spring обробляє життєвий цикл бобів, і зокрема щодо постпроцесора квасолі .

Отже, у мене є така схема:

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

Для мене цілком зрозуміло, що це означає:

На етапі Визначення компонента завантаження виконуються наступні кроки :

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

  • Визначення Bean, додані до BeanFactory (кожне індексується під своїм ідентифікатором)

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

Потім на етапі створення квасолі виконуються наступні кроки :

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

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

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

Добре, це для мене досить зрозуміло, і я також знаю, що існує два типи процесорів пост-обробки, які:

  • Ініціалізатори: Ініціалізуйте компонент за вказівкою (тобто @PostConstruct).

  • та всі інші: що дозволяють додаткову конфігурацію і які можуть працювати до або після кроку ініціалізації

І я публікую цей слайд:

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

Отже, для мене дуже зрозуміло, що ініціалізатори виконують післяпроцесорні процеси (це методи, котрі анотуються анотацією @PostContruct, і які автоматично викликаються відразу після методів сеттера (тобто після введення залежностей), і я знаю, що я можу використовувати для виконати певний пакет ініціалізації (так само заповнити кеш, як у попередньому прикладі).

Але що саме представляє інший постпроцесор bean? Що ми маємо на увазі, коли говоримо, що ці кроки виконуються до або після фази ініціалізації ?

Отже, мої компоненти створюються за допомогою екземпляра, а його залежності вводяться, тож фаза ініціалізації завершується (виконанням коментованого методу @PostContruct ). Що ми маємо на увазі, кажучи, що процесор поштової передачі Bean використовується до фази ініціалізації? Це означає, що це відбувається до виконання анотованого методу @PostContruct ? Чи означає це, що це могло статися до введення залежності (до цього викликаються методи встановлення)?

І що саме ми маємо на увазі, коли говоримо, що це виконується після кроку ініціалізації . Це означає, що це трапляється після того, що виконання анотованого методу @PostContruct чи що?

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


Я майже впевнений, що ви не повинні ділитися зображеннями слайдів :)
Рег

@Reg З якого саме курсу / презентації походять ці зображення?
Малвон

@Malvon Це було з попереднього видання офіційного базового курсу Pivotal. І
Рег.

@Reg Чи є спосіб придбати курс, не відвідуючи навчальних курсів?
Малвон

Цікаво, що відбувається з тією фіолетовою частиною діаграми “Визначення компонента післяпроцесу”?
Akshay Hiremath

Відповіді:


48

Spring doc пояснює BPP під налаштуванням компонентів за допомогою 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;
    }
}

буде викликано та роздруковано ім'я класу та компонента для кожного створеного компонента.

Щоб зрозуміти, як метод відповідає життєвому циклу квасолі, і коли саме метод викликається, перевірте документи

postProcessBeforeInitialization (Object bean, String beanName) Застосуйте цей BeanPostProcessor до даного нового екземпляра компонента перед будь-якими зворотними викликами ініціалізації компонента (як InitializingBean's afterPropertiesSet або спеціальний метод init).

postProcessAfterInitialization (Object bean, String beanName) Застосуйте цей BeanPostProcessor до даного нового екземпляра компонента після будь-яких зворотних викликів ініціалізації компонента (наприклад InitializingBean's afterPropertiesSet або спеціальний метод init).

Важливий біт також це

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

Що стосується відношення до @PostConstructзауваження, що ця анотація є зручним способом декларування postProcessAfterInitializationметоду, і Spring про це дізнається, коли ви або реєструєтесь, CommonAnnotationBeanPostProcessorабо вказуєте <context:annotation-config />файл конфігурації bean. Чи @PostConstructбуде метод виконуватися до або після будь-якого іншого, postProcessAfterInitializationзалежить від orderвластивості

Ви можете налаштувати кілька екземплярів BeanPostProcessor, і ви можете контролювати порядок, в якому виконуються ці BeanPostProcessors, встановлюючи властивість замовлення.


30

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

Процесору пост-компонентів передається оригінальний екземпляр компонента, він може викликати будь-які методи на цілі, але він також може повернути фактичний екземпляр компонента, який повинен бути прив'язаний у контексті програми, а це означає, що він може фактично повернути будь-який об'єкт, який він хоче. Типовим сценарієм, коли це корисно, є те, коли пост-процесор компонента обгортає ціль екземпляром проксі. Усі виклики на компоненті, прив'язаному в контексті програми, пройдуть через проксі-сервер, і проксі-сервер потім зможе виконати деяку магію до та / або після викликів на цільовому компоненті, наприклад, AOP або управління транзакціями.


6
Похвала для прикладу з реального життя!
raiks

дякую, що надали фактичний варіант використання, а не лише теорію
Амол Аггарвал,

4

Різниця полягає у BeanPostProcessorпідключенні до ініціалізації контексту, а потім виклику postProcessBeforeInitializationтаpostProcessAfterInitialization для всіх визначених компонентів.

Але @PostConstructвін просто використовується для конкретного класу, який ви хочете налаштувати створення компонента після конструктора або методу набору.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.