Martes, 15 Julio 2014 02:08

Comenzando con Spring MVC 3. Inyección de Dependencias

Escrito por 
Valora este artículo
(0 votos)

Que tal amigos, con este post iniciaremos una serie de tutoriales web, emprendiendo sobre el Framework Spring   MVC   para Java. Comenzaremos desde lo mas  básico hasta llegar a realizar con lo que se hizo con JSF (Una tabla con datos, un CRUD sobre la misma y algo mas).

En este post, como en los demás, no se dara teoría de todo lo que se puede hacer con este Framework, ya que es muchísimo, sino que se ira al grano como se dice por ahí, iremos directamente al código, si se explicara lo que se está haciendo pero no se entrara muy en detalle, uds. lo completaran con la documentación de la misma y demás por toda la red. Recomiendo la documentación Oficial y algunos books com ser

Empecemos lo que se hara en este post, es explicar unos de los pilares de Spring, la Inyección de Dependencias (ID), pero que es esto.
Básicamente es cuando nuestras clases dependen de otras para realizar sus tareas, esto puede traer problemas en ciertas ocaciones. Supongamos que tenemos una clase que se llama Operación, para que esta realice su tarea necesita de otra clase denominada Cuadrado (que nos calcula el área de un cuadrado) tal como se  ve en el siguiente código
 

  1. package clases;
  2. public class Operacion {
  3.      Cuadrado cuadrado;
  4.      
  5.     public int resultado(){
  6.         int dato=4;
  7.         int resultado;
  8.         //instanciamos la clase
  9.         cuadrado = new Cuadrado();
  10.         //llamamos a su metodo
  11.         resultado=cuadrado.calculo(dato);
  12.         //realiza una operacion con lo que retorna el metodo calculo de la clase cuadrado
  13.         resultado=resultado*4;
  14.         return resultado;
  15.     }
  16. }
  17.  
  18. package clases;
  19.  
  20. /**
  21.  *
  22.  * @author RAFAEL
  23.  */
  24. public class Cuadrado {
  25.  
  26.     public int calculo(int dato) {
  27.        //calculamos en area de un cuadrado
  28.        return (dato+dato);
  29.     }
  30.    
  31.    
  32. }



En esta caso  vemos que la clase Operación, depende  de otra clase, de la clase Cuadrado, la clase operación es la encargada de instanciarla y hacer uso de ella,  eso es la dependencia. Supongamos que en un futuro la clase operación cambia su tarea y ya no necesita el area de una cuadrado, sino la de un circulo, entonces habrá que cambiar el código  de la misma, hacer un “new” de otra clase y demás, por supuesto que en esta clase no pareciera ser tan difícil por  la poca complejidad que presenta la misma, ya que son meros ejemplos practicos para llegar a entender la ID, pero en otros casos con mucha dependencia, esta tarea de cambio lleva tiempo y pueden surgir problemas en la refactorización.
Spring lo que hace con la ID, es que su componente, el CONTENEDOR, sea el encargado de inyectar las dependencias de los objetos, en ves de que ellos mismos lo hagan, es decir que la dependencia de cada objeto depende del CONTENEDOR. Como seria en el caso de la clase operación, esta en ningún momento haría un
cuadrado = new Cuadrado();
sino que el CONTENEDOR es el encargado de realizar esa inyección de dependencias, por lo que si en un futuro cambia esa dependencia, el contenedor solo se tendría que cambiar la configuración (en este post lo realizaremos con un archivo XML).

Spring coloca las clases básicas de su contenedor de para ID en dos paquetes:

  • org.springframework.beans
     
  • org.springframework.context

Estos paquetes contienen dos interfaces que son las que realizan la tarea de la instanciación de objetos. La primera es "org.springframework.beans.factory.BeanFactory", que proporciona un mecanismo de configuración avanzada capaz de manejar cualquier tipo de objeto. Además proporciona una sub-interface de esta última, "org.springframework.context.ApplicationContext", la cual agrega una integración más fácil con algunas de las características más interesantes de Spring, como su módulo de Programación Orientada a Aspectos, manejo de recursos de mensajes (para la internacionalización), publicación de eventos, y contextos específicos para ciertas capas de aplicaciones (como aplicaciones web), entre otras.

