sábado, 15 de agosto de 2009

Spring Básico, inyección de dependencias desde xml

Este post tratará el concepto de inyección de dependencias declarado en un archivo xml, y ¿cómo? desde código java podemos obtener el ensamblado(todos los beans instanciados y relacionados en memoria), para este caso utilizo un modelo de dominio de pedidos de compra, aquí hay que tener cuidado ya que el objetivo del post es ver como Spring inyecta las dependencias en los objetos que va creando, en un entorno de producción Spring no se utiliza para instanciar objetos de negocio o de un modelo de un dominio especifico(de esto se puede encargar Hibernate, Ibatis o el ORM de tu preferencia), Spring en entornos de producción nos servirá para instanciar servicios, daos, acciones de struts, etc...

Veamos la base de código, del modelo de dominio.

Proveedor.java
package pe.com.slcsccy.springbasico.dominio;
public class Proveedor {
private Integer idProveedor;
private String nombreProveedor;
private String nombreContacto;
private String direccion;
private String telefono;
//siguen setters y getters...
}

PedidoCompra.java
package pe.com.slcsccy.springbasico.dominio;
import java.util.ArrayList;
public class PedidoCompra {
private Integer idPedidoCompra;
private String numeroPedidoCompra;
private String descripcionPedidoCompra;
private String fechaPedido;
private String fechaEntrega;

//Aqui agregamos referencias a un listado de items
//de pedido DetallePedido
private ArrayList detalle;

//Aqui mantenemos la información del proveedor
//a quien se realiza la compra
private Proveedor proveedor;

//siguen setters y getters...
}

DetallePedido.java
package pe.com.slcsccy.springbasico.dominio;
import java.math.BigDecimal;
public class DetallePedido {
private Integer idDetallePedido;
private Integer idPedidoCompra;
private Integer idProducto;
private BigDecimal precioUnitario;
private Integer unidadesPedidas;
//siguen setters y getters...
}

Ahora veamos el archivo de configuración de spring que hace que la magia de la instanciación y la inyección de componentes ó beans se lleve a cabo. El siguiente archivo lo colocamos en el directorio raiz de las clases java

pedido1.xml
<?xml version="1.0" encoding="UTF-8"?>

<!-- Definimos los namespaces que vamos a usar; recordar que un namespace define un enlace(Entre la instancia XML, este archivo, y el esquema con las reglas de formación que debe tener este archivo, el esquema está representado por una URL), el namespace en este archivo lo podemos identificar por la palabra clave xmlns, si despues de esta palabra clave hay dos puntos y otra palabra, pues esta otra palabra es llamada el prefijo que deberemos usar en el archvo XML(este archivo), para este caso el namespace principal que usamos es
beans xmlns="http://www.springframework.org/schema/beans" y como no está asociado a un prefijo pues su uso en ste archivo es a través de la palabra "beans"(ojo podemos usar cualquier otra palabra, es como si declararamos una variable), resumiendo lo dicho entre instancias Xml y esquemas Xsd pues como una analogía podemos tomar un esquema como una clase y un instancia Xml como una instancia(objeto) de esa clase.
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

<!--Definimos un bean proveedor-->
<!--Bueno ahora veamos que es lo que Spring hace cuando se encuentra con un bean como este, Spring lo que hará es crear una instancia con el nombre proveedor(atributo id) de la clase Proveedor(atributo class) y le asignará valores a cada una de sus propiedades.
Tambien lo podemos ver de la siguiente manera:
Proveedor proveedor = new Proveedor();
proveedor.setIdProveedor(1000);
proveedor.setNombreProveedor("CcySolutions");
proveedor.setNombreContacto("Carlos Cacique Yupanqui");
proveedor.setDireccion("Av. Tupac Amaru 094");
proveedor.setTelefono("989873846");
-->
<bean id="proveedor" class="pe.com.slcsccy.springbasico.dominio.Proveedor">
<property name="idProveedor" value="1000"/>
<property name="nombreProveedor" value="CcySolutions"/>
<property name="nombreContacto" value="Carlos Cacique Yupanqui"/>
<property name="direccion" value="Av. Tupac Amaru 094"/>
<property name="telefono" value="989873846"/>
</bean>

<!-- Definimos beans del tipo detalle de pedido-->
<!--
Una forma más simplificada de asignar los valores a las propiedades es usando el alias p del namespace http://www.springframework.org/schema/p
-->
<bean id="item1" class="pe.com.slcsccy.springbasico.dominio.DetallePedido"
p:idDetallePedido="1478" p:idPedidoCompra="1000" p:idProducto="1024"
p:precioUnitario="3000.14" p:unidadesPedidas="100"/>

<bean id="item2" class="pe.com.slcsccy.springbasico.dominio.DetallePedido"
p:idDetallePedido="1479" p:idPedidoCompra="1000" p:idProducto="1024"
p:precioUnitario="7800.14" p:unidadesPedidas="10"/>

