Jak dokładnie działa Spring BeanPostProcessor?

97

Studiuję do uzyskania certyfikatu Spring Core i mam pewne wątpliwości co do tego, jak Spring radzi sobie z cyklem życia ziaren, aw szczególności z postprocesorem fasoli .

Więc mam taki schemat:

wprowadź opis obrazu tutaj

Jest dla mnie całkiem jasne, co to oznacza:

W fazie ładowania definicji komponentów bean wykonywane są następujące kroki :

  • W @Configuration zajęcia są przetwarzane i / lub @Components są skanowane pod kątem i / lub pliki XML są analizowane.

  • Definicje Bean dodane do BeanFactory (każda zindeksowana pod swoim identyfikatorem)

  • Wywołana specjalna fasola BeanFactoryPostProcessor może zmodyfikować definicję dowolnego komponentu bean (na przykład w celu zastąpienia wartości zastępczej właściwości).

Następnie w fazie tworzenia fasoli mają miejsce następujące kroki :

  • Każda fasola jest domyślnie tworzona z niecierpliwością (tworzona we właściwej kolejności z wstrzykniętymi zależnościami).

  • Po wstrzyknięciu zależności każde ziarno przechodzi przez fazę przetwarzania końcowego, w której może nastąpić dalsza konfiguracja i inicjalizacja.

  • Po przetworzeniu końcowym ziarno jest w pełni zainicjowane i gotowe do użycia (śledzone przez jego identyfikator, aż do zniszczenia kontekstu)

Ok, jest to dla mnie całkiem jasne i wiem też, że istnieją dwa typy postprocesorów fasoli :

  • Inicjalizatory: Inicjalizacja fasoli jeśli polecił (tj @PostConstruct).

  • i Cała reszta: pozwala na dodatkową konfigurację i może działać przed lub po kroku inicjalizacji

I publikuję ten slajd:

wprowadź opis obrazu tutaj

Więc jest dla mnie bardzo jasne, co inicjalizatory bean postprocesorów (są to metody z adnotacją @PostContruct i które są automatycznie wywoływane natychmiast po metodach ustawiających (czyli po wstrzyknięciu zależności) i wiem, że mogę użyć do wykonać partię inicjalizacyjną (zapełnij pamięć podręczną, jak w poprzednim przykładzie).

Ale co dokładnie reprezentuje drugi postprocesor fasoli? Co mamy na myśli, gdy mówimy, że te kroki są wykonywane przed lub po fazie inicjalizacji ?

Więc moje ziarna są tworzone, a ich zależności są wstrzykiwane, więc faza inicjalizacji jest zakończona (przez wykonanie metody z adnotacjami @PostContruct ). Co mamy na myśli, mówiąc, że postprocesor Bean jest używany przed fazą inicjalizacji? Oznacza to, że dzieje się to przed wykonaniem metody z adnotacjami @PostContruct ? Czy to oznacza, że ​​może się to zdarzyć przed wstrzyknięciem zależności (przed wywołaniem metod ustawiających)?

A co dokładnie mamy na myśli, gdy mówimy, że jest to wykonywane po kroku inicjalizacji . Oznacza to, że dzieje się to po wykonaniu metody z adnotacjami @PostContruct , czy co?

Mogę łatwo zrozumieć, dlaczego potrzebuję metody z adnotacjami @PostContruct , ale nie mogę znaleźć typowego przykładu innego rodzaju postprocesora fasoli, czy możesz mi pokazać typowy przykład kiedy są używane?

AndreaNobili
źródło
Jestem pewien, że nie powinieneś udostępniać zdjęć ze slajdów :)
Rej
@Reg Z jakiego dokładnie kursu / prezentacji pochodzą te obrazy?
Malvon,
@Malvon To było z poprzedniej edycji oficjalnego wiosennego kursu podstawowego firmy Pivotal. ORAZ BTW - Jeśli przygotowujesz się do egzaminu, zignoruj ​​wszystko z XML :)
Reg.
@Reg Czy jest sposób na zakup kursu bez faktycznego uczęszczania na zajęcia szkoleniowe?
Malvon,
Zastanawiam się, co się dzieje w tej fioletowej części diagramu „Definicje fasoli po zakończeniu procesu”?
Akshay Hiremath