"BeanFactory" proporciona el framework de configuración y la funcionalidad básica, mientras que "ApplicationContext" agrega más funcionalidad específica para ciertos productos empresariales. Ambas interfaces representan contenedores de beans, solo que de tipos distintos.

"BeanFactory" representa las fábricas de beans y son el tipo de contenedor más simple. Este proporciona el soporte básico para DI. "ApplicationContext" representa... el contexto de la aplicación, estos están construidos con las mismas nociones de las fábricas de beans, pero proporcionan a la aplicación servicios adicionales.

Nosotros trabajaremos con ApplicationContext, BeanFactory es para aplicaciones sencillas, para tomar todas las ventajas que nos puede proporcionar Spring utilizamos ApplicationContext.

Manos a la Obra

Antes que nada recordamos que utilizamos para los posts:

  • Netbeans 7.1.1 (El ide ya viene incorporado con las librerías de Spring)

Iremos al código para entender mejor esto.
Abrimos el netbeans y creamos nuestro primer Proyecto


Elegimos aplicación Java


Le damos el nombre, en este caso Inyección de Dependencias


Bien hasta ahora tenemos creado un simple proyecto Java.
Lo que haremos ahora es agregar las Librería de Spring 3.x, para hacer uso de la misma


Para ello le damos click derecho sobre Bibliotecas como lo muestra la imagen, luego el Agregar Biblioteca

En la ventana buscamos Spring Framework 3.0.6 y le damos click en Añadir biblioteca


Listo ya tenemos nuestro proyecto con las librerías necesarias para hacer funcionar Spring sobre una aplicación Java.

El arbol del proyecto queda de la siguiente manera

A continuación crearemos una interfaz. Es necesario aclarar que Spring toma mucha potencia en el uso de Interfaces, la mayoría de nuestro código estará en clases que implementaran una interfaz.
Bien le damos click derecho sobre Paquetes de fuentes-> nuevo-> Java Interface

 

 


En nombre: Operacion (el nombre de la Interface)
Paquete: Clases (El paquete en donde estará la clase)
Nuestra interface Operación tendrá el siguiente código, con un solo método “calculo”, que dependiendo su implementación retornara un resultado

  1.  
  2. package Clases;
  3.  
  4. public interface Operacion {
  5.    
  6.     public int calculo(int dato);
  7. }



Ahora crearemos nuestra 2 clases “Cuadrado” y ”Circulo”, que serán implentaciones de nuestra interface Operación
Le damos click derecho sobre Paquetes de fuentes-> nuevo-> Java Class

 


En nombre: Cuadrado (el nombre de la clase)
Paquete: Clases (El paquete en donde estará la clase)

 El código de nuestra clase Cuadrado será el siguiente, en esta clase solo se calcula el area de un cuadrado, según lo que tenga dato

  1. package Clases;
  2.  
  3. public class Cuadrado implements Operacion{
  4.  
  5.     public int calculo(int lado) {
  6.         //calculamos en area de un cuadrado
  7.         return (dato + dato);
  8.     }
  9. }

 Ahora de la misma manera creamos la clase Circulo, en el mismo paquete, pero con el siguiente código, aquí  también se calcula el area pero de un circulo, al resultado se lo redondea a entero:

  1. package Clases;
  2.  
  3. public class Circulo implements Operacion{
  4.    
  5.     public int calculo(int radio){
  6.         return Math.round((float)(3.14*(radio*radio)));
  7.     }
  8. }

 Bien ya tenemos la interface y nuestra 2 clases que implementan la interface Operación, el árbol del proyecto queda de la siguiente manera