<!--Tambien podemos signar los valores a las propiedades de la forma más usual-->
<bean id="item3" class="pe.com.slcsccy.springbasico.dominio.DetallePedido">
<property name="idDetallePedido" value="1480"/>
<property name="idPedidoCompra" value="1000"/>
<property name="idProducto" value="1026"/>
<property name="precioUnitario" value="800.14"/>
<property name="unidadesPedidas" value="17"/>
</bean>

<bean id="item4" class="pe.com.slcsccy.springbasico.dominio.DetallePedido"
p:idDetallePedido="1481" p:idPedidoCompra="1000" p:idProducto="1025"
p:precioUnitario="40.14" p:unidadesPedidas="50"/>

<!-- Ahora INYECTAMOS los beans anteriores al bean principal -->
<bean id="pedido1" class="pe.com.slcsccy.springbasico.dominio.PedidoCompra">
<!-- La siguiente linea INYECTA el bean proveedor a este bean(pedido1) -->
<property name="proveedor" ref="proveedor"/>
<property name="idPedidoCompra" value="100000"/>
<property name="numeroPedidoCompra" value="CX-TX-1000"/>
<property name="descripcionPedidoCompra" value="Pedido realizado."/>
<property name="fechaPedido" value="2009-08-15"/>
<property name="fechaEntrega" value="2009-08-17"/>

<!-- Las siguiente líneas INYECTARAN los items anteriores-->
<property name="detalle">
<list>
<ref bean="item1"/>
<ref bean="item2"/>
<ref bean="item3"/>
</list>
</property>
</bean>
</beans>

Ahora veamos la clase principal que levanta el archivo pedido1.xml y muestra los valores de cada instancia/objeto:

Inicio.java
package pe.com.slcsccy.springbasico;
import java.util.ArrayList;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import pe.com.slcsccy.springbasico.dominio.DetallePedido;
import pe.com.slcsccy.springbasico.dominio.PedidoCompra;
import pe.com.slcsccy.springbasico.dominio.Proveedor;

public class Inicio {

public static void main(String[] arg) {
//Instanciamos un contenedor de Spring:
ApplicationContext context = new ClassPathXmlApplicationContext(
new String[]{"pedido1.xml"});

PedidoCompra pedido1 = (PedidoCompra) context.getBean("pedido1");
System.out.println("Datos del Pedido:");
System.out.println("*****Descripción:" + pedido1.getDescripcionPedidoCompra());
System.out.println("*****Fecha Entrega:" + pedido1.getFechaEntrega());

Proveedor proveedor = pedido1.getProveedor();
System.out.println("Datos del Proveedor:");
System.out.println("*****Contacto:" + proveedor.getNombreContacto());
System.out.println("*****Nombre:" + proveedor.getNombreProveedor());

System.out.println("Detalle del pedido:");
ArrayList detalle = pedido1.getDetalle();
for (DetallePedido item : detalle) {
System.out.println("****Precio:"+item.getPrecioUnitario());
}
}
}

9 comentarios:

  1. Gracias. Justo lo que estaba buscando

    ResponderBorrar
  2. Q interesante para los q recien comenzamos.
    Lo he probado y me funko cambiando el arrayList al tipo DetallePedido
    y si funka.
    gracias

    ResponderBorrar
  3. No es web, es un proyecto simple ejecutable por consola.

    ResponderBorrar
  4. Consulta,
    En el ejemplo utilizas datos en duro,en el xml para DetallePedido: precioUnitario="40.14", unidadesPedidas="50", etc. A modo de ejemplo está claro.

    ¿En una aplicación real, la inyección de dependecias de Spring solo sirve para crear objetos, solo para reemplazar al "new"?.

    ResponderBorrar
  5. Es bueno comunicarse, pero que pasa si no responden o no publican tus comentarios...

    ResponderBorrar
  6. Hola anónimo, disculpa por no publicar tu comentario no sé porque se me paso. Bueno, en una aplicación real la inyección de dependencias de spring es usado para un tema muy importante de la ingeniería de software que es el desacoplamiento, en el ejemplo puedes inyectar los valores del detalle del pedido no en duro sino desde una capa de acceso a datos(DAO) sin importar la implementación de esta capa, por ejemplo puedes implementar el DAO con toplink o hibernate e inyectar esta implementación en forma transparente a tu aplicación sin tener que modificar la capa del modelo(el paquete que contiene la clase DetallePedido).

    ResponderBorrar
  7. Carlos me podrías ayudar una app
    spring web que tengas hecho en netbean o eclipse
    que tenga los método CRUD lo que login para la pagina con acceso a base de datos.
    Necesito soy nuevo en spring y le veo medio duro amigo

    ResponderBorrar
  8. los jar de spring para poder correr el proyecto cuales son?

    ResponderBorrar

Es bueno comunicarnos, comenta!!.