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
J2ee, Spring

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

springframework

1.- Introducción a Spring

  • EL objetivo de Spring

– Proveer el soporte  para desarrollar aplicaciones empresariales con java.

– Enfocarnos en resolver nuestro problema de dominio.

  • El rol en la arquitectura de aplicaciones empresariales.

– El core de Spring nos da la posibilidad de configurar nuestra aplicación de maneras sencillas,así  también el de poder realizar una integración con aplicaciones empresariales,  realizar testing y poder manejar el acceso a la data.

– Permite integrar y configurar componentes de manera sencilla; parte de los componentes son  plain java objects.

– Integrar pool de conexiones  de base de datos, transacciones, seguridad, messaging, acceso remoto, entre otras.

– Realizar testing,  desacoplando  los objetos desde nuestros ambientes(testing, producción) , realizar test unitarios o de integración.

– El acceder a la data de una manera mucho mas fácil, spring  nos entrega soporte para la gran parte de las tecnologías de acceso de datos, como lo son JDBC,JPA,JDO,HIBERNATE,IBATIS, ya ahora llamado MyIbatis, otra característica es que maneja los recursos por nosotros, un ejemplo de esto es que puede adquirir la conexión, participar en la transacción, manejar las exceptions, procesar resultados, etc; nos provee de helpers como lo es JdbcTemplate.

– Soporte para el desarrollo de aplicaciones Web, permite la integración con JSF, Struts, Velocity, FreeMaker y algunos otros, nos permite trabajar con el patrón de diseño MVC, rendear las vistas,validación de formularios, manejo de estados con web flow,  acciones de usuarios, etc, así también, aplicar una capa de seguridad con spring Security.

– Soporte en el desarrollo de aplicaciones empresariales,  desarrollando webservices,  asegurando servicios con accesos de control, planificando jobs y procesos, integrando servicios de mensajería.

  • La base de spring se puede definir mediante el triangulo de Spring

– Inyección de dependencia

– Programacion orientada a aspectos

-y Abstracción de servicios empresariales.

2 .- Beans y contenerdores:

  • En Spring un bean es un objeto que vive y que es manipulado por el contenedor, no confundir con un javabean.
  • Spring gestiona todo el ciclo de vida de la aplicación, todos los beans son inicializados antes que se utilicen.
  • Los beans siempre son creados en orden correcto, Spring se encarga de resolver la dependencia de cada uno de ellos.
  • Cada bean posee un identificador único
  • Encapsula las implementaciones dado  el despliegue de la aplicación, oculta los detalles de la implementación.

2.1 – Los beans.

Un bean es un objeto, y como tal puede ser bastante simple,  como el siguiente:

Con sus atributos, getters y setters, tal y cual, es un objeto plano en java, para pasarlo a un bean de Spring, tenemos que ponerlo en un contenedor de beans, que no es mas que una definición en un archivo xml.

Esta es una clase que no contiene dependencias, si quisiéramos instanciar la clase vía reflection, bastaría con hacer:

SimpleBean simpleBean = new SimpleBean();

Pero Spring nos provee de una interfaz para proporcionar la configuración de una aplicación, esta es el ApplicationContext.

ApplicationContext context = new ClassPathXmlApplicationContext(“basic-context.xml”);
SimpleBean simpleBean = (SimpleBean) context.getBean("simpleBean",SimpleBean.class);

Ahora Spring es quien contiene y maneja todo el ciclo de vida del bean llamado «simpleBean» que definimos mas arriba.

2.2 Inyección de dependencias.

Spring nos permite el poder inyectar dependencias a nuestros beans vía setter, o constructor.

2.2.1 Inyección de dependencia por constructor.

Es equivalente a:

SimpleBean sb = new SimpleBean(787545, "valor del tipo string", new HashMap...);

Beneficios de la inyección por constructor:

  1. Cumplir con las dependencias obligatorias.
  2. Proveer de inmutabilidad
  3. Programar de una forma consistente, creación e inyección en una sola linea de código.

2.2.2 Inyección de dependencia por Setter.

Es equivalente a:

SimpleBean sb = new SimpleBean();
sb.setId(787545);
sb.setName("valor del tipo string");
sb.setMaps(new HashMap()...);

Beneficios de la inyección por Setter:

  1. Permitir dependencias por defecto u opcionales.
  2. Tener nombres descriptivos.
  3. Seguir la convención JavaBeanTM
  4. Se hereda de forma automática.

También se pueden combinar.

Los puristas prefieren uno sobre otro,¿Cual usar?,  tu elijes, se consistente…

2.2.3 Dependencias y configuración en detalle ver aqui

En resumen, dentro de los beneficios de las inyecciones de dependencia podemos mencionar.

  • Al objeto se le entrega lo necesario para trabajar, simplifica el código, permite la reutilización, permite resolver la dependencias entre los componentes.
  • Nos permite trabajar con interfaces, para ocultar los detalles de la implementación
  • Promueve las pruebas de manera aislada o de todos los componentes juntos.
  • Maneja el ciclo de vida del objeto.

3.- El Factory Bean

El factoryBean es una interfaz que es implementada por los objetos que usara el BeanFactory,  si un objeto la implementa, este se utilizará como  una fabrica de objeto, esta interfaz soporta  scopes singletons y prototypes, con la opción de crearse en forma temprana o tardía(lazily).
Métodos de FactoryBean:
getObject() retorna una instancia del objeto creado.
getObjectType() retorna el tipo de objeto que se creo, o null si no se conoce.
isSingleton() si el objeto es manejado como un singleton.

A tener en cuenta:

  • Spring autodetecta cualquier implementación del factoryBean y retorna el objeto creado por
    el metodo getObject()
  • Nos permite encapsular la creación del objeto
  • Spring nos permitirá instanciar el objeto como un bean Singleton, o Prototype.

3.1 Implementando FactoryBean:

Objeto que implementa FactoryBean

package com.spring.basic.factory;

import org.springframework.beans.factory.FactoryBean;

/**
 * Clase de muestra de como funciona el facoryBean de spring
 * <ul>
 * 	<li>Spring autodetecta  cualquier implementacion del {@link FactoryBean } y retorna el objeto creado por
 * el metodo <code>getObject()</code></li>
 * <li>Nos permite encapsular la creacion del objeto</li>
 * <li>Spring nos permitira dejarlo como un bean Singleton</li>
 * </ul>
 * @author jbovet
 */
public class ObjectFactory implements FactoryBean {

	/***
	 * Objeto que sera devuelto
	 */
	private MockObject mockObject;

	private Integer idMock;
	private String nameMock;
	private boolean isSingleton = Boolean.TRUE;

	/***
	 * retorna la instancia del objeto MockObject
	 */
	public Object getObject() throws Exception {
		if (mockObject ==null) {
			initMockObject();
		}
		return mockObject;
	}

	/***
	 * crea la instancia del objeto
	 */
	private void initMockObject() {
		//se crea el objeto mediante constructor
		mockObject = new MockObject(nameMock,idMock);
	}

	/***
	 * Obtiene la clase del objeto
	 */
	public Class<MockObject> getObjectType() {
		return MockObject.class;
	}

	/**
	 * el factorybean se registra como singleton
	 * @see org.springframework.beans.factory.FactoryBean#isSingleton()
	 */
	public boolean isSingleton() {
		return isSingleton;
	}

	public void setIdMock(Integer idMock) {
		this.idMock = idMock;
	}
	public void setNameMock(String nameMock) {
		this.nameMock = nameMock;
	}
}

Configuración del contexto de Spring, para la implementación de un objeto que implementa el FactoryBean.

<?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:util="http://www.springframework.org/schema/util"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd">

	<bean id="mockObjectFactory" class="com.spring.basic.factory.ObjectFactory">
		<property name="idMock" value="123"/>
		<property name="nameMock" value="mockito"/>
	</bean>
        <!--bean que usa el objeto mock -->
	<bean id="simpleBean">
	    <property name="mockObject" ref="mockObjectFactory"/>
	</bean>
</beans>

Test para obtener el objeto MockObject

package com.spring.basic.factory;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestFactory {

	public static void main(String[] args) throws Exception {
		ApplicationContext context = new ClassPathXmlApplicationContext("classpath:com/spring/basic/factory/factory-context.xml");
		MockObject mockObject = (MockObject) context.getBean("mockObjectFactory");
		System.out.println(mockObject.toString());
		//SimpleBean sb = (SimpleBean) context.getBean("simpleBean", SimpleBean.class);
		//sb.doSomething();
	}
}

El uso de los FactoryBeans en Spring:

  • JndiObjectFactoryBean: para poder trabajar con objetos JNDI
  • Nos permite crear proxies remotos
  • Para configurar el acceso a la data.(ibatis, hibernate,jpa,etc)

4.- Creando un Spring Application Context

Un Spring Application Context puede ser ejecutado en casi cualquier ambiente, incluyendo en sistema de testing como Junit, dentro de una aplicacion web, con EJB’s, o e una aplicación  standalone de java, podemos cargar el contexto de partes, como lo es el classpath, desde el sistema de archivos, o como un recurso dentro de una aplicion web, para esto, spring nos proporciona 3 implementaciones para cargar nuestros beans.

Tipo Ejemplo
ClassPathXmlApplicationContext $CLASSPATH/org/spring/basic/application-config.xml
FileSystemXmlApplicationContext \tmp\context\application-config.xml
XmlWebApplicationContext $JBOSS_HOME/webapp/webappName/WEB-INF/application-config.xml

4.1 Usando prefijos.

classpath:

new ClassPathXmlApplicationContext(“classpath:org/spring/basic/application-config.xml”);

file:

new FileSystemXmlApplicationContext(“file:\tmp\context\application-config.xml”);

http:

ctx.getResource("http://myserver/logo.png);

Los prefijos los podemos utilizar en cualquier lugar donde spring necesite cargar algún recurso, no solamente como  argumento en el constructor del applicationContext.

4.2  Creando mutiples Application Context.

  • Un contexto puede ser configurado desde múltiples archivos, permite separar la definición de los beans en grupos lógicos.
  • Una buena practica es separar los beans de la aplicación de los  de infraestructura, ya que estos últimos pueden cambiar dependiendo del entorno.

Ejemplo de como cargar los beans de producción con mysql

ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {
“app-config.xml”,
“mysql-infrastructure-config.xml”
});

Ejemplo de como cargar los beans de desarrollo con mysql en test

ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {
“app-config.xml”,
“mysql-test-infrastructure-config.xml”
});

En la segunda parte, veremos mas en profundidad el ciclo de vida de un bean..

Estándar