Odpowiedzi:

50

Dokument Spring wyjaśnia BPP w sekcji Dostosowywanie ziaren przy użyciu BeanPostProcessor . Ziarna BPP to specjalny rodzaj ziaren, które powstają przed innymi ziarnami i wchodzą w interakcję z nowo powstałymi ziarnami. Dzięki tej konstrukcji Spring umożliwia podłączenie i dostosowanie zachowania cyklu życia po prostu przez zaimplementowanie BeanPostProcessorsiebie.

Posiadanie niestandardowego BPP, takiego jak

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;
    }
}

zostanie wywołana i wydrukuje klasę i nazwę fasoli dla każdego utworzonego ziarna.

Aby dowiedzieć się, jak metoda pasuje do cyklu życia fasoli i kiedy dokładnie metoda jest wywoływana, sprawdź dokumentację

postProcessBeforeInitialization (Object bean, String beanName) Zastosuj ten BeanPostProcessor do danej nowej instancji bean przed jakimikolwiek wywołaniami zwrotnymi inicjalizacji fasoli (np. afterPropertiesSet InitializingBean lub niestandardowa metoda init).

postProcessAfterInitialization (Object bean, String beanName) Zastosuj ten BeanPostProcessor do danej nowej instancji bean po wszelkich wywołaniach zwrotnych inicjalizacji fasoli (takich jak afterPropertiesSet InitializingBean lub niestandardowa metoda init).

Ważne jest również to

Fasola będzie już wypełniona wartościami właściwości.

Jeśli chodzi o związek z @PostConstructuwagą, ta adnotacja jest wygodnym sposobem zadeklarowania postProcessAfterInitializationmetody, a Spring zdaje sobie z tego sprawę, kiedy albo rejestrujesz się, CommonAnnotationBeanPostProcessoralbo określasz <context:annotation-config />plik konfiguracyjny w beanie. To, czy @PostConstructmetoda zostanie wykonana przed, czy po jakiejkolwiek innej, postProcessAfterInitializationzależy od orderwłaściwości

Możesz skonfigurować wiele instancji BeanPostProcessor i możesz kontrolować kolejność wykonywania tych BeanPostProcessors, ustawiając właściwość order.

Master Slave
źródło
31

Typowym przykładem postprocesora fasoli jest sytuacja, gdy chcesz zawinąć oryginalny bean w instancję proxy, np. Podczas korzystania z @Transactionaladnotacji.

Postprocesor bean otrzyma oryginalną instancję fasoli, może wywołać dowolne metody w miejscu docelowym, ale może również zwrócić rzeczywistą instancję fasoli, która powinna być powiązana w kontekście aplikacji, co oznacza, że ​​może faktycznie zwrócić dowolną obiekt, którego chce. Typowym scenariuszem, w którym jest to przydatne, jest sytuacja, gdy postprocesor fasoli opakowuje obiekt docelowy w instancję proxy. Wszystkie wywołania komponentu bean związanego w kontekście aplikacji będą przechodzić przez proxy, a następnie proxy będzie mogło wykonać magię przed i / lub po wywołaniach na docelowym beanie, np. AOP lub zarządzanie transakcjami.

marthursson
źródło
6
Uznanie za przykład z życia wzięty!
raiks
dzięki za przedstawienie rzeczywistego przypadku użycia, a nie tylko teorii
Amol Aggarwal
5

Różnica polega na tym, BeanPostProcessorże podłączy się do inicjalizacji kontekstu, a następnie wywoła postProcessBeforeInitializationi postProcessAfterInitializationdla wszystkich zdefiniowanych komponentów bean.

Ale @PostConstructjest używany tylko dla określonej klasy, którą chcesz dostosować tworzenie bean po konstruktorze lub metodzie set.

Tam Le
źródło