Usando Spring 2.5.6

La distribuccion de Spring ofrece varias funcionalidades, segun lo que queremos usar deberemos importar una o varias librerias de Spring.  Asi la version basica, que se encuentra en el jar Spring 2.5.6 ofrece las funcionalidades basicas de spring como contenedor, la libreria Spring AOP ofrece funcionalidad orientada a aspectos, etc....

Vamos a ver lo mas basico de Spring, el contenedor, como meter nuestros beans, como referenciarlos entre ellos para que se puedan comunicar.

Importar las librerias. Si usais maven, basta con añadir su dependencia:

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring</artifactId>
        <version>2.5.6</version>
    </dependency>

La configuracion de Spring se puede hacer mediante xml o mediante anotaciones. Yo prefiero usar xml, porque es menos intrusivo, que meter anotaciones referenciando nombres, que quizas cambiemos, o para realizar cualquier cambio tendriamos que volver a compilarlo todo, vamos, a mi me parece mas "sucio".
Pero vamos, para gustos los colores.
El archivo de configuracion de spring, puede tener cualquien nombre, pero ya que es un archivo donde vamos a definir los beans que van a estar en el contenedor (contexto de ejecucion de la aplicacion), lo voy a llamar context.xml. pero se puede llamar como sea. Este archivo debe estar accesible desde el classpath para que lo encuentren las libreias de Spring. (No es obligatorio, pero es recomendable que este en un path relativo).

