web-dev-qa-db-fra.com

Comment fonctionne exactement le Spring BeanPostProcessor?

J'étudie actuellement pour obtenir la certification Spring Core et j’ai quelques doutes sur la façon dont Spring gère le cycle de vie des beans et en particulier sur le post-traitement des beans.

J'ai donc ce schéma:

enter image description here

C'est assez clair pour moi ce que cela signifie:

Les étapes suivantes ont lieu dans la phase Load Bean Definitions:

  • Les classes @ Configuration sont traitées et/ou @ Composants sont analysées et/ou fichiers XML sont analysées.

  • Définitions de bean ajoutées à BeanFactory (chacune indexée sous son id)

  • Beans spéciaux BeanFactoryPostProcessor invoqués, il peut modifier la définition de n'importe quel bean (par exemple pour les remplacements de valeurs d'espace réservé de propriété).

Ensuite, les étapes suivantes ont lieu dans le phase de création des beans:

  • Chaque bean est instancié instinctivement par défaut (créé dans le bon ordre avec ses dépendances injectées).

  • Après l'injection de dépendance, chaque haricot passe par une phase de post-traitement au cours de laquelle une configuration et une initialisation supplémentaires peuvent se produire.

  • Après le post-traitement, le bean est complètement initialisé et prêt à être utilisé (suivi par son identifiant jusqu'à la destruction du contexte)

Ok, c'est assez clair pour moi et je sais aussi que il y a deux types de post-processeurs de haricots qui sont:

  • Initializer: Initialise le bean si demandé (c'est-à-dire @PostConstruct).

  • et Tout le reste: qui permet une configuration supplémentaire et que peut s'exécuter avant ou après l'étape d'initialisation

Et je poste cette diapositive:

enter image description here

Donc, il est très clair pour moi ce que font les post-processeurs initialiseurs (ce sont les méthodes annotées avec une annotation @ PostContruct et qui sont automatiquement appelées immédiatement après les méthodes setter (donc après l'injection de dépendance), et je sais que je peux utiliser certains lots d'initialisation (pour remplir un cache comme dans l'exemple précédent).

Mais que représente exactement l'autre post-processeur de haricot? Que voulons-nous dire quand nous disons que ces étapes sont effectuées avant ou après la phase d’initialisation?

Donc, mes beans sont instanciés et ses dépendances sont injectées, la phase d'initialisation est donc terminée (par l'exécution d'une méthode @ PostContruct annotée). Que voulons-nous dire en disant qu'un post processeur Bean est utilisé avant la phase d'initialisation? Cela signifie que cela se produit avant l'exécution de la méthode annotée @ PostContruct? Cela signifie-t-il que cela pourrait se produire avant l'injection de dépendance (avant que les méthodes de définition ne soient appelées)?

Et qu'est-ce qu'on veut dire exactement quand on dit que c'est effectué après l'étape d'initialisation. Cela signifie que cela se produit après que l'exécution d'une méthode annotée @ PostContruct, ou quoi?

Je peux facilement comprendre pourquoi j’ai besoin d’une méthode @ PostContruct annotée, mais je ne peux pas comprendre un exemple typique de l’autre type de post-traitement de haricots. Pouvez-vous me montrer un exemple typique de quand utilisé?

77
AndreaNobili

La documentation Spring explique les BPP sous Personnalisation des beans à l'aide de BeanPostProcessor . Les haricots BPP sont un type spécial de haricots qui sont créés avant tout autre haricot et interagissent avec les haricots nouvellement créés. Avec cette construction, Spring vous donne le moyen de vous connecter et de personnaliser le comportement du cycle de vie simplement en implémentant vous-même un BeanPostProcessor.

Avoir un BPP personnalisé comme

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

sera appelé et affichera le nom de la classe et du bean pour chaque bean créé.

Pour comprendre comment la méthode correspond au cycle de vie du bean, et quand exactement la méthode est appelée, cochez docs

postProcessBeforeInitialization (Bean Object, String beanName) Applique ce BeanPostProcessor à la nouvelle instance de bean donnée avant tout rappel d'initialisation de bean (comme après afterPropertiesSet de InitializingBean ou une méthode d'initialisation personnalisée. ).

postProcessAfterInitialization (Bean Object, String beanName) Applique ce BeanPostProcessor à la nouvelle instance de bean donnée après tout rappel d'initialisation de bean (comme après afterPropertiesSet d'InitializingBean ou une méthode d'initialisation personnalisée. ).

Le bit important est aussi que

Le bean sera déjà rempli avec les valeurs de propriété.

En ce qui concerne la relation avec le @PostConstruct, Notez que cette annotation est un moyen pratique de déclarer une méthode postProcessAfterInitialization, et Spring en prend conscience lorsque vous enregistrez CommonAnnotationBeanPostProcessor ou spécifiez le <context:annotation-config /> dans le fichier de configuration du bean. Que la méthode @PostConstruct Soit exécutée avant ou après tout autre postProcessAfterInitialization dépend de la propriété order

Vous pouvez configurer plusieurs instances de BeanPostProcessor et vous pouvez contrôler l'ordre dans lequel ces BeanPostProcessors s'exécutent en définissant la propriété order.

38
Master Slave

L’exemple typique d’un post-traitement de bean est le moment où vous souhaitez envelopper le bean original dans une instance de proxy, par exemple. en utilisant le @Transactional annotation.

Le postprocesseur de bean reçoit l'instance d'origine du bean, il peut appeler n'importe quelle méthode de la cible, mais il renvoie également l'instance de bean réelle qui doit être liée dans le contexte de l'application, ce qui signifie qu'elle peut en réalité renvoyer toute objet qu'il veut. Le scénario typique lorsque cela est utile est lorsque le post-processeur de bean encapsule la cible dans une instance de proxy. Toutes les invocations sur le bean lié dans le contexte de l’application passeront par le proxy, lequel procèdera ensuite à une certaine magie avant et/ou après les invocations sur le bean cible, par exemple. AOP ou gestion des transactions.

25
marthursson

La différence est que BeanPostProcessor se connecte à l'initialisation du contexte, puis appelle postProcessBeforeInitialization et postProcessAfterInitialization pour tous les beans définis.

Mais @PostConstruct est uniquement utilisé pour la classe spécifique pour laquelle vous souhaitez personnaliser la création de bean après le constructeur ou la méthode set.

3
Tam Le