Bien ahora el siguiente paso es crear nuestro archivo de configuración ApplicacionContext.xml
Este archivo será nuestro contenedor de beans Spring, recordar que estos beans no son los mismos que los javabeans, sino que son beans de Spring. En este archivo de configuración crearemos los beans a utilizar en la aplicación, definimos su dependencia (la ID), el cableado (wiring) que seria la relación entre las mismas y demás cosas que iremos viendo el post posteriores.
Bien manos a la obra con el archivo de configuración, le damos click derecho sobre
Paquetes de fuentes-> nuevo-> Otro (en mi caso)


Luego en esta ventana Otros y luego en el otro panel Archivo XML de Configuración Spring


Luego le damos el nombre ApplicationContext

Entonces nos queda
En nombre: ApplicationContext (el nombre del archivo)
Paquete: src (El paquete predeterminado)
Luego en siguiente
En la ventana podemos elegir algún espacios de nombres(en esta caso no usaremos ninguno de ellos, sino los que ya viene por defecto), le damos en terminar



Entonces el árbol del proyecto nos queda de la siguiente manera


A nuestro archivo ApplicationContext.xml le agregamos la siguiente línea
 

<bean id="operacion" class="Clases.Cuadrado"  />     


Entonces queda de la siguiente manera

<?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-3.0.xsd">

           
    <bean id="operacion" class="Clases.Cuadrado"  />      

</beans>

Bien, en la línea agregada

<bean id="operacion" class="Clases.Cuadrado"  />     

Lo que estamos haciendo es agregar nuestro primer bean al contenedor de Spring
Tiene las siguientes propiedades
Id: identificación único del beans
Class: la clase a la cual hace referencia el bean, en este caso a Cuadrado del paquete clases
 Para  ver mas en detalles sobre los tags y propiedades de los mismos nos podemos remitir a la documentación oficial de Spring.
Ahora haremos uso del ApplicationContext.xml, osea del contenedor de beans de Spring. Haremos que este sea el que instancie la clase y no nosotros en el código de una clase.
 Para ello abrimos nuestro archivo InyeccionDependencia.java y agregamos el siguiente código

package inyecciondependencia;

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

public class InyeccionDependencia {

    /**
     * @param args the command line arguments
     */

    public static void main(String[] args) {
        //hacemos uso de ApplicationContext
        //lo instanciamos a travez de ClassPathXmlApplicationContext (un archivo que se encuentra en el classpath)
        //le pasamos como parametro el nombre del archivo de configuracion creado
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        //a Operacion le pasamos una instancia ya creada por
        //applicationContext.getBean("operacion", Operacion.class);
        Operacion operacion = applicationContext.getBean("operacion", Operacion.class);
        //una vez instanciada operacion podemos hacer uso de sus metodos
        System.out.println("El valor del area es " + operacion.calculo(4));
    }
}
 

Bien las líneas están comentadas de todos modos aclaramos que:
ApplicationContext: es la interface de la cual hacemos uso para instanciar beans.
ClassPathXmlApplicationContext("ApplicationContext.xml") : ApplicationContext es instanciada a travez de esta, con el parámetro “ApplicationContext.xml” que es el archivo de configuración creado.
Una vez instanciado atravez de  applicationContext.getBean, obtenemos una instancia de Operación, sin realizar ningun “new”, y que tiene 2 parametros
operación”:  que es el nombre del bean declarado en el archivos de config. ApplicationContext.xml
Operacion.class : que es el tipo de clase que nos tiene que devolver el método getBean de applicationContext.

Bien estamos en condiciones de hacer correr nuestro primer proyecto Spring
Le damos F6 o cualquiera de las otras formas para correr nuestro proyecto y obtenemos(click derecho sobre el proyecto y luego run, o sobre el icono de la barra de herramientas)



“El valor del area es 8”, previo a algunos mensajes que nos muestra Spring
Bien con esto vimos que en ningún momento nosotros realizamos un
Cuadrado = new Cuadrado(4);
Sino que Spring lo hace por nosotros.
Ahora bien supongamos que nos queremos calcular el area del cuadrado, sino la de un circulo. Solamente tenemos que cambiar nuestro archivo de configuración ApplicationContext.xml
Cambiamos la siguiente línea

<bean id="operacion" class="Clases.Circulo"  />   


El archivo completo nos queda de la siguiente manera
 