Para ello, si seguimos una estructura maven, vamos a crear el archivo en la carpeta src/main/resources (todo lo que hay ahi, maven lo metera en el path de la aplicacion.

El archivo basico sera algo asi: (context.xml):


<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:jee="http://www.springframework.org/schema/jee"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
       http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd">

   <!-- y aqui dentro definimos los beans -->
    <bean id="bean_uno" class="org.dppware.persistence.dao.generic.GenericDAO">
 ...

    </bean>
</beans>


Vemos, que despues de toda la definicion de esquemas de spring, metemos nuestros beans. Para ello:
1.Definimos el nombre que queremos que tenga dentro del contenedor
2.Especificamos la clase del tipo que es.
Si nos fijamos, vemos que instancia objetos, a partir del nombre de la clase, esto esta de lujo, porque podemos instanciar por ejemplo un contexto de persistencia sin ejecutar siquiera una linea de codigo. Falta con definir el bean en el xml, y decirle los parametros de inicio. Cuando Spring vaya a instanciar dicho bean, le pasara los argumentos y ya estara instanciado en nuestro contenedor para que lo usemos.

Los Beans
Instanciacion:
Vemos que con definir el nombre y la clase, nos valdria, pero supongamos que nuestro bean , necesita algunos parametros en el constructor. Queremos que Spring se los pase al crearlo. Para ello imaginemos nuestro bean muy basico:

public class webserviceClient{
       private String url_connection;
       public webserviceClient (String url_conection){
            this.url_connection = url_connection;
      }

}

Para pasarle esos argumentos en el constructor, usaremos esta definicion de bean, ojo a los parametros:

<bean id="webserviceClientBean" class="org.dppware.webservices">
            <constructor-arg type="java.lang.String" value="http://www.webservices.com/service1" />  

</bean>

De esta forma le pasamos argumentos al constructor, que los usara para lo que quiera.
Este metodo de trabajo esta de lujo, por si queremos usar clases de carga de persistencia, con pasarle los parametros, ya tendriamos ese bean en el contenedor. Y si quisieramos cambiar la conexion, basta con cambiar el xml (otro motivo mas, por el que usar mejor xml).

Si quisieramos pasar mas de un parametro al constructor, podemos especificar el orden de los argumentos con el atributo "index":
Por ejemplo
      public webserviceClient (String url_conection, int timeOut){
            this.url_connection = url_connection;
             this.timeOut = timeOut;
      }
Los argumentos quedarian asi, en la definicion del bean:
 <bean id="webserviceClientBean" class="org.dppware.webservices">

<constructor-arg index="0" value="http://www.webservices.com/service1"/>
  <constructor-arg index="1" value="4000"/>
</bean>

Con index, especificamos el orden.


Referencias entre Beans:
Generalmente nuestras clases necesitan de otras clases para interacturar. Por ejemplo vamos a ampliar el antiguo bean:

public class webserviceClient{
       private String url_connection;
       private BBDDManager dao;
  
       public webserviceClient (String url_conection){
            this.url_connection = url_connection;

       }


      public void setDao (BBDDManager dao){
         this.dao = dao
       }



}

Nos fijamos, que nuestro bean , necesita de otro bean , pero no se lo queremos pasar en el constructor
Para meterle la referencia al BBManager, habria que :
1.Definir el BBDDManager como un bean disponible en el contexto
2.Meter en nuestro webserviceClient una referencia a ese bean, para que spring se lo inyete.

Asi quedara mas o menos:
    
      <bean id="daoBean" class="org.dppware.persistence.BBDDManager">
        <!--Este aqui dentro tendria su definicion de propiedades, si se quisiera meter-->

     </bean>


       <bean id="webserviceClientBean" class="org.dppware.webservices">
            <constructor-arg type="java.lang.String" value="http://www.webservices.com/service1" />  

           <property name="dao" ref="daoBean"/>  <!--Aqui es donde esta la referencia-->
      </bean>

Cuando Spring instancie el webserviceClientBean, le pasara en el constructor el argumento puesto.Tambien buscara el metodo setDao (convencion de nombres de sun ) para meterle el bean que le hemos especificado en la propiedad "ref"

De esta manera podemos inyectar unos beans en otros sin tocar codigo de nuestra aplicacion, unicamente usando spring y su xml. Si quisieramos cambiar la implementacion de los beans a usar, bastaria con cambiar el xml (si lo hubieramos hecho con anotaciones, tendriamos que volver a compilarlo todo, un rollo en mi opinion).

LO BUENO DE SPRING
Lo bueno de instanciar los objetos y tenerlos en el contenedor es que podemos instanciar clases sin tirar una linea de codigo, por ejemplo, podemos instanciar un datasource sin tirar una linea de codigo y utilizarlo mediante otras clases.
Por ejemplo, vamos a crear un datasource y lo crearemos como bean en el contenedor:

<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
  
  <!-- results in a setDriverClassName(String) call -->
  <property name="driverClassName">
    <value>com.mysql.jdbc.Driver</value>
  </property>
  <property name="url">
    <value>jdbc:mysql://localhost:3306/mydb</value>
  </property>
  <property name="username">
    <value>root</value>
  </property>
  <property name="password">
    <value>masterkaoli</value>
  </property>
</bean>


Ahi hemos creado un bean, de tipo datasource (llamado "mydatasource") que se conecta a una bbdd, sin tirar una sola linea de codigo. Si quisieramos utilizarlo en nuestro bean, bastaria con hacer esto:

1.Crear nuestra clase:

public class usuariosDAO{
         private BasicDataSource datasource:
         public void setDatasource(BasicDataSource datasource){
               this.datasource = datasource;
        }
}


2. Editar el fichero de contexto para inyectar el datasource en nuestro bean:

       <bean id="usuariosDAOBean" class="org.dppware.usuariosDAO">
           <property name="datasource" ref="mydatasource"/><!-nombre de la propiedad y tipo de objeto que debe meter-->
      </bean>


con este poco codigo, ya tenemos una clases con acceso a un datasource, sin hacer ni un "new" ni un nada, y que spring se encarga de gestionarlo.

Cuando hablan de que spring integra con hibernate, con jersey y con demas framework, quiere decir que podemos instanciar los motores de estos frameworks directamente definiendo el/los beans que se requieran en nuestro xml.

Hazme caso, Spring te quita mucho trabajo!!


NOMENCLATURAS:
Las referencias, las propiedades y demas cosas del xml se pueden escribir de varias maneras, es decir:

Estas 2 expresiones son equivalentes:

<property name="beanOne"><ref bean="otroBean"/></property>
<property name="beanOne" ref="otroBean"/> 
Pero la segunda es mas "elegante", pero valen las 2.
Asi tambien son equivalentes las siguientes definiciones:
 
<property name="url">
    <value>jdbc:mysql://localhost:3306/mydb</value>
</property>
 
<property name="url" value="jdbc:mysql://localhost:3306/mydb" />
 
 
INSTANCIANDO EL CONTEXTO 
Segun el tipo de aplicacion que estemos montando (Aplicacion web, aplicacion 
escritorio, batch, etc..)
Spring nos ofrece diversas maneras de "levantar" o crear su contexto. 
 
Para acceder al contexto Spring nos da el uso de clases
ApplicationContext, dependiendo de la naturaleza del proyecto podremos obtenerlo 
de diversas maneras .
 
Asi la mas basica es mediante lectura de xml
 
Carga basica por XML
ApplicationContext context = new ClassPathXmlApplicationContext(
             new String[] {"context.xml"});
 
Ojo, acepta un array de String, es decir un array con los nombres de ficheros que 
tiene definicion de beans en nuestra aplicacion, es decir, no hace falta definir 
todos los beans en un mismo xml, se pueden cargar varios:
 
ApplicationContext context = new ClassPathXmlApplicationContext(
             new String[] {"context.xml", "/spring_dao_context/context.xml}); 
 
Applicacion web
Para instanciar un contexto en una aplicacion web, Spring nos ofrece unas clases 
que se pueden añadir como listeners en nuestro web.xml y desde ella manejar el 
contexto.
 
Hay que añadir estas lineas en nuestro web.xml
 
<context-param>
     <param-name>contextConfigLocation</param-name>
     <param-value>/WEB-INF/applicationContext.xml</param-value>
     <param-value>/WEB-INF/anotherContext.xml</param-value>
</context-param>

<listener>
     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
 
Fijarse, que, al igual que en el anterior metodo, le paso varios archivos que 
contienen la definnicion de beans, si fuera necesario.
 
Para acceder al applicationContext (si lo necesitaramos), se realizaria con la 
siguiente instruccion:
 
WebApplicationContext ctx = ContextLoader.getCurrentWebApplicationContext();
 
Es importante acceder con el getCurrentApplicationContext(), que nos devuelve el 
contexto actual que se acaba de generar.
 
 
 
CARGA DE VARIOS ARCHIVOS DE DEFINICION DE BEANS
 
Hemos visto, que podemos pasarle al constructor del contexto, varios archivos donde
tengamos nuestros beans, vamos que no hace falta que sea uno solo.
Tambien podemos hacer esto desde dentro de un xml , referenciando a otros. 
Basta con añadir las siguientes lineas en nuestro fichero de definnicion de contexto:
 
<beans xmlns="http://www.springframework.org/schema/beans" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"....bla bla >
 
<import resource="classpath*:directorio1/context-beans-definition1.xml"/>
<import resource="classpath*:directorioB/context-beans-definition2.xml"/> 
 
</beans>
Con esto ya nos importara la configuracion de dichos archivos.
Quizas este metodo es mas limpio para centralizar todos los archivos en uno.
Para gustos....
 
 
Espero te haya sido de ayuda. Ya sabes, a compartir!!!

Comentarios

Entradas populares de este blog

Lectura sencilla de XML en Java , SAX (Simple API for XML)

Reiniciar usuario de SVN Subversion

Subir campos Blob a BBDD (Oracle) con Java