Mi granito de java: Spring
Mostrando entradas con la etiqueta Spring. Mostrar todas las entradas
Mostrando entradas con la etiqueta Spring. Mostrar todas las entradas

jueves, 14 de julio de 2011

Spring Core

Continuando con el post anterior de introducción a Spring, que se puede ver en http://migranitodejava.blogspot.com/2011/06/introduccion-spring.html, vamos a profundizar algunos temas.

Creando Beans.

En Spring hay diversas formas de crear un bean. En el ejemplo de la introducción a Spring vimos una opción donde colocábamos la ruta del xml de configuración:
ApplicationContext respuesta =
new FileSystemXmlApplicationContext("C:/Users/max/eclipse workspace/spring.xml");


Esta forma de crear beans esta bien para un ejemplo o aplicaciones muy chicas, pero es poco práctico para el resto de los casos. Spring nos brinda formas alternativas a FileSystemXmlApplicationContext y las más utilizadas son:
ClassPathXmlApplicationContext: busca el xml en el classpath, para mi gusto es la mejor opción.
XmlWebApplicationContext: el xml se encuentra en un contexto de una aplicación web.

Ciclo de vida de un bean.

En Spring la vida de un objeto difiere de la forma tradicional: existen más oportunidades para aprovechar en la creación o destrucción de un bean. Las distintas etapas son:
  1. Instanciación del bean.
  2. Inyección de propiedades.
  3. Nombre del bean: si el bean implementa BeanNameAware, Spring le pasa el id en el método setBeanName(). De esta forma, sabe cual es su id según el xml de Spring.
  4. Contexto: si el bean implementa ApplicationContextAware, Spring llama al método setApplicationContext() y le pasa el contexto como parámetro.
  5. Post proccessor: si hay un BeanPostProccessor, Spring llama al método postProccessBeforeInitialization().
  6. Inicializar bean: si implementa InitializingBean, se llama a afterPropertiesSet().
  7. Post proccessor (de nuevo!): si hay un BeanPostProccessor, Spring también llama al método postProccessAfterInitialization().
  8. El bean esta listo para ser utilizado!
  9. Destrucción del bean: si implmenta DisposableBean se llama a destroy().

Y agregamos lo siguiente al xml:

<bean id="persona" class="ejemplo.Persona" >
     <property name="nombre" value="Maxi"/>
</bean>




Inyección por constructores.

Es posible instanciar objetos con un constructor distinto al vacío. Para ello existe un tag llamado <constructor-arg> que posee dos atributos importantes: ref y value. Por ejemplo, si tenemos un constructor que recibe un int podriamos hacer lo siguiente:
<constructor-arg value=”100” />
Pero si se recibe un objeto compuesto se deberá usar el atributo ref que hace referencia a otro bean de Spring y se lo llama por su id:
<constructor-arg ref=”persona” />

Veamos un ejemplo:
 Y el xml:
<bean id="persona" class="ejemplo.Persona" >
    <constructor-arg value="100" />
    <constructor-arg value="Perez" />
     <property name="nombre" value="Maxi"/>
</bean>




Entonces …¿conviene inyectar por constructor o por setter?

Es muy útil la inyección por constructor por varios motivos. Primero, a diferencia de la mayoría de frameworks que nos obligan a que casi todas nuestras clases sean pojos (y por lo tanto usen el constructor vacío), aquí esto no supone un problema y es Spring quien se adapta y nos da la libertad de trabajar como queremos. Por otro lado, obligamos a que, cuando se crea un objeto, se lo haga de la forma adecuada (con todas sus dependencias creadas si o si).
Por otro lado, inyectar por constructor puede hacer engorrosa la herencia y si el bean tiene muchas dependencias se vuelve cada vez más complicado.
Particularmente prefiero inyectar por setter, pero es bueno tener ambas posibilidades.

Inyectar beans exclusivos.

Hay situaciones donde un bean debería ser una dependencia de otro de manera exclusiva. El problema del archivo xml de Spring es que una vez declarado, el bean puede ser dependencia de cualquiera. Por ejemplo:

