General, Spring

Introducción a los aspectos básicos de Spring Framework – Segunda Parte

1. El ciclo de vida de un bean.

Como anteriormente se pudo ver, Spring, gestiona el ciclo de vida del bean durante toda su ejecución, la cual se basa en tres etapas; ,la inicialización, el uso, y la destrucción.

  1. Inicialización: Los servicios de la aplicación son creados, configurados y se pueden asignar recursos del sistema.
  2. Uso: En esta esta se procesan las peticiones de los clientes, los comportamientos de la aplicación son llevados acabo en esta etapa, siendo esta la que ocupa la mayor parte del tiempo del ciclo de vida.
  3. Destrucción: En la destrucción se liberan los recursos del sistema mediante el garbage colletion.

2. Fases:

2.1 Inicialización:

2.1.1 Carga de la definición de Beans

¿Que pasa cuando se instancia  un ApplicacionContext?

ApplicationContext context = new ClassPathXmlApplicationContext(“basic-context.xml”);

La fase de inicialización esta completa cuando se crea el contexto,  en esta etapa se parsean el o los archivos xml de configuración , las definiciones de los beans son cargados en el contexto del BeanFactory, como anteriormente se menciono, estos se crean con  un identificador único, para el contexto, luego, se invocan a clases y métodos especiales que nos permiten modificar las definiciones de los beans que fueron creados anteriormente, esta funcion la realizan los beans del tipo BeanFactoryPostProcessor, los cual nos permiten manipular, transformar  grupos de definiciones de beans antes que  los objetos sean creados, podemos incluso crear nuestras propias implementaciones de esta interfaz.

Clases que implementan BeanFactoryPostProcesor en Spring 2.5

AspectJWeavingEnablerCustomAutowireConfigurerCustomEditorConfigurerCustomScopeConfigurer,

PreferencesPlaceholderConfigurerPropertyOverrideConfigurerPropertyPlaceholderConfigurer,

PropertyResourceConfigurerServletContextPropertyPlaceholderConfigurer

Un ejmeplo de una clase que implementa BeanFactoryPostProcessor es la clase PropertyPlaceholderConfigurer, que nos permite substituir valores de variables para los beans desde archivos de configuración, ejemplo tenemos un archivo datasource.properties que contiene la forma clave=valor como la siguiente entrada:

driver=com.mysql.jdbc.Driver
dbname=mysql:mydb

Para cargar las propiedades del archivo, se tiene que  usar la sintaxis  del placeholder  

{...}

como en el siguiente ejemplo, que crea un data source, en donde los … serán reemplazados por las claves de nuestra configuración, en este caso, driver y dbname.

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
   <property name="driverClassName"><value>${driver}</value></property>
   <property name="url"><value>jdbc:${dbname}</value></property>
 </bean>

para poder leer y cargar el archivo, spring entre otros, nos proporciona, prefijos para los namespace de configuración que nos facilita el trabajo, uno de estos es el   <context>.

<context:property-placeholder location=“/WEB-INF/datasource.properties” />

2.1.2 Inicialización de la instancia del Bean

  • Cada bean, es instanciado en forma temprana, es creado en el orden correcto  con la inyección de sus dependencias.
  • Después de la inyección de dependencias, los beans pasan a una etapa de post procesamiento, luego de esta etapa, están inicializados y listos para ser usados.

La etapa del post procesamiento se puede  separar en  dos,  se le puede ordenar inicializar la instancia del bean,o se puede implementar un BeanPostProcessors, que nos permite modificar de una manera personalizada las nuevas instancias de los beans.

Si queremos ejecutar comportamientos específicos o invocar  métodos que necesitemos en la instanciación de  bean,  spring nos proporciona mas de una manera para poder hacerlo; mediante la anotación de la JSR-250 @PostConstruct, o a través del init-method, en el cual se especifica el nombre del método inicial que se ejecutará durante la instanciación del bean, esto se realiza en  el archivo de configuración de Spring,  y una tercera opción, es implementando la interfaz InitializingBean.

Vía Anotación:

package com.spring.basic.initialization;

import javax.annotation.PostConstruct;

public class SimpleBeanImpl {

	@PostConstruct
	void initMehtod(){
		//metodo a inicial que es ejecutado despues de que
		//la inyeccion de dependencias haya finalizado
	}

}

* esto es para Spring 2.5 o superior
Para habilitar esta característica, debemos agregar en el archivo de configuración el bean CommonAnnotationBeanPostProcessor o lo recomendado es usar el namespace <context:annotation-config/> , solo bastan con agregarlo tal cual.

Mediante el init-method:

El método debe ser publico, y el bean no debe tener dependencias.

<bean id="simpleBean" class="com.spring.basic.initialization.SimpleBeanImpl" init-method="initMehtod"/>

y mediante la implementación de InitializingBean:

Para versiones inferiores  a spring 2.5, es recomendable usar esta implementación, para versiones superiores o igual a la 2.5,  se recomienda usar @PostConstruct.

package ...
import org.springframework.beans.factory.InitializingBean;
public class SimpleBeanImpl implements InitializingBean {

	@Override
	public void afterPropertiesSet() throws Exception {
		// para versiones inferiores a spring 2.5
	}
}

El método afterPropertiesSet() es invocado automáticamente por Spring.

La interfaz BeanPostProcessor nos permite llevar a cabo configuraciones adicionales, entre sus funciones, nos permite modificar la instancia de un bean en cualquier momento, spring detecta automáticamente estos tipos de beans,  los podemos usar para trabajar con proxies, o para marcar algunas interfaces de modo que la inyección sea requerida, como lo proporciona la anotación @Required, para habilitar esta opción, solo basta agregar <context:annotation-config/> a la configuración.

La interfaz nos provee de dos métodos para poder modificar las instancias, el primero de ellos, es el postProcessAfterInitialization, que nos retorna una nueva instancia después de que se haya hecho la llamada de  inicialización, y el otro método, postProcessBeforeInitialization, quien  lo realiza antes de la llamada de instanciación.

Existe una implementación de BeanPostProcessor llamada RequiredAnnotationBeanPostProcessor que nos permite verificar en tiempo de configuración que todas las propriedades marcadas con la anotación @Required estén seteadas correctamente, si no usamos esta verificación, no nos daríamos cuenta hasta usar el bean que su dependencia no fue inyectada.

...

	private DataSource dataSource;

	/**
	 * Set del datasource
	 * @param dataSource the data source
	 */
	@Required
	public void setDataSource(DataSource dataSource) {
		this.dataSource = dataSource;
	}
2.2 La fase de uso.
Los beans son invocados para usarse, estos pueden haber sido creados dentro de un proxy, quien añade comportamiento y lógica que es transparente a la aplicación, estos proxys son creados en la etapa del post procesamiento.
2.3 La fase de destrucción.
En esta etapa se destruye el contexto que contiene los beans, este no puede ser ocupado nuevamente, también se pueden indicar al contexto que beans específicos se deben destruir, se puede realizar mas de una llamada para la destrucción, esto es conveniente para liberar recursos, spring nos provee mas de una manera de poder destruir  los beans, una de ellas es con la anotación @PreDestroy de la JSR-250, o mediante la configuración con la propiedad destroy-method,  y para versiones inferiores a las version 2.5 de spring, implementando la interfaz DisposableBean.

Vía Anotación:

public class SimpleBeanImpl {

	@PreDestroy
	void release(){
                //se llama antes que se realize la destruccion de la instancia del bean
		//sin restriccion del nombre del metodo ni de visibilidad
	}

}

Mediante el destroy-method:

El método debe ser publico, y el bean no debe tener dependencias, ni argumentos

<bean id="simpleBean" class="...SimpleBean" destroy-method="release"/>

*el método debe ser publico y no debe tener dependencias.

Mediante la implementación de DisposableBean:

public class SimpleBeanDestroy implements DisposableBean {

	@Override
	public void destroy() throws Exception {
		//sping se encarga de llamar a este método en el momento adecuado
	}
}
Estándar