<?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-3.0.xsd">

           
    <bean id="operacion" class="Clases.Circulo"  />  

</beans>
 

Corremos el proyecto y el resultado es para un circulo de radio 4



Notemos que ahora hacemos uso de la clase Circulo, en ningún momento tocamos la clase, ni instanciamos nosotros los objetos, sino que lo hace Spring.
Las dependencias las definimos en el archivo de config. ApplicationContext.xml.
Quizás para algunos no quede claro aun esto, a continuación extenderemos el ejemplo realizado.

Ahora supongamos que tenemos una clase Servicio.java, que hace uso de la interface Operación
 Y esta clase Servicio realiza unos cálculos extras aparte de necesitar el area de un cuadrado o circulo.
Antes que nada aclararemos que podemos hacer la Inyeccion de Dependencias de 2 maneras

  • ID mediante constructor
  • ID por setter

En nuestro ejemplo anterior en las implementaciones no usamos ningún constructor.
Para nuestra nueva clase servicio incluiremos un constructor. Quizas en el ejemplo anterior se preguntaron ¿Si Spring instancia la clase por nosotros, en caso de que tenga un constructor, como le pasamos el o los parámetros?
Pues bien la rta. es mediante el archivos de config. ApplicationContext.xml, para ello contamos con los tags necesarios para realizar la ID mediante constructores.

ID mediante Constructores

Bien creamos nuestra  clase Servicio, como lo hicimos anteriormente con las demás pero con los sig. datos:
En nombre: Servicio (el nombre de la clase)
Paquete: Clases (El paquete en donde estará la clase)

El código de la clase es el siguiente

package Clases;

public class Servicios {
   
    private Operacion operacion;

    public Servicios(Operacion operacion) {
        this.operacion = operacion;
    }
   
    public double consultaResultado(){
        double resultado;
        // a resultado le pasamos lo q nos devuelve el metodo calculo de operacion
        resultado=this.operacion.calculo(4);
        //con los q nos pasa resultado realizamo algo (en este caso le multiplicamos E)
        resultado=resultado +(Math.E);
        //retornamos resultado
        return resultado;
       
    }
}
 

Bien ahora tenemos nuestra clase Servicio, si observamos tenemos un constructor en la misma, en la cual se pasa como parámetro  un objeto de la clase Operación, ahora en nuestro ApplicationContext.xml tenemos que declara este bean declarando que tiene un constructor y pasándole un parámetro.

Abrimos nuestro ApplicationContext.xml y añadimos las siguientes líneas

<bean id="servicio" class="Clases.Servicios">
        <constructor-arg ref="operacion"  />
    </bean>
Entonces nuestro archivo de config. Spring queda

<?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-3.0.xsd">

           
    <bean id="operacion" class="Clases.Circulo"  />  
    <bean id="servicio" class="Clases.Servicios">
        <constructor-arg ref="operacion"  />
    </bean>
   
</beans>
 

En donde declaramos otro bean de id servicio y que hace referencia a la clase Servicio del paquete Clases. Observamos que el tag del bean no se autocierra, ya que necesitamos incorporar dentro un hijo que seria el contructor.
El tag <constructor-arg   />  es el tag que nos permite indicar que nuestra clase es instanciada mediante un constructor. Como propiedad tenemos ref=”operacion” , osea estamos diciendo que el parámetro lo pasamos como referencia y es operación, que es nuestra interface que esta implementada mediante la clase Circulo. En caso de tener mas parámetros para el constructor hacemos uso de la propiedad index, también contamos con la propiedad type para indicar el tipo de dato que pasaremos. La imagen nos muestra una observación con flechas.



Bien ya tenemos nuestro contexto definido con sus propios beans, ahora modificamos InyeccionDependencia.java, queda de la siguiente manera
 

package inyecciondependencia;

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

public class InyeccionDependencia {

    /**
     * @param args the command line arguments
     */

    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        Servicios servicio = applicationContext.getBean("servicio", Servicios.class);
        System.out.println("El valor del area es " + servicio.consultaResultado());
    }
}
 

