Como exatamente funciona o Spring BeanPostProcessor?

94

Estou estudando para a certificação Spring Core e tenho algumas dúvidas sobre como o Spring lida com o ciclo de vida dos beans e, em particular, sobre o pós-processador do bean .

Então, eu tenho este esquema:

insira a descrição da imagem aqui

É muito claro para mim o que significa:

As etapas a seguir ocorrem na fase de Definições do bean de carregamento :

  • As classes @Configuration são processadas e / ou @Components são verificados e / ou arquivos XML são analisados.

  • Definições de bean adicionadas ao BeanFactory (cada um indexado sob seu id)

  • Beans BeanFactoryPostProcessor especiais chamados, ele pode modificar a definição de qualquer bean (por exemplo, para as substituições de valores de placeholder de propriedade).

Em seguida, as seguintes etapas ocorrem na fase de criação de feijão :

  • Cada bean é instanciado avidamente por padrão (criado na ordem correta com suas dependências injetadas).

  • Após a injeção de dependência, cada bean passa por uma fase de pós-processamento em que configuração e inicialização adicionais podem ocorrer.

  • Após o pós-processamento, o bean é totalmente inicializado e pronto para uso (rastreado por seu id até que o contexto seja destruído)

Ok, isso está muito claro para mim e também sei que existem dois tipos de pós-processadores de feijão :

  • Inicializadores: inicializam o bean se instruído (isto é, @PostConstruct).

  • e Todo o resto: que permite configuração adicional e que pode ser executado antes ou depois da etapa de inicialização

E eu posto este slide:

insira a descrição da imagem aqui

Portanto, está muito claro para mim o que os inicializadores bean post processors (eles são os métodos anotados com a anotação @PostContruct e que são chamados automaticamente imediatamente após os métodos setter (após a injeção de dependência), e eu sei que posso usar para execute algum lote de inicialização (como preencher um cache como no exemplo anterior).

Mas o que exatamente representa o outro pós-processador de bean? O que queremos dizer quando afirmamos que essas etapas são realizadas antes ou depois da fase de inicialização ?

Portanto, meus beans são instanciados e suas dependências são injetadas, então a fase de inicialização é concluída (pela execução de um método anotado @PostContruct ). O que queremos dizer ao dizer que um Bean Post Processor é usado antes da fase de inicialização? Isso significa que isso acontece antes da execução do método anotado @PostContruct ? Isso significa que pode acontecer antes da injeção de dependência (antes que os métodos setter sejam chamados)?

E o que exatamente queremos dizer quando dizemos que é executado após a etapa de inicialização . Significa que depois disso ocorre a execução de um método anotado @PostContruct , ou o quê?

Posso imaginar facilmente por que preciso de um método anotado @PostContruct , mas não consigo imaginar algum exemplo típico do outro tipo de pós-processador de bean. Você pode me mostrar algum exemplo típico de quando são usados?

AndreaNobili
fonte
Tenho certeza que você não deveria compartilhar as imagens dos slides :)
Reg
@Reg De que curso / apresentação exata são essas imagens?
Malvon
@Malvon Isso era da edição anterior do curso básico oficial da Pivotal. E BTW - Se você estiver se preparando para o exame, ignore qualquer coisa com XML :)
Reg
@Reg Existe uma maneira de adquirir o curso sem realmente assistir às aulas de treinamento?
Malvon
Estou me perguntando o que acontece naquela parte roxa do diagrama “Post process Bean Definitions”?
Akshay Hiremath

Respostas:

48

Spring doc explica os BPPs em Customizando Beans usando BeanPostProcessor . Os beans BPP são um tipo especial de beans que são criados antes de quaisquer outros beans e interagem com os beans recém-criados. Com essa construção, o Spring oferece meios para conectar e personalizar o comportamento do ciclo de vida simplesmente implementando um BeanPostProcessorvocê mesmo.

Ter um BPP personalizado como

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

seria chamado e imprimiria a classe e o nome do bean para cada bean criado.

Para entender como o método se encaixa no ciclo de vida do bean, e quando exatamente o método é chamado, verifique os documentos

postProcessBeforeInitialization (Object bean, String beanName) Aplique este BeanPostProcessor à nova instância de bean fornecida antes de qualquer callback de inicialização de bean (como afterPropertiesSet de InitializingBean ou um método init customizado).

postProcessAfterInitialization (Object bean, String beanName) Aplique este BeanPostProcessor à nova instância de bean fornecida após qualquer callback de inicialização de bean (como afterPropertiesSet de InitializingBean ou um método init customizado).

O importante também é que

O bean já estará preenchido com valores de propriedade.

No que diz respeito à relação com a @PostConstructnota, essa anotação é uma maneira conveniente de declarar um postProcessAfterInitializationmétodo, e o Spring toma conhecimento disso quando você registra CommonAnnotationBeanPostProcessorou especifica o <context:annotation-config />arquivo de configuração do bean. Se o @PostConstructmétodo será executado antes ou depois de qualquer outro postProcessAfterInitializationdepende da orderpropriedade

Você pode configurar várias instâncias de BeanPostProcessor e pode controlar a ordem na qual esses BeanPostProcessors são executados definindo a propriedade order.

Senhor de escravos
fonte
30

O exemplo típico de um pós-processador de bean é quando você deseja envolver o bean original em uma instância de proxy, por exemplo, ao usar a @Transactionalanotação.

O pós-processador do bean receberá a instância original do bean, ele pode chamar quaisquer métodos no destino, mas também consegue retornar a instância do bean real que deve ser ligada no contexto do aplicativo, o que significa que pode realmente retornar qualquer objeto que deseja. O cenário típico quando isso é útil é quando o pós-processador do bean envolve o destino em uma instância de proxy. Todas as invocações no bean vinculado ao contexto do aplicativo passarão pelo proxy, e o proxy então executa alguma mágica antes e / ou depois das invocações no bean de destino, por exemplo, AOP ou gerenciamento de transação.

marthursson
fonte
6
Parabéns por um exemplo da vida real!
raiks de
obrigado por fornecer o caso de uso real e não apenas a teoria
Amol Aggarwal
4

A diferença é que BeanPostProcessorse conectará à inicialização do contexto postProcessBeforeInitializatione, postProcessAfterInitializationem seguida, chamará e para todos os beans definidos.

Mas @PostConstructé usado apenas para a classe específica que você deseja personalizar a criação do bean após o construtor ou método de definição.

Tam Le
fonte