¿Cómo funciona exactamente Spring BeanPostProcessor?

94

Estoy estudiando para la certificación Spring Core y tengo algunas dudas sobre cómo Spring maneja el ciclo de vida de los beans y, en particular, sobre el postprocesador de beans .

Entonces tengo este esquema:

ingrese la descripción de la imagen aquí

Para mí está bastante claro lo que significa:

Los siguientes pasos tienen lugar en la fase Load Bean Definitions :

  • Las clases de @Configuration se procesan y / o se escanean los @Components y / o se analizan los archivos XML .

  • Definiciones de Bean agregadas a BeanFactory (cada una indexada bajo su ID)

  • BeanFactoryPostProcessor especiales invocados, puede modificar la definición de cualquier bean (por ejemplo, para los reemplazos de valores de marcador de posición de propiedad).

Luego, los siguientes pasos tienen lugar en la fase de creación de beans :

  • Cada bean se instancia ansiosamente por defecto (creado en el orden correcto con sus dependencias inyectadas).

  • Después de la inyección de dependencia, cada bean pasa por una fase de posprocesamiento en la que pueden ocurrir más configuraciones e inicializaciones.

  • Después del posprocesamiento, el bean está completamente inicializado y listo para su uso (seguido por su id hasta que se destruye el contexto)

Ok, esto es bastante claro para mí y también sé que hay dos tipos de postprocesadores de frijoles que son:

  • Inicializadores: Inicialice el bean si se le indica (es decir, @PostConstruct).

  • y todo lo demás: que permiten configuraciones adicionales y que pueden ejecutarse antes o después del paso de inicialización

Y publico esta diapositiva:

ingrese la descripción de la imagen aquí

Entonces, para mí está muy claro qué hacen los inicializadores postprocesadores de frijoles (son los métodos anotados con la anotación @PostContruct y que se llaman automáticamente inmediatamente después de los métodos de establecimiento (es decir, después de la inyección de dependencia), y sé que puedo usar para realizar algún lote de inicialización (como llenar un caché como en el ejemplo anterior).

Pero, ¿qué representa exactamente el otro postprocesador de frijoles? ¿A qué nos referimos cuando decimos que estos pasos se realizan antes o después de la fase de inicialización ?

Entonces, se crean instancias de mis beans y se inyectan sus dependencias, por lo que luego se completa la fase de inicialización (mediante la ejecución de un método anotado @PostContruct ). ¿Qué queremos decir al decir que se utiliza un postprocesador Bean antes de la fase de inicialización? ¿Significa que sucede antes de la ejecución del método anotado @PostContruct ? ¿Significa que podría suceder antes de la inyección de dependencia (antes de que se llamen a los métodos de establecimiento)?

¿Y qué queremos decir exactamente cuando decimos que se realiza después del paso de inicialización ? Significa que sucede después de la ejecución de un método anotado @PostContruct , ¿o qué?

Puedo imaginarme fácilmente por qué necesito un método anotado @PostContruct , pero no puedo encontrar un ejemplo típico del otro tipo de postprocesador de frijoles, ¿puede mostrarme algún ejemplo típico de cuándo se usan?

AndreaNobili
fuente
Estoy bastante seguro de que no deberías compartir las imágenes de las diapositivas :)
Reg
@Reg ¿De qué curso / presentación exacta son estas imágenes?
Malvon
@Malvon Esto fue de la edición anterior del curso básico oficial de primavera de Pivotal. Y BTW - Si se está preparando para el examen, ignorar cualquier cosa con XML :)
Reg
@Reg ¿Hay alguna forma de comprar el curso sin asistir realmente a las clases de formación?
Malvon
Me pregunto ¿Qué sucede en esa parte violeta del diagrama "Definiciones de frijoles posteriores al proceso"?
Akshay Hiremath

Respuestas:

48

Spring doc explica los BPP en Personalización de beans usando BeanPostProcessor . Los frijoles BPP son un tipo especial de frijoles que se crean antes que cualquier otro frijol e interactúan con los frijoles recién creados. Con esta construcción, Spring le brinda los medios para conectarse y personalizar el comportamiento del ciclo de vida simplemente implementando un BeanPostProcessorusted mismo.

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

se llamaría e imprimiría la clase y el nombre del bean para cada bean creado.

Para comprender cómo se ajusta el método al ciclo de vida del bean y cuándo se llama exactamente al método, consulte los documentos

postProcessBeforeInitialization (Object bean, String beanName) Aplique este BeanPostProcessor a la nueva instancia de bean dada antes de cualquier devolución de llamada de inicialización de bean (como el afterPropertiesSet de InitializingBean o un método init personalizado).

postProcessAfterInitialization (Object bean, String beanName) Aplique este BeanPostProcessor a la nueva instancia de bean dada después de cualquier devolución de llamada de inicialización de bean (como el afterPropertiesSet de InitializingBean o un método init personalizado).

Lo importante también es que

El bean ya estará poblado con valores de propiedad.

Por lo que se refiere a la relación con la @PostConstructnota, esta anotación es una forma conveniente de declarar un postProcessAfterInitializationmétodo, y Spring se da cuenta de ello cuando se registra CommonAnnotationBeanPostProcessoro especifica el <context:annotation-config />archivo de configuración del bean. Si el @PostConstructmétodo se ejecutará antes o después de cualquier otro postProcessAfterInitializationdepende de la orderpropiedad

Puede configurar varias instancias de BeanPostProcessor y puede controlar el orden en el que se ejecutan estos BeanPostProcessors estableciendo la propiedad order.

Maestro-esclavo
fuente
30

El ejemplo típico de un postprocesador de frijoles es cuando desea envolver el bean original en una instancia de proxy, por ejemplo, cuando usa la @Transactionalanotación.

Al postprocesador de frijoles se le entregará la instancia original del frijol, puede llamar a cualquier método en el objetivo, pero también puede devolver la instancia de frijol real que debería estar vinculada en el contexto de la aplicación, lo que significa que en realidad puede devolver cualquier objeto que quiere. El escenario típico cuando esto es útil es cuando el postprocesador del bean envuelve el destino en una instancia de proxy. Todas las invocaciones en el bean enlazado en el contexto de la aplicación pasarán a través del proxy, y el proxy podrá realizar algo de magia antes y / o después de las invocaciones en el bean de destino, por ejemplo, AOP o gestión de transacciones.

marthursson
fuente
6
¡Felicitaciones por un ejemplo de la vida real!
raiks
gracias por proporcionar un caso de uso real y no solo teoría
Amol Aggarwal
4

La diferencia es que BeanPostProcessorse conectará a la inicialización del contexto y luego llamará postProcessBeforeInitializationy postProcessAfterInitializationpara todos los beans definidos.

Pero @PostConstructsolo se usa para la clase específica que desea personalizar la creación de bean después del constructor o el método establecido.

Tam Le
fuente