Ciclo de vida Bean

En esta entrada vamos a ver la secuencia de procesos (ciclo de vida) que sigue Spring para administrar los beans de la aplicación. Spring somete al bean a procesos secuenciales desde que lo instancia hasta cuando lo destruye. Veamos el siguiente grafico:

Ciclo de vida Bean

La imagen anterior muestra todo el ciclo de vida de un bean, desde que es instanciado hasta cuando es destruido. Spring maneja la totalidad del ciclo de vida de los beans singleton, para los beans prototype Spring no gestiona la totalidad del ciclo de vida del bean(una vez es entregado al cliente, el contenedor no tiene mas registros de él).

# Ciclo Descripción
1 Abrir Contenedor Crea una instancia del contenedor Spring mediante los metadatos de configuración
2 Instanciar Bean El contenedor Spring crea el bean(no inyecta las propiedades aún)
3 Llenar propiedades Spring inyecta todas las propiedades requeridas por el bean.
4 Procesar Bean En este paso Spring realiza algúnos procesos mas que nada orientados a obtener informacion del propio bean y del contenedor. Si deseas profundizar en este paso, mira este post
5 Inicializar Bean Permite realizar cierto trabajo de inicialización del bean(abrir conexiones, rellenar modelo, etc.) después de se hayan establecido todas las propiedades necesarias en el bean.
6 Bean listo El bean esta completamente configurado y ensamblado, listo para ser utilizado
7 Bean utilizado El bean es utilizado por el cliente. Si es un bean prototype, su ciclo de vida finaliza alli, el cliente será el responsable de la gestion de la vida posterior del bean.
8 Cache singleton Los bean con scope singleton serán almacenamos aquí.
9 Cerrar contenedor Una vez se llame al método context.close(), el contenedor Spring será destruido incluido los beans manejados por él.
10 Destrucción bean El bean puede realizar ciertas tareas despúes de la destrucción del contenedor Spring(contiene al bean), por lo general tareas para liberar recursos.

Callbacks de creación y destrucción de beans

Cuando Spring crea un nuevo bean, configura y ensambla el bean de acuerdo con los metadatos de configuración, pero puede ser necesario realizar tareas adicionales de configuración antes de que el bean este listo para ser utilizado, de la misma manera, realizar tareas antes de que el bean sea destruido, por ejemplo, liberar recursos.

Spring nos proporciona algunos mecanismos para interactuar con el ciclo de vida de los beans administrados por el contenedor. Las callbacks o métodos de retrollamada permiten notificar al bean el momento de su creación y destrucción.

Veamos las alternativas disponibles para notificar al bean :

  1. Interfaz para notificaciones
  2. Métodos notificados a través de metadatos de configuración
  3. Métodos notificados mediante anotaciones JSR-250

Vamos a continuar trabajando con el ejemplo anterior app-persona para implementar las callbacks de creación y destrucción

Interfaz de notificaciones

Spring dispone de las intefaces InitializingBean y DisposableBean, la primera con el método afterPropertiesSet() que es llamado una vez el bean haya sido instanciado y sus propiedades asignadas totalmente, la segunda con el método destroy() que es llamado una vez el contenedor Spring haya sido destruido.

Vamos a implementarlar las intefaces anteriores sobre la clase ProfesionPoliciaImpl.

public class ProfesionPoliciaImpl implements Profesion, InitializingBean, DisposableBean{
    @Override
    public void afterPropertiesSet() throws Exception{ 	
        System.out.println("Inicialización mediante  InitializingBean");
        // Tareas de inicializacion 
    }
    
     @Override
    public void destroy() throws Exception{ 	
        System.out.println("Bean destruido DisposableBean");
        // Tareas de limpieza 
    }
    //.....
}

No se recomienda implementar las callback a tráves de InitilizinBean ni InitializingBean ya que acoplan innecesariamente el código a Spring.

Métodos notificados mediante metadatos de configuración

Otra alternativa para notificar al bean, consiste en definir un método propio tanto de inicialización como destrucción y luego ser referenciados desde los metadatos de configuración del bean a través de los atributos init-method y destroy-method.

Los métodos deben cumplir las siguientes reglas:

  • Modificador de acceso (public, private, protected, etc), por convención suelen ser public.
  • Pueden tener cualquier nombre, por convención son llamados init y destroy para la inicialización y destrucción respectivamente.
  • Pueden tener valor de retorno, por lo general suelen ser sin retorno(void).

