Wie genau funktioniert der Spring BeanPostProcessor?

94

Ich studiere für die Spring Core-Zertifizierung und habe einige Zweifel daran, wie Spring mit dem Bohnen-Lebenszyklus und insbesondere mit dem Bohnen-Postprozessor umgeht .

Also habe ich dieses Schema:

Geben Sie hier die Bildbeschreibung ein

Mir ist ziemlich klar, was es bedeutet:

Die folgenden Schritte finden in der Phase Load Bean-Definitionen statt :

  • Die @ Configuration- Klassen werden verarbeitet und / oder @Components werden durchsucht und / oder XML-Dateien werden analysiert.

  • BeanFactory hinzugefügte Bean-Definitionen (jede unter ihrer ID indiziert)

  • Besondere BeanFactoryPostProcessor- Beans, die aufgerufen werden, können die Definition jeder Bean ändern (z. B. für das Ersetzen von Eigenschaftsplatzhalterwerten).

Dann finden die folgenden Schritte in der statt Phase :

  • Jede Bean wird standardmäßig eifrig instanziiert (in der richtigen Reihenfolge mit eingespeisten Abhängigkeiten erstellt).

  • Nach der Abhängigkeitsinjektion durchläuft jede Bean eine Nachbearbeitungsphase, in der eine weitere Konfiguration und Initialisierung erfolgen kann.

  • Nach der Nachbearbeitung ist die Bean vollständig initialisiert und einsatzbereit (wird anhand ihrer ID verfolgt, bis der Kontext zerstört ist).

Ok, das ist mir ziemlich klar und ich weiß auch, dass es zwei Arten von Bean-Postprozessoren gibt:

  • Initialisierer: Initialisieren Sie die Bean, wenn Sie dazu aufgefordert werden (dh @PostConstruct).

  • und alles andere: Diese ermöglichen eine zusätzliche Konfiguration und können vor oder nach dem Initialisierungsschritt ausgeführt werden

Und ich poste diese Folie:

Geben Sie hier die Bildbeschreibung ein

Es ist mir also sehr klar, was die Initialisierer bewirken Bean- Postprozessoren tun (dies sind die mit @ PostContruct- Annotation annotierten Methoden , die automatisch unmittelbar nach den Setter-Methoden (also nach der Abhängigkeitsinjektion) aufgerufen werden, und ich weiß, dass ich sie verwenden kann Führen Sie einen Initialisierungsstapel durch (füllen Sie einen Cache wie im vorherigen Beispiel).

Aber was genau repräsentiert den anderen Bean-Postprozessor? Was meinen wir, wenn wir sagen, dass diese Schritte ausgeführt werden? vor oder nach der Initialisierungsphase ausgeführt werden ?

Meine Beans werden instanziiert und ihre Abhängigkeiten werden injiziert, sodass die Initialisierungsphase abgeschlossen ist (durch Ausführen einer mit @PostContruct annotierten Methode). Was meinen wir damit, dass vor der Initialisierungsphase ein Bean-Postprozessor verwendet wird? Es bedeutet, dass es vor dem passiert @PostContruct kommentierten Methodenausführung ? Bedeutet dies, dass dies vor der Abhängigkeitsinjektion geschehen könnte (bevor die Setter-Methoden aufgerufen werden)?

Und was genau meinen wir, wenn wir sagen, dass es nach dem Initialisierungsschritt ausgeführt wird . Dies bedeutet, dass danach eine mit @PostContruct annotierte Methode ausgeführt wird, oder was?

Ich kann mir leicht vorstellen, warum ich eine mit @PostContruct kommentierte Methode benötige , aber ich kann kein typisches Beispiel für die andere Art von Bean- Postprozessor finden. Können Sie mir ein typisches Beispiel für die Verwendung zeigen?

AndreaNobili
quelle
Ich bin mir ziemlich sicher, dass Sie die Bilder der Folien nicht teilen sollten :)
Reg
@Reg Aus welchem ​​genauen Kurs / welcher Präsentation stammen diese Bilder?
Malvon
@Malvon Dies war aus der vorherigen Ausgabe von Pivotals offiziellem Spring Core-Kurs. UND Übrigens - Wenn Sie sich auf die Prüfung vorbereiten, ignorieren Sie alles mit XML :)
Reg
@Reg Gibt es eine Möglichkeit, den Kurs zu kaufen, ohne tatsächlich an den Schulungskursen teilzunehmen?
Malvon
Ich frage mich, was in diesem lila Teil des Diagramms „Bean-Definitionen nach dem Prozess“ passiert.
Akshay Hiremath