<bean id="liz" class="ejemplo.Persona" >
    <constructor-arg value="3" />
    <constructor-arg value="Juarez" />
     <property name="nombre" value="Liz"/>
     <property name="documento" ref="documentoLiz"/>
</bean>

<bean id="documentoLiz" class="ejemplo.Documento" >
    <property name="tipo" value="DNI"/>
     <property name="numero" value="123456789"/>
</bean>


Hasta aquí nada sobresaliente, simplemente hemos agregado a la clase Persona un objeto Documento y lo hemos vinculado para que funcionen en conjunto.




Pero hay un pequeño problema. ¿Que pasa si agregamos lo siguiente en el xml?
<bean id="leo" class="ejemplo.Persona" >
    <constructor-arg value="30" />
    <constructor-arg value="Gonzalez" />
     <property name="nombre" value="Leo"/>
     <property name="documento" ref="documentoLiz"/>
</bean>

Leo esta usando el documento de Liz!! Eso no es correcto y, por ello, Spring permite crear beans exclusivos de la siguiente manera:
<bean id="liz" class="ejemplo.Persona" >
    <constructor-arg value="3" />
    <constructor-arg value="Juarez" />
     <property name="nombre" value="Liz"/>
     <property name="documento">
              <bean class="ejemplo.Documento" >
                  <property name="tipo" value="DNI"/>
                  <property name="numero" value="123456789"/>
               </bean>
    </property>
</bean>
Observamos que Spring permite definir un bean dentro de una propiedad que no lleva el atributo id y, por lo tanto, no es posible referenciarlo de ninguna manera.
Hay que tener mucho cuidado al crear objetos de este tipo ya que estaremos impidiendo la reutilización del código.

Scope de un bean.

Por defecto, todos los beans de Spring son Singletons. Si no se conoce dicho patrón se puede leer en http://migranitodejava.blogspot.com/2011/05/singleton.html
Spring sólo crea una única instancia de cada objeto en su contenedor y luego la reutiliza. Todos sabemos que en ciertos casos esto no es conveniente, por lo que nos da la opción de cambiarlo. Para ello, en la etiqueta bean hay un atributo llamado scope que puede tomar los siguientes valores:
  • Singleton: es el valor default e implica una única instancia.
  • prototype: se instancia todas las veces que sea necesario.
  • request: válido en Spring MVC, donde es instanciado por cada petición HTTP.
  • session: válido en Spring MVC, donde es instanciado por cada usuario.
  • global-session: válido en Spring MVC, donde es instanciado en una session global HTTP.

Ojo si usan una versión anterior a Spring 2 que esto se trata de manera diferente.

Como se habrán dado cuenta, este singleton de Spring tiene una particularidad: no es realmente un Singleton. Es decir, Spring nos asegura que nos devolverá una única instancia pero nada impide que haga un new Object().
Muchas veces nosotros necesitamos controlar el Singleton para evitar problemas. Para ello Spring nos brinda una solución:

 Y en el xml definimos cual es el método encargado de crear el bean:
<bean id="fechaUtils" class="calendario.FechaUtils" factory-method="getInstance"/>
   


De esta forma, es posible adaptar a Spring para que instancie los objetos como nosotros le digamos. Este ya si es un Singleton propiamente dicho.

Autoconexión.

Vimos que es posible conectar las propiedades mediante un constructor o los métodos setters. Hasta aquí se hizo de manera explícita en el archivo xml. Pero se puede hacer que Spring resuelva esto por nosotros mediante el atributo autowire de cada bean. Hay 4 tipos de autoconexión:
  1. byName: es la más común, ya que conecta por ID (ver el ejemplo). Si no se encuentra un bean correspondiente la propiedad queda sin conectar.
  2. byType: busca un único bean en el contenedor cuyo tipo sea correspondiente con la propiedad a conectar. Si no se encuentra no conecta, pero si encuentra más de una lanza una UnsatisfiedDependenciException.
  3. constructor: busca uno o más beans del contenedor que correspondan con los parámetros del constructor del bean a conectar. Si no puede resolverlo lanza una UnsatisfiedDependenciException.
  4. autodetect: intenta primero conectar por constructor y luego byType.