Bien observamos que ahora ya no pedimos una instancia de Operación, sino de Servicio, y servicio es la encargada de hacer uso de Operación, hace uso de Operación que es implentada mediante Circulo porque asi lo indicamos en el archivo de config. ApplicacionContext.xml.

El arbol des proyecto queda de la siguiente manera


Corremos el proyecto y observamos la salida


Observamos un numero real porque asi lo hicimos en la clase Servicio. Bien ahora supongamos que Servicio no necesita que Operación le pase el area de un Circulo, sino la de un cuadrado, lo único que hacemos es realizar una implementación de la interface Operación que nos calcule el área de un cuadrado (en este caso ya la tenemos) y de ahí modificar tan solamente el archivo de config.  ApplicacionContext.xml. Supongamos este caso y modificamos el archivo de config.
Modificamos la línea
    <bean id="operacion" class="Clases.Cuadrado"  />   
Y nos queda
 

<?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-3.0.xsd">

           
    <bean id="operacion" class="Clases.Cuadrado"  />  
    <bean id="servicio" class="Clases.Servicios">
        <constructor-arg ref="operacion"  />
    </bean>
   
</beans>

El resultado es entonces


Con esto damos cuenta de que nosotros no tocamos en ningún momento nuestras clases, es decir no hay acoplamiento extremo, las dependencias la podemos manejar con un archivo de configuración, en este caso Spring lo hace por nosotros.

Bien para terminar con este sencillo post, realizaremos la ID pero por setter.

ID mediante Setter

Primero lo que haremos es quitar el parámetro que tiene el constructor de la clase Servicios
Luego haremos un setter de la clase Operación, entonces la clase Servicio queda asi
 

package Clases;

public class Servicios {

    private Operacion operacion;

    public Servicios() {
    }

    public double consultaResultado() {
        double resultado;
        // a resultado le pasamos lo q nos devuelve el metodo calculo de operacion
        resultado = this.operacion.calculo(4);
        //con los q nos pasa resultado realizamo algo (en este caso le multiplicamos E)
        resultado = resultado + (Math.E);
        //retornamos resultado
        return resultado;

    }

    public void setOperacion(Operacion operacion) {
        this.operacion = operacion;
    }
}


Como haremos la ID por setter, incluimos un setter de Operación, y de paso quitamos los parámetros del constructor
Ahora modificamos la línea en donde declarábamos nuestro constructor en el archivo de config., por la sig. línea

<property name="operacion" ref="operacion"  />

ApplicacionContext.xml nos queda  asi entonces
 

<?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-3.0.xsd">

           
    <bean id="operacion" class="Clases.Cuadrado"  />  
    <bean id="servicio" class="Clases.Servicios">
        <property name="operacion" ref="operacion"  />
    </bean>
   
</beans>
 


En el tag < property  /> indicamos que queremos modificar una propiedad de la clase Servicios
En este caso la propiedad tiene el nombre de “operación” (name="operacion"), y hace referencia al bean “operación” que esta declarado una línea antes.
Con esto hacemos ID pero por setter y ya no por constructor, es decir Spring instancia nuestra clase Servicios y de paso settea nuestra propiedad operación, osea Spring hace lo siguiente
       

        Servicios sevicio= new Servicios();
        Operacion operacion= new Cuadrado();
        servicio1.setOperacion(operacion);

y nos devuelve a nosotros un bean ya instanciado y seteado.
Corremos el proyecto y el resultado es el mismo



Bien por razones de tpo. y demás, dejamos aquí este primer post sobre Spring. Hemos tratado de entender unos de los pilares de Spring, la inyección de dependencias, espero haber podido hacerlo. Pronto vendrán mas tutos sobre Spring,  espero sus comentarios. Saludos…smiley

Proximo post HOLA MUNDO 1 EN SPRING MVC

Visto 1205 veces Modificado por última vez en Martes, 15 Julio 2014 18:26

Deja un comentario

Asegúrate de llenar la información requerida marcada con (*). No está permitido el código HTML. Tu dirección de correo NO será publicada.