En la clase Direccion vamos a crear los métodos init() y destroy().

public class Direccion{
    public void init(){ 	
        System.out.println("Inicialización mediante  método propio");
        // Tareas de inicializacion 
    }
    public void destroy(){ 	
        System.out.println("Bean destruido  método propio");
        // Tareas de limpieza 
    }
    //.....
}

En la definición del bean agregamos los atributos init-method y destroy-method y los referenciamos a los metodos init y destroy.

 <bean id="miDireccion" class="com.curso.spring.Direccion"  scope="prototype"  init-method="init" destroy-method="destroy" />		 

Si ejecutas la aplicación, podrás notar que el mensaje del método destroy() no se imprime, esto se debe a que el bean miDireccion es prototype, Spring no maneja el ciclo de destrucción de un bean prototype.

Si además de los métodos propios, el bean implementa las interfaces InitializingBean y DisposableBean, estas ejecutarán sus métodos afterPropertiesSet () y destroy() primero.

Métodos notificados mediante anotaciones JSR-250

Las anotaciones @PostConstruct y @PreDestroy son otra alternativa para manejar la inicialización y destrucción de los beans, estas son parte de la especificación JSR-250 de plataforma Java EE.

De la misma manera que la alternativa anterior, se debe definir un método propio para ser anotado con @PostConstruct y otro para @PreDestroy. Sobre la clase Persona crearemos estos dos métodos.

public class Persona{
  @PostConstruct
    public void init(){ 	
        System.out.println("Inicializando Persona con  @PostConstruct");
        // Tareas de inicializacion 
    }
    @PreDestroy
    public void destroy(){ 	
        System.out.println("Liberando recurso de Persona con @PreDestroy");
        // Tareas de limpieza 
    }
    //.....
}

Detalles importantes de esta alternativa:

Si trabaja con una versión de Java 8.x.y, no tendrá que realizar nada más, pero si trabaja con una versión de Java 9 o superior, tenga presente que para estas versiones la plataforma Java EE quedo obsoleta, por ello debe realizar lo siguiente para que las anotaciones anteriores funcionen:

  • Agregar dependencia en el pom.xml

    <dependency> 
            <groupId>javax.annotation</groupId>
            <artifactId>javax.annotation-api</artifactId>
            <version>1.3.2</version>
    </dependency > 
    
  • Agregar una definición de bean CommonAnnotationBeanPostProcessor de Spring, para activar el comportamiento de las anotaciones.

     <bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />		 
    

    Pero otro enfoque más conciso que definir un bean CommonAnnotationBeanPostProcessor, podría ser utilizar el espacio de nombres de contexto.

    <?xml  version="1.0" encoding="UTF-8"?>
    <beans  xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns:context="http://www.springframework.org/schema/context"
            xsi:schemaLocation="http://www.springframework.org/schema/beans
        			 https://www.springframework.org/schema/beans/spring-beans.xsd
                             http://www.springframework.org/schema/context
                             http://www.springframework.org/schema/context/spring-context.xsd">
                             
    	<context:annotation-config/> 
    </beans>
    

    Añada los name-spaces de contexto, marcados con borde gris, además con <context:annotation-config/> activamos los procesadores de anotaciones. Esta forma reemplaza a la definición de bean CommonAnnotationBeanPostProcessor

Métodos por default para inicialización y destrucción

Las alternativas anteriores de notificación para la creación y destrucción de beans, se deben realizar por cada definición de bean, esto puede volverse algo tedioso. Spring nos provee la siguiente alternativa.

Los atributos default-init-method="init" y default-destroy-method="destroy" del elemento superior <beans/>, hace que el contenedor Spring reconozca los métodos llamados init y destroy de la clase del bean creado, como la callback de inicialización y destrucción respectivamente. Y de esta manera evitar tener que especificar init-method y destroy-method para cada bean.

 <beans ... default-init-method="init" default-destroy-method="destroy" >
                         
	<-- .... -->
</beans>

Cuando el contenedor Spring instancie y destruya el bean, buscara los metodos init  y destroy de la clase del bean ,en caso de exitir los ejecutará, de lo contrario no pasará nada.

Descargar proyecto gitHub | ciclo de vida

¡Hasta pronto 👋👍!

Comentarios

Entradas populares de este blog

JWT (Json Web Token)

Instalar Java Developmet Kit(JDK)

Curso de Spring