Antworten:

48

Spring doc erläutert die BPPs unter Anpassen von Beans mit BeanPostProcessor . BPP-Beans sind eine spezielle Art von Beans, die vor allen anderen Beans erstellt werden und mit neu erstellten Beans interagieren. Mit diesem Konstrukt können Sie mit Spring das Lebenszyklusverhalten einfach durch Implementieren von a verbinden und anpassenBeanPostProcessor .

Mit einem benutzerdefinierten BPP wie

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

würde aufgerufen werden und den Klassen- und Bean-Namen für jede erstellte Bean ausdrucken.

Um zu verstehen, wie die Methode zum Lebenszyklus der Bean passt und wann genau die Methode aufgerufen wird, überprüfen Sie die Dokumente

postProcessBeforeInitialization (Object Bean, String BeanName) Wenden Sie diesen BeanPostProcessor vor Rückrufen der Bean-Initialisierung auf die angegebene neue Bean-Instanz an (z. B. AfterPropertiesSet von InitializingBean oder eine benutzerdefinierte Init-Methode).

postProcessAfterInitialization (Object Bean, String BeanName) Wenden Sie diesen BeanPostProcessor nach Rückrufen der Bean-Initialisierung auf die angegebene neue Bean-Instanz an (z. B. AfterPropertiesSet von InitializingBean oder eine benutzerdefinierte Init-Methode).

Das Wichtige ist auch das

Die Bean wird bereits mit Eigenschaftswerten gefüllt.

Was die Beziehung zu dem @PostConstructHinweis betrifft , dass diese Annotation eine bequeme Methode zum Deklarieren einer postProcessAfterInitializationMethode ist, wird Spring darauf aufmerksam, wenn Sie entweder CommonAnnotationBeanPostProcessordie <context:annotation-config />In-Bean-Konfigurationsdatei registrieren oder angeben . Ob die @PostConstructMethode vor oder nach einer anderen Methode ausgeführt wird, postProcessAfterInitializationhängt von der orderEigenschaft ab

Sie können mehrere BeanPostProcessor-Instanzen konfigurieren und die Reihenfolge steuern, in der diese BeanPostProcessors ausgeführt werden, indem Sie die order-Eigenschaft festlegen.

Master Slave
quelle
30

Das typische Beispiel für einen Bean-Postprozessor ist, wenn Sie die ursprüngliche Bean in eine Proxy-Instanz einschließen möchten, z. B. wenn Sie die verwenden @Transactional Annotation verwenden.

Dem Bean-Postprozessor wird die ursprüngliche Instanz der Bean übergeben. Er kann beliebige Methoden auf dem Ziel aufrufen, kann aber auch die tatsächliche Bean-Instanz zurückgeben, die im Anwendungskontext gebunden werden soll, was bedeutet, dass er tatsächlich eine beliebige zurückgeben kann Objekt, das es will. Das typische Szenario, in dem dies nützlich ist, besteht darin, dass der Bean-Postprozessor das Ziel in eine Proxy-Instanz einschließt. Alle Aufrufe auf der Bean, die im Anwendungskontext gebunden sind, werden über den Proxy geleitet, und der Proxy kann vor und / oder nach Aufrufen auf der Ziel-Bean, z. B. AOP oder Transaktionsverwaltung, etwas Magie ausführen.

marthursson
quelle
6
Ein großes Lob für ein reales Beispiel!
Raiks
Vielen Dank für die Bereitstellung des tatsächlichen Anwendungsfalls und nicht nur der Theorie
Amol Aggarwal
4

Der Unterschied besteht darin, dass BeanPostProcessordie Kontextinitialisierung aktiviert postProcessBeforeInitializationund dann postProcessAfterInitializationfür alle definierten Beans aufgerufen wird .

Wird @PostConstructjedoch nur für die bestimmte Klasse verwendet, für die Sie die Bean-Erstellung nach dem Konstruktor oder der Set-Methode anpassen möchten.

Tam Le
quelle