Y en el xml:
<bean id="persona" class="ejemplo.Persona" scope="prototype" autowire="byName">
    <constructor-arg value="100" />
    <constructor-arg value="Perez" />
     <property name="nombre" value="Maxi"/>
</bean>
<bean id="domicilio" class="ejemplo.Domicilio" >
    <property name="calle" value="Av. Rivadavia"/>
     <property name="numero" value="948"/>
     <property name="localidad" value="Bs As"/>
</bean>



Autoconexión por defecto.

Por defecto, los beans no se conectan. Pero esto se puede cambiar en la etiqueta beans:
<beans default-autowire="byName">
...
</beans>
De esta forma, le estamos diciendo a Spring que conecte por byName por defecto, lo que se puede sobreescribir en cualquier etiqueta bean.

Colecciones.

Voy a asumir que ya todos conocen el concepto de List, Set, Map y las colecciones más importantes de Java, como por ejemplo Properties. Así que iré directamente a un ejemplo integrador donde se mostrará como configurar Spring para cada tipo de colección. De todas maneras, es muy intuitivo entenderlo.

List, set y arrays funcionan de manera similar. Cuando son array o list simplemente debo confgurar el xml de la siguiente manera (si son sets, solo hay que cambiar <list> por <set>):
<bean id="persona" class="ejemplo.Persona" >
  <property name="telefonos">
    <list>
          <ref="telefono1">
          <ref="telefono2">
          <ref="telefono3">
    </list>
  </property>
</bean>
Y un Map sería:
    <map>
          <entry key="clave1" value="valor1">
          <entry key="clave2" value="valor2">
    </map>

Tanto en la clave como en el valor es posible referenciar a otros beans en lugar de poner Strings. Para ello, en vez de key debemos colocar key-ref donde haremos referencia hacia el id de otro bean. Lo mismo ocurre en el valor: en vez de value debemos colocar value-ref.

En cuanto a los properties (clase java.util.Properties) se hace de la siguiente manera:

    <props>
          <prop key="clave1" >valor1</prop>
          <prop key="clave2">valor2</prop>
    </props>

Herencia entre beans.

Es posible utilizar herencia dentro de los beans declarados en el xml de Spring, lo cual nos puede permitir que nuestro archivo se reduzca en cuanto a la cantidad de líneas que tenemos que escribir. Para ello, el tag bean posee 2 atributos que, hasta ahora, no hemos utilizado. Estos son:
  • parent: indica quien es el padre (como un extends).
  • abstract: indica si es un bean abstracto que me sirve solo como modelo pero que nunca se va a instanciar. Toma valores true o false.
Por ejemplo, supongamos que en una empresa los empleados tienen, en su gran mayoría, el mismo domicilio y telefono laboral. Solo cambiar su interno.
<bean id="empleado" class="ejemplo.Empleado" abstract="true">
    <property name="domicilioLaboral" value="Av. Rivadavia 123"/>
     <property name="telefonoLaboral" value="49876648"/>
</bean>
Luego, cada vez que quiera crear un empleado solo debo hacer lo siguiente:
<bean id="juan" parent="empleado"/>

Si un empleado no tiene, por ejemplo, ese domicilio laboral, entonces se lo puede sobreescribir:
<bean id="sergio" parent="empleado">
        <property name="domicilioLaboral" value="Av. Cordoba 233"/>
</bean> 






Y el xml era así:
<bean id="saludoImpl" class="saludo.SaludoImpl">
      <property name="valor" value="Hola mundo!"/>
</bean>

<bean id="alumno" class="saludo.Alumno" >
      <property name="saludo" ref="saludoImpl"/>
</bean>


Ahora vamos a hacer un pequeño cambio en el xml y lo vamos a dejar así: 
<bean id="saludoImpl" class="saludo.SaludoImpl">
      <property name="valor" value="Hola mundo!"/>
    <replaced-method name="saluda" replacer="saludoAlternativo"/>
</bean>
<bean id="saludoAlternativo" class="saludo.SaludoAlternativo"/>

Y realizamos la implementación SaludoAlternativo:

Como se imaginarán hemos cambiado el "Hola mundo" por algo más actual. =)

2) Sustitución por getter: permite que los métodos sean sustituidos en tiempo de ejecución con nuevas implementaciones. En realidad es un caso especial de la sustitución anterior. Se suele utilizar en casos de métodos abstractos, aunque no es obligatorio.
Vamos a porner un ejemplo sencillo. Imaginemos que una clase llamada Reloj posee el siguiente método:
public abstract Tiempo getTiempo();


En el xml se podría escribir:
<bean id="reloj" class="ejemplo.Reloj">
    <lookup-method name="getTiempo" bean="tiempoImpl"/>
</bean>

De esta forma se sustituye lo que devuelve el método por la implementación de tiempoImpl. En la practica la sustitución por método no se suele utilizar demasiado ya que no son demasiados los casos donde se puede aplicar (¿para que voy a hacer un método que despues lo voy a cambiar no?), pero es bueno saber que existe.

Estas son las características principales del Core de Spring. Cuando tenga tiempo y ganas escribiré un post sobre Spring AOP.

martes, 28 de junio de 2011

Introducción a Spring

Primero voy a dar una introducción a Spring para quienes no conozcan el framework, donde veremos de que se trata, como configurarlo y un sencillo "Hola Mundo". Luego escribiré un post sobre Spring Core que permitirá conocer el framework de manera más amplia.

Spring es un marco de trabajo cuya finalidad es facilitar el desarrollo de aplicaciones con Java. Fue creado por Rod Johnson y es de código abierto.
Sus características son:
  • Simplicidad y acoplamiento débil: da la sensación que quién desarrollo Spring se imagino a Java de otra manera, más robusto y configurable, con más facilidadades y posibilidades para los desarrolladores. Esto se ve reflejado en este framework: busca ser simple y se basa en la inyección de dependencias para obtener un acoplamiento débil. Luego veremos estos dos conceptos.
  • Es un contenedor: no es solo un framewrok más. Es un contenedor que gestiona el ciclo de vida de los objetos y como se relacionan entre ellos. Proporciona una gran infraestructura que permite que el desarrollador se dedique a la lógica de la aplicación.
  • Ligero: es muy rápido en tiempo de procesamiento y no es intrusivo a la hora de desarrollar. Esto último es uno de sus puntos más fuertes.
  • Orientado a aspectos: soporta la programación orientada a aspectos, lo que permite facilitar una capa de servicios que son ideales para este tipo de programación como auditoría, o gestión de transacciones.

Módulos de Spring

Spring posee diversos módulos que se pueden agregar a las aplicaciones Java. Cada desarrollador agrega los módulos que necesite.  Spring Core es el núcleo de Spring, es el único módulo que tenemos que agregar para que Spring funcione. ya que contiene la DI (inyección de dependencias) y la configuración y uso de objetos Java. Muchas aplicaciones sólo necesitan de Spring Core sin necesidad de agregar módulos adicionales.

Otros módulos conocidos son: AOP para trabajar con aspectos, DAO para trabajar con base de datos, MVC para la capa web, Portlet MVC para trabajar con portlets, JMS para mensajería y Security para el manejo de seguridad (el framewrok de seguridad era antes conocido como Acegi).
Como se puede observar Spring nos da muchas opciones para poder agregar a nuestro proyecto. Estos no son los únicos módulos que nos ofrece Spring, sólo son los más importantes.

Inyección  de dependencias (DI).

Originalmente la inyección de dependencias se llamaba inversión de control, pero en el 2004 Martin Fowler llegó a la conclusión que realmente no se invertía el control, sino las dependencias.
La DI permite a un objeto que conozca sus dependencias mediante una interfaz y no por su implementación. De esta forma, la implementación puede variar sin que el objeto dependiente se de cuenta. La gran ventaja de la DI es el acoplamiento débil entre objetos.
Muy linda la teoría pero si uno se inicia en Spring por primera vez suena a conceptos muy abstractos.  Nada mejor que un ejemplo sencillo para aclarar los puntos. Veremos un pequeño ejemplo antes de introducirnos en Spring Core,  pero antes veremos como configurar Spring en una aplicación eclipse:

1) Bajar Spring desde http://www.springsource.org/download y agregar las fuentes al proyecto.
2) Si la distribución de Spring no adjunta las librerías de apache commons también hay que bajarlas: http://commons.apache.org/
Adjunto un pic con las librerias necesarias para empezar (ignoren el archivo spring.xml por ahora):


3) Dentro de las librerías habrán visto que hay un archivo llamado spring.xml (le pueden poner el nombre que quieran, es lo mismo).
Por ahora les recomiendo que hagan un archivo xml que tenga el siguiente contenido y lo agreguen al classpath. Luego les explicaré que significa cada cosa de dicho archivo.


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

<bean id="saludoImpl" class="saludo.SaludoImpl">
      <property name="valor" value="Hola mundo!"/>
</bean>

<bean id="alumno" class="saludo.Alumno" >
      <property name="saludo" ref="saludoImpl"/>
</bean>

</beans>

4) Por último, vamos a hacer una clase que nos permita levantar el archivo:

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

public class ContextFactory {
   
    private static ApplicationContext respuesta;
   
   
    public static ApplicationContext getInstance(){
        if (respuesta != null) {
            return respuesta;
        }
        respuesta = new FileSystemXmlApplicationContext
        ("C:/Users/max/eclipse workspace/spring.xml"); // aca pongan la ruta donde pusieron el xml
        return respuesta;
    }

Listo, con esto tenemos todo para comenzar con nuestro ejemplo.
Crearemos una clase Alumno que tiene un atributo de la clase (intefaz) Saludo.


Aquí una posible implementación de la clase Saludo:

Veamos como se ejecuta esto:


¿Que ha pasado aquí?

A simple vista deduciremos lo siguiente: la clase Alumno posee un atributo que es una interfaz y no se entera como es la implementación de la misma.
Vamos a explicar el funcionamiento: todo se debe gracias al archivo de configuración xml. El tag <beans> es el elemento raíz del xml y todo lo que se encuentre dentro de este elemento es configuración de Spring.
El elemento <bean>  indica a Spring que se configurará un objeto para ser utilizado en el contenedor de Spring. Id es un atributo obligatorio que debería identificar unívocamente al bean en cuestión.
En nuestro ejemplo vemos la siguiente configuración:
<bean id="saludoImpl" class="saludo.SaludoImpl">
<property name="valor" value="Hola mundo!"/>
</bean>
El atributo class indica la clase a la cual pertenece el bean y cada bean puede tener subelementos <property> que representan los atributos (en este caso me refiero a atributos de objetos y no de xml) del bean. El name debe coincidir con el nombre de atributo que tenga en la clase y, en este ejemplo, value sería el valor que toma. Veremos luego que hay varias opciones más.
Continuando con el xml vemos:
<bean id="alumno" class="saludo.Alumno" >
<property name="saludo" ref="saludoImpl"/>
</bean>
La novedad aca aplica a atributo ref del elemento property: esta indicando que este atributo es un objeto y, por lo tanto, es conveniente configurar dicho objeto de manera separa y se hace referencia al mismo mediante su id.

¿Y no es lo mismo hacerlo así?


Si y no a la vez: tradicionalmente cada objeto es responsable de obtener sus propias dependencias y esto lleva a un código muy acoplado. Cada objeto debe conocer como se construyen otros y si bien los patrones creacionales pueden ayudar con este tema, entonces hay que conocer que patrón se aplicó a cada objeto.
Cuando se aplica la DI se otorgan las dependencias a cada objeto, se obtiene un acoplamiento débil: si un obejto solo conoce sus dependencias mediante su interfaz, entonces puede variar su implementación sin que  el objeto dependiente sepa la diferencia. Por otro lado, el código es más limpio y ordenado.

Hasta aquí con esta breve introducción a Spring. Cuando escriba sobre Spring Core se verán estos temas con más profuncidad.