0% encontró este documento útil (0 votos)
354 vistas

Manual Spring

El documento introduce Spring, un framework Java popular que ayuda a simplificar el desarrollo de aplicaciones mediante la automatización de tareas comunes y la integración con otros frameworks. Spring se basa en los principios de inyección de dependencia e inversión de control para coordinar los componentes de una aplicación de forma no intrusiva. El documento explica brevemente los principales módulos de Spring y sus beneficios.
Derechos de autor
© Attribution Non-Commercial (BY-NC)
Formatos disponibles
Descarga como DOC, PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
354 vistas

Manual Spring

El documento introduce Spring, un framework Java popular que ayuda a simplificar el desarrollo de aplicaciones mediante la automatización de tareas comunes y la integración con otros frameworks. Spring se basa en los principios de inyección de dependencia e inversión de control para coordinar los componentes de una aplicación de forma no intrusiva. El documento explica brevemente los principales módulos de Spring y sus beneficios.
Derechos de autor
© Attribution Non-Commercial (BY-NC)
Formatos disponibles
Descarga como DOC, PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 44

jueves, 2 de septiembre de 2010 Spring 3 - Parte 1: Introduccin En la actualidad el desarrollo de aplicaciones empresariales, aunque es ms sencillo ya que hay muchas

herramientas, APIs, y Frameworks; los cuales aunque son opcionales, el aprender a usarlos nos ayudar a desarrollar nuestras aplicaciones en menos tiempo y a que estas sean ms robustas y contengan menos errores. Tambin se vuelve un poco ms complicado porque nuestras aplicaciones deben ser capaces de conectarse con otras aplicaciones y servicios. Adems, como desarrolladores, somos los responsables de coordinar cada una de las partes de nuestra aplicacin para que todo funcione correctamente. Por si no fuera suficiente, debemos tomar en cuenta que debemos darle mantenimiento a nuestras aplicaciones, y que en algunos casos ser necesario que cambiemos mdulos o capas enteras de la misma para mejorarla; como por ejemplo sustituir nuestras consultas JDBC con Hibernate en los casos en los que sea prudente. Afortunadamente existen super-frameworks que nos ayudan hacindose cargo de todas o casi todas las complicaciones mencionadas anteriormente. Spring es el ms popular de estos super-frameworks Java. Nos proporciona varios mdulos los cuales abarcan la mayor parte de las cosas que debemos hacer en cualquiera de las capas de nuestras aplicaciones, desde plantillas para trabajar con JDBC o invocacin de Web Services y JMS, pasando por sus propias soluciones, ORM o MVC (web), hasta integracin con otros frameworks, como Struts 2, Hibernate, JSF, etc. Todo esto de una forma elegante y haciendo uso de muchos buenos principios de programacin. Adems Spring maneja la infraestructura de la aplicacin, por lo que nosotros solo deberemos preocuparnos de la lgica de la misma (y de la configuracin de Spring). En esta serie de tutoriales aprenderemos como usar Spring, en su versin 3, para facilitarnos la vida en el desarrollo de nuestras aplicaciones Java. Para aprender a usar Spring de forma correcta hay que ver muuucha teora, as que en este primer tutorial hablaremos solo de los conceptos bsicos de Spring y explicar cada una de las partes, junto con su teora correspondiente, en el post correspondiente. Spring es, como lo definen sus autores, un framework ligero para construir aplicaciones empresariales. Aunque Spring se encuentra dividido en distintos mdulos, cada uno de los cuales se encarga de partes diferentes de nuestra aplicacin, no deja de ser un monstruo, ya que es tan grande que alguien podra nunca usar todos estos mdulos en aplicaciones pequeas o medianas; pero en aplicaciones grandes o realmente grandes puede ahorrarnos mucho trabajo ya que puede coordinar todas las partes de la aplicacin. Esta separacin en mdulos nos permite usar solo las partes que necesitamos, sin tener la carga de los que no usemos. Spring est diseado para no ser intrusivo, esto significa que no es necesario que nuestra aplicacin extienda o implemente alguna clase o interface de Spring (si no lo queremos), por lo que nuestro cdigo de lgica quedar libre y completamente reutilizable para un proyecto sin Spring, o por si debemos quitarlo de una aplicacin que ya lo est usando. Gracias a esto es posible usar un POJO o un objeto Java para hacer cosas que antes solo podan hacerse con EJBs. Sin embargo la utilidad de Spring no es solo para el desarrollo de aplicaciones web, o no solo en el servidor. Cualquier aplicacin Java puede beneficiarse del uso de Spring. Adems, si usamos Spring de la forma correcta (lo cual no es difcil) nuestra aplicacin quedar dividida en capas bien delimitadas, y con buenas prcticas de programacin. El ncleo de Spring est basado en un principio o patrn de diseo llamado Inversin de Control (IoC por sus siglas en ingls). Las aplicaciones que usan el principio de IoC se basan en su configuracin (que en este caso puede ser en archivos XML o con anotaciones como en Hibernate) para describir las dependencias entre sus componentes, esto es, los otros objetos con los que interacta. En este caso inversin significa que la aplicacin no controla su estructura; permite que sea el framework de IoC (en este caso Spring) quien lo haga. Por ejemplo, supongamos que tenemos una clase AlmacenUsuario, que depende de una instancia de una clase UsuariosDAO para realizar su tarea. AlmacenUsuario crea una instancia de UsuariosDAO usando el operador new u obtiene una de algn tipo de Fabrica. Usando la tcnica de IoC, una instancia de UsuariosDAO, o una subclase de esta, es proporcionada a AlmacenUsuario en tiempo de ejecucin por el motor de Spring. En este caso UsuariosDAO tambin podra ser una interface y Spring se encargar de proporcionarnos una instancia de una clase que implemente esa interface. Esta inyeccin de dependencia en tiempo de ejecucin ha hecho que a este tipo de IoC se le d el nombre ms descriptivo de inyeccin de dependencia (DI por sus siglas en ingls). El concepto importante es que los componentes no saben cul implementacin concreta de otros componentes estn usando; solo ven sus interfaces. El uso de interfaces y DI son mutuamente benficos, ya que hace ms flexible y robusta nuestra aplicacin y es mucho ms fcil realizar pruebas unitarias. Pero la complejidad de escribir cdigo que maneje las dependencias entre los componentes de una aplicacin diseada para usar interfaces puede llegar a ser mucho y esto, adems, hace que los desarrolladores tengamos que escribir an ms cdigo. Afortunadamente, usando DI reducimos la cantidad de cdigo extra que debemos escribir, para un diseo basado en interfaces, casi a cero.

En el contexto de DI, Spring acta como un contenedor que proporciona las instancias de las clases de nuestra aplicacin todas las dependencias que necesita, pero en una forma no intrusiva y automtica. Todo lo que debemos hacer es crear un archivo de configuracin que describa las dependencias; Spring se har cargo del resto. Como dije antes: Spring es un contenedor ya que no solo crea los componentes de nuestra aplicacin, sino porque contiene y maneja al ciclo de vida y configuracin de estos componentes. En Spring, podemos declarar cmo debe ser creado cada uno de los objetos de nuestra aplicacin, cmo deben ser configurados, y cmo deben asociarse con los dems. La implementacin de DI de Spring se enfoca en el acoplamiento dbil: los componentes de nuestra aplicacin deben asumir lo menos posible acerca de otros componentes. La forma ms fcil de lograr este bajo acoplamiento en Java es mediante el uso de Interfaces. Como cada componente de la aplicacin solo est consciente de la interface de otros componentes, podemos cambiar la implementacin del componente sin afectar a los componentes que usan el nuevo componente. Hablar un poco ms de esto cuando veamos los ejemplos. El uso de DI tiene como beneficios, adems de lo que ya he mencionado arriba, los siguientes: Reduce el cdigo pegamento: Esto quiere decir que reduce dramticamente la cantidad de cdigo que debemos escribir para unir los distintos componentes. Aunque algunas veces est cdigo puede ser tan simple como usar el operador new para instanciar un nuevo objeto, otras puede ser ms complejo, como realizar una bsqueda de dicha dependencia en un repositorio a travs de JNDI, como en el caso de los recursos remotos. En esto caso, el uso de DI puede reducir de forma dramtica la cantidad de cdigo pegamento (o glue code) proporcionando bsquedas automticas. Externaliza dependencias: Como es posible colocar la configuracin de dependencias en archivos XML podemos realizar una reconfiguracin fcilmente, sin necesidad de recompilar nuestro cdigo. Gracias a esto es posible realizar el cambio de la implementacin de una dependencia a otra (como en el ejemplo de Hibernate que mencion antes) Las dependencias se manejan en un solo lugar: Toda la informacin de dependencias es responsabilidad de un solo componente, el contenedor de IoC de Spring, haciendo que este manejo de dependencias ms simple y menos propenso a errores. Hace que las pruebas sean ms fciles: Nuevamente, como nuestras clases sern diseadas para que sea fcil el reemplazo de dependencias, podemos proporcionar mocks o dummies, que regresen datos de prueba, de servicios o cualquier dependencia que necesite el componente que estamos probando.

Como podemos ver, el uso de DI nos proporciona muchos beneficios, pero no sin sus correspondientes desventajas. En particular, es difcil ver qu implementacin particular de una dependencia est siendo usada para qu objeto, especialmente para alguien que no est familiarizado con esta forma de trabajo. Y por qu tanto hablar de DI? Pues porque estos dos conceptos (IoC y DI) son los puntos centrales alrededor del cual gira todo en Spring, as que es mejor entenderlos desde el principio ^_^. Como dije: Spring est dividido en alrededor de 20 mdulos y colocados en los siguientes grupos: Contenedor Central (Core Container) Acceso a Datos / Integracin WEB AOP (Programacin Orientada a Aspectos) Instrumentacin Pruebas

Estos grupos se muestran en la siguiente imagen:

A lo largo de estos tutoriales tratar de explicar la mayor cantidad de mdulos. Pero como dije antes: Spring es en realidad un monstruo. As que probablemente cuando termine de explicarlos todos, ya habr salido una nueva versin, as que me centrar solo en los ms importantes y en su integracin con otros frameworks que comencemos a usar en otros tutoriales. En general, estas son algunas de las caractersticas de Spring:

Simplificacin de la programacin orientada a aspectos. Simplificacin del acceso a datos. Simplificacin e integracin con JEE Soporte para planificacin de trabajos. Soporte para envi de mail. Interaccin con lenguajes dinmicos (como BeanShell, JRuby, y Groovy). Soporte para acceso a componentes remotos. Manejo de Transacciones. Su propio framework MVC. Su propio Web Flow. Manejo simplificado de excepciones.

La versin 3 de Spring es una versin revisada y mejorada de la versin estable anterior (2.5), que incluye nuevas caractersticas, entre las que se incluyen:

Soporte para Java 5: Proporciona configuracin basada en anotaciones y soporta caractersticas como varargs y generics, adems la parte web es compatible con las versiones 1.4 y 5 de Java EE. Debido a esta nueva caracterstica, ahora es necesario tener el JRE versin 5 o superior. Lenguaje de Expresiones (SpEL): En esta nueva versin se incluye un lenguaje de expresiones que puede ser usando cuando se definen beans, tanto en XML como con anotaciones y tambin da soporte a travs de todos los mdulos de Spring. Soporte para Servicios Web REST: Ahora Spring soporte servicios web de tipo REST. Soporte para Java EE6: Ofrece soporte de caractersticas como JPA 2.0, JSF 2.0 y JRS 303 (validaciones de Beans). Soporte para bases de datos embebidas: Un soporte conveniente para bases de datos embebidas como HSQL, H2 y Derby. Soporte para formateo de datos mediante anotaciones: Ahora los campos de fecha, divisas, etc., sern formateados automticamente y convertidos usando anotaciones. Nueva organizacin de los mdulos: Los mdulos han sido revisados y separados en diferentes paquetes, mas organizados, de acuerdo a su funcionalidad. Para que se den una idea, estos son los nuevos paquetes: o org.springframework.aop o org.springframework.beans o org.springframework.context o org.springframework.context.support o org.springframework.expression o org.springframework.instrument o org.springframework.jdbc o org.springframework.jms o org.springframework.orm o org.springframework.oxm o org.springframework.test o org.springframework.transaction o org.springframework.web o org.springframework.web.portlet o org.springframework.web.servlet o org.springframework.web.struts

A lo largo de estos tutoriales veremos algunos de estos paquetes. Aunque este post, como ya se habrn dado cuenta es solo de teora, crearemos la librera para NetBeans de Spring que estaremos usando en esta serie de tutoriales. As que lo primero que haremos es abrir el NetBeans. En realidad el NetBeans 9 ya tiene una biblioteca de Spring 3, la 3.0.2. Pero han salido actualizaciones desde esta versin (actualmente la versin ms nueva es la 3.0.4). As que lo que haremos es crear una nueva biblioteca que har uso de los jars que necesitamos (y los cuales iremos incrementando en cada tutorial). Bajamos la ltima versin de Spring de su pgina de descargas. Tambin necesitaremos el archivo commons-logging-api-1.1.1.jar que podemos encontrar en la pgina de descarga de commons-logging, en el archivo "commons-logging-1.1.1-bin.zip, tal y como lo hicimos en los tutoriales de JasperReports. Una vez que hayamos bajado el archivo de Spring, lo descomprimimos y veremos que tiene un subdirectorio dist el cual contiene todos los jars de Spring para cada uno de sus mdulos. Vamos al NetBeans y nos dirigimos al men Tools -> Libraries.

En la ventana que se abre presionamos el botn New Library...:

En esta nueva ventana colocamos como nombre de la biblioteca "Spring3" y como tipo dejamos "Class Libraries":

Ahora que tenemos nuestra biblioteca , presionamos el botn Add Jar/Folder para agregar los nuevos archivos que conformarn la biblioteca:

Agregamos a la biblioteca los siguientes archivos:

org.springframework.asm-3.0.4.RELEASE.jar org.springframework.beans-3.0.4.RELEASE.jar org.springframework.context-3.0.4.RELEASE.jar org.springframework.core-3.0.4.RELEASE.jar org.springframework.expression-3.0.4.RELEASE.jar commons-logging-api-1.1.1.jar (que bajamos aparte)

Con estos es suficiente para hacer nuestros hola mundo iniciales :D. Una vez seleccionados estos archivos, nuestra biblioteca debe verse as:

Presionamos el botn OK y nuestra biblioteca estar lista para ser usada en los siguientes tutoriales ^_^. Por el momento hemos cubierto una muy pequea parte de la teora con respecto a Spring 3, que iremos ampliando en los siguientes posts, as que no desesperen, pronto comenzaremos a usar este framework, que muchas alegras (y dolores de cabeza) nos dar a ms de uno. No olviden dejar cualquier comentario, duda o sugerencia en la seccin de comentarios. Saludos. jueves, 23 de diciembre de 2010 Spring 3 - Parte 2: Contenedores de IoC e Inyeccin de Dependencias Como vimos en el primer tutorial de la serie, el core de Spring se basa en el concepto de Inversin de Control (IoC por sus siglas en ingls), ms especficamente en la Inyeccin de Dependencias (DI). Este es un proceso en el cual los objetos definen sus dependencias (o sea, los otros objetos con los que trabajan) solo a travs de los argumentos de su constructor, argumentos a un mtodo de factory, o mtodos setter que son invocados despus de que el objeto se ha construido. En este caso en vez de ser el mismo objeto quien se encargue de instanciar, o localizar, las dependencias con las que trabaja (usando directamente su constructor o un localizador de servicios), es el contenedor el que inyecta estas dependencias cuando crea al bean. Este proceso, como podemos observar, es el inverso al que normalmente se hace, y de ah el nombre de Inversin de Control (es el framework el que hace el trabajo, no el programador ^_^). En este tutorial veremos como configurar Spring de 4 formas distintas para que realice este proceso de Inyeccin de Dependencias de forma automtica Spring coloca las clases bsicas de su contenedor de IoC en dos paquetes:

org.springframework.beans org.springframework.context

Estos paquetes contienen dos interfaces que son las que realizan la "magia" de la instanciacin de objetos. La primera es "org.springframework.beans.factory.BeanFactory", que proporciona un mecanismo de configuracin avanzada capaz de manejar cualquier tipo de objeto. Adems proporciona una sub-interface de esta ltima, "org.springframework.context.ApplicationContext", la cual agrega una integracin ms fcil con algunas de las caractersticas ms interesantes de Spring, como su mdulo de Programacin Orientada a Aspectos, manejo de recursos de mensajes (para la internacionalizacin), publicacin de eventos, y contextos especficos para ciertas capas de aplicaciones (como aplicaciones web), entre otras. "BeanFactory" proporciona el framework de configuracin y la funcionalidad bsica, mientras que "ApplicationContext" agrega ms funcionalidad especfica para ciertos productos empresariales. Ambas interfaces representan contenedores de beans, solo que de tipos distintos.

"BeanFactory" representa las fbricas de beans y son el tipo de contenedor ms simple. Este proporciona el soporte bsico para DI. "ApplicationContext" representa... el contexto de la aplicacin, estos estn construidos con las mismas nociones de las fbricas de beans, pero proporcionan a la aplicacin servicios adicionales. En Spring, los objetos que forman la columna vertebral de las aplicaciones, y que son administradas por el contenedor de IoC de Spring, son llamados "Beans". Un bean es un objeto que es instanciado, ensamblado (cuando sus dependencias son inyectadas), y en general, administrado por el contenedor de IoC. Dicho de otra forma: un bean es simplemente uno de muchos objetos de nuestra aplicacin. Los Beans, y las dependencias entre ellos, las declaramos en los metadatos del contenedor de IoC (lo cual puede ser mediante anotaciones o archivos de mapeo). Como dije antes: la interface "ApplicationContext" representa un tipo de contenedor de IoC de Spring, y es el responsable de instanciar, configurar, y ensamblar los antes mencionados beans. El contenedor obtiene la informacin de qu objetos debe crear leyendo los metadatos de la configuracin, los cuales, como dije antes, pueden ser colocados en archivos XML, anotaciones, o dentro del cdigo Java. Spring proporciona muchas implementaciones de "ApplicationContext". En particular en las aplicaciones que NO son web, usamos "org.springframework.context.support.ClassPathXmlApplicationContext", que busca los archivos de configuracin dentro del classpath, o "org.springframework.context.support.FileSystemXmlApplicationContext", que los busca en el sistema de archivos de la mquina donde se ejecute la aplicacin. Para ejemplificar todo esto, haremos una aplicacin la cual tendr una clase de prueba que invocar a un "ServicioRemoto". Este servicio no har algo especial, solamente regresar un nmero aleatorio entre 0 y 10; lo interesante de esto es que el cliente obtendr una instancia del ServicioRemoto sin tener que crearla de manera directa, sino usando la DI de Spring. Lo primero que haremos es crear un nuevo proyecto en NetBeans. Para esto vamos al Men "File->New Project...". En la ventana que se abre seleccionamos la categora "Java" y en el tipo de proyecto "Java Application". Le damos una ubicacin y un nombre al proyecto, en mi caso ser "SpringIoC". Nos aseguramos que las opciones "Create Main Class" y "Set as Main Project" estn habilitadas. Presionamos el botn "Finish" y veremos aparecer en el editor nuestra clase "Main". Nota: Yo usar dos proyectos, uno para usar archivos de mapeo y otro para usar anotaciones y que el cdigo de ambos no se mezcle. Agregamos la biblioteca de "Spring 3" que creamos en el primer tutorial de la serie. Hacemos clic derecho sobre el nodo "Libraries" del proyecto, en el men que aparece elegimos la opcin "Add Library..."

En la ventana que se abre seleccionamos la biblioteca "Spring 3":

Y presionamos el botn "Add Library". Con esto los archivos de la biblioteca deben agregarse a nuestro proyecto:

Ahora crearemos un nuevo paquete que contendr a nuestros beans, este paquete se llamar "beans". Hacemos clic derecho en el paquete en el que se encuentra nuestra clase "Main" (que en mi caso es "ejemplos.spring.ioc") y en el men que se abre seleccionamos la opcin "New -> Java package..." y al nombre del paquete le agregamos "beans". Presionamos el botn "Finish" y con esto aparecer nuestro nuevo paquete:

Crearemos nuestra clase "ServicioRemoto", dentro del paquete "beans". Esta clase ser muy sencilla, y solo tendr un mtodo llamado "consultaDato" el cual no recibir ningn parmetro y regresar un "int" aleatorio entre 1 y 10. La clase "ServicioRemoto" queda de esta forma: public class ServicioRemoto { public int consultaDato() { return (int)(Math.random()*10.0); } } Como ven es una clase sumamente sencilla, as que no har falta explicar mucho. Normalmente para obtener una nueva instancia de "ServicioRemoto" tendramos que colocar la siguiente lnea en alguna parte de la clase de prueba: servicioRemoto = new ServicioRemoto(); Como haba dicho antes: el cliente no debera ser responsable de la instanciacin de este ServicioRemoto, ya que es una tarea que no le corresponde. Gracias a la DI podremos evitarnos el escribir la lnea anterior, y por lo tanto (como veremos un poco ms adelante) muchos problemas potenciales que pueden surgir con ella. En Spring, los objetos no son responsables de encontrar o crear los otros objetos que necesitan para hacer su trabajo. En vez de eso, el contenedor les da las referencias de los objetos con los que colaborarn. El acto de crear estas asociaciones entre objetos de la aplicacin, usando DI, es llamado "wiring" (cableado en espaol). En el resto del tutorial veremos la configuracin bsica de este wiring con Spring, y veremos las posibilidades que este nos ofrece. En las aplicaciones basadas en Spring, los objetos de la aplicacin viven dentro del contenedor de beans. El contenedor se encarga de crear los objetos y "cablearlos", configurarlos, y administrar su ciclo de vida completo. Entender la forma en la que funciona este contenedor, nos permitir comprender la forma en la que nuestros objetos

sern

manejados,

por

lo

tanto

cmo

podemos

aprovecharlos

mejor

dentro

de

nuestra

aplicacin.

Configuracin de Beans en Spring Como mencione al principio: existen, bsicamente, dos formas de configurar los beans y sus dependencias en Spring, la primera es mediante un archivo de configuracin en XML, la segunda es mediante anotaciones proporcionadas por Spring. Como siempre, cada una tiene sus ventajas y sus desventajas. Nosotros veremos ambas formas de configuracin. Iniciaremos viendo la configuracin con archivos en XML y posteriormente pasaremos a verla con anotaciones. 1. Configuracin con archivos XML La configuracin de Spring consiste de, al menos, la definicin de un bean que ser administrado por el contenedor. Los metadatos de configuracin basados en XML muestran estos beans configurados como elementos "<bean />" (sin s) dentro de un elemento "<beans />" (con s). Estas definiciones de beans corresponden con los objetos que componen nuestra aplicacin. Cuando creamos una aplicacin, tpicamente definimos una capa de servicios, una capa de acceso a datos (o DAOs) una capa de presentacin, y una capa de infraestructura (con objetos como el "SessionFactory" de Hibernate). En Spring normalmente declaramos objetos que definen estas 4 capas (y no objetos muy especficos del dominio), ya que son las capas anteriores quienes se encargan de crear y manejar los objetos del dominio. Crearemos el archivo de configuracin en nuestro proyecto, as que hacemos clic derecho sobre el nodo "Source Packages" de nuestro proyecto, y en el men contextual que se abre seleccionamos "new -> Other...":

En la ventana que se abre, seleccionamos la categora "Other" y como tipo de archivo "Spring XML Configuration File":

Le damos un nombre al archivo, en mi caso ser "applicationContext". Hacemos clic en el botn "Next". En la siguiente pantalla debemos seleccionar los namespaces que queremos que tenga nuestro archivo. No seleccionaremos ninguno. Ms adelante en este mismo tutorial explicar qu es esto. Presionamos el botn "Finish" y con eso aparecer en nuestro editor el archivo "applicationContext.xml" con el siguiente contenido:

<?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"> </beans>

El archivo contiene nicamente el elemento raz "<beans>" dentro del cual declararemos cada uno de nuestros beans usando un elemento "<bean>" para cada uno ^_^. Lo siguiente que haremos es declarar nuestro bean "ServicioRemoto" para que el contenedor de Spring lo administre. Para esto declaramos un elemento "<bean>" en nuestro archivo de configuracin: <bean /> El elemento "<bean>" es la unidad de configuracin ms bsica en Spring, le dice que cree y administre un objeto. Debemos darle un identificador a cada uno de nuestros beans dentro de la aplicacin; esto no es obligatorio pero si no lo hacemos no podremos distinguir a los beans con los que trabajamos (normalmente NO especificamos un identificador cuando los usamos como beans internos). Estos deben estar identificados de manera nica dentro del contenedor que tiene al bean. Un bean por lo regular solo tiene un identificador (aunque hay formas de colocarle ms en caso de ser necesario). En esta configuracin basada en XML usamos el atributo "id" o el atributo "name" para especificar el identificador del bean. El atributo "id" nos permite especificar exactamente un identificador, esto es porque hace uso del elemento "id" real de la especificacin XML, lo que nos permite algunas validaciones extra con parsers normales de XML, sin embargo nos limita al uso de caracteres que son legales en XML para definir este identificador. Si necesitamos usar algn carcter especial como identificador, o si queremos indicar algn alias para nuestro bean, podemos usar el atributo "name", separando los alias con una coma (,), un punto y coma (;), o un espacio en blanco. Para este bean, usaremos el identificador "servicioRemoto": <bean id="servicioRemoto" /> Ahora nuestro bean puede ser referenciado por el nombre de "servicioRemoto". El ltimo paso que debemos hacer en nuestro archivo de configuracin es decirle a Spring de qu tipo es el bean, esto es, la clase de la que queremos que cree los objetos. Para hacer esto usamos el atributo "class". En este caso el bean ser de tipo "ejemplos.spring.ioc.beans.ServicioRemoto". Por lo que la configuracin de nuestro bean queda de la siguiente forma:

<bean id="servicioRemoto" class="ejemplos.spring.ioc.beans.ServicioRemoto" /> Y el archivo de configuracin queda as: <?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="servicioRemoto" class="ejemplos.spring.ioc.beans.ServicioRemoto" /> </beans> Ahora que tenemos nuestro archivo de configuracin listo ha llegado el momento tan esperado, ahora usaremos uno de los contenedores de Spring para crear nuestros beans. Como haba dicho, hay dos tipos de contenedores los "BeanFactory" y los "ApplicationContext". Veremos cmo usar estos dos tipos de contenedores. 1.1 Archivos XML con BeanFactory Como podemos imaginarnos por su nombre, un BeanFactory es una implementacin del patrn de diseo factory. Esto es, una clase cuya responsabilidad es crear beans. BeanFactory hace ms que solo crear objetos. Como un BeanFactory conoce a los objetos que aplicacin (los declarados en el archivo de configuracin), es capaz de crear las asociaciones entre momento de ser instanciados. Adems, como el BeanFactory tiene el control del ciclo de vida del llamadas a mtodos personalizados de inicializacin y destruccin (si estos mtodos componen nuestra estos objetos en el bean, puede hacer estn definidos).

Hay muchas implementaciones de la interface "BeanFactory" (supuestamente, porque yo solo conozco una). La ms usada (y la nica que conozco) es "org.springframework.beans.factory.xml.XmlBeanFactory", el cual carga los beans basndose en la configuracin del archivo XML que creamos hace un momento. Para crear un "XmlBeanFactory" debemos indicar de dnde se leer este XML, ya que podemos obtenerlo de un stream, de un archivo en nuestro classpath, hasta de un arreglo de bytes. Para esto usamos una instancia de "org.springframework.core.io.Resource". Spring proporciona varias implementaciones de esta interface:

org.springframework.core.io.ByteArrayResource Permite cargar contenido de un arreglo de bytes. Segn la documentacin es til para crear adjuntos de mail de contenido local. org.springframework.core.io.ClassPathResource Carga la configuracin desde un recurso que se encuentre en el classpath de la aplicacin. Este es el que normalmente estaremos usando. org.springframework.core.io.FileSystemResource Carga la configuracin desde un archivo situado en cualquier parte de la mquina. org.springframework.core.io.InputStreamResource Carga la configuracin desde un InputStream org.springframework.web.portlet.context.PortletContextResource Carga la configuracin desde un recurso que est disponible en el contexto de un portlet. org.springframework.web.context.support.ServletContextResource Carga la configuracin desde un recurso que est disponible en el contexto de una aplicacin web. org.springframework.core.io.UrlResource Carga la configuracin desde un recurso que est disponible en una URL dada, usando la resolucin de un protocolo, como "file:" o "classpath:" org.springframework.core.io.VfsResource Carga la configuracin desde un recurso que se encuentra en un sistema de archivos virtual (Virtual file system).

Nosotros usaremos "ClassPathResource" para cargar nuestra configuracin, ya que el archivo "applicationContext.xml" que creamos est dentro del classpath de nuestra aplicacin (ms especficamente en la raz de la misma). A este "ClassPathResource" le pasamos una cadena que contiene la ruta (dentro del classpath) de nuestro archivo de configuracin, de esta forma: BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml")); Ahora que tenemos esta "BeanFactory" ya podremos obtener nuestro bean. Como una nota importante hay que decir que en el momento en el que creamos nuestro BeanFactory, este lee las definiciones de los beans del archivo indicado, sin embargo los beans NO son creados en ese momento. Los beans se crean hasta el momento que son necesitados (cuando los pedimos en nuestro cdigo). Ahora, con nuestro "BeanFactory" podemos obtener un bean haciendo uso del identificador que le dimos en el archivo XML, en este caso "servicioRemoto". Para esto usamos el mtodo "getBean" del BeanFactory. A este mtodo podemos (opcionalmente) indicarle la clase que esperamos que devuelva el mtodo (y con esto ahorrarnos un cast ^_^). ServicioRemoto servicio = beanFactory.getBean("servicioRemoto", ServicioRemoto.class); En el momento en el que invocamos a "getBean", la fabrica instanciar el bean y establecer los valores de sus propiedades usando DI. Es aqu cuando comienza el ciclo de vida de un bean en el contenedor de Spring. Veremos este ciclo de vida ms adelante. Ahora que ya tenemos una instancia de "ServicioRemoto" podemos invocar sus mtodos como lo hacemos normalmente: System.out.println("El valor es " + servicio.consultaDato()); Todo esto lo hacemos dentro de nuestro mtodo "main", que queda de esta forma: public static void main(String[] args) { BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml")); ServicioRemoto servicio = beanFactory.getBean("servicioRemoto", ServicioRemoto.class); System.out.println("El valor es " + servicio.consultaDato()); } Si ejecutamos nuestra aplicacin obtenemos la siguiente salida: run: XX-xxx-XXXX XX:XX:XX org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions INFO: Loading XML bean definitions from class path resource [applicationContext.xml] El valor es 7 BUILD SUCCESSFUL (total time: 0 seconds) Como podemos ver, obtenemos un mensaje que indica que las definiciones de beans del archivo "applicationContext.xml". Adems obtenemos el valor que est regresando nuestro servicio remoto (en mi caso "7"). Todo esto lo logramos sin hacer ni un solo "new". Este ejemplo aunque es muy simple (por no decir tonto ^_^) nos muestra las bases de Spring. Un poco ms adelante veremos, en este mismo tutorial, dnde est la verdadera ventaja de Spring (solo confen en mi y continen leyendo).

Ahora veremos cmo hacer esto mismo usando un "ApplicationContext". 1.2 - Archivos XML con ApplicationContext Un "BeanFactory" est bien para aplicaciones simples, pero no toma ventaja de todo el poder que nos proporciona el framework de Spring, y como desarrolladores queremos cargar los beans de nuestra aplicacin usando el contenedor ms avanzado que nos proporciona Spring, el ApplicationContext. Usar "ApplicationContext" es similar a usar "BeanFactory". Ambos cargan definiciones de beans, cablean los beans, y los envan a quienes se los piden. Pero "ApplicationContext" ofrece ms cosas:

Proporciona un medio para resolver mensajes de texto (no, no son SMSs), incluyendo soporte para internacionalizacin (I18N) de estos mensajes. Proporciona una manera genrica de cargar archivos de recursos, como imgenes. Puede publicar eventos a beans que estn registrados como listeners.

Debido a que "ApplicationContext" proporciona ms funcionalidades, es preferible el uso de este sobre "BeanFactory" en casi todo tipo de aplicaciones, la nica excepcin es cuando estamos ejecutando una aplicacin donde los recursos son escasos, como en un dispositivo mvil. Aunque hay muchas implementaciones de "ApplicationContext" (de esta si =) ), hay 3 que son las ms usadas comnmente:

org.springframework.context.support.ClassPathXmlApplicationContext: Carga la configuracin desde un archivo XML ubicado en el classpath. org.springframework.context.support.FileSystemXmlApplicationContext: Carga la configuracin desde un archivo XML ubicado en cualquier parte del sistema de archivos de la computadora. org.springframework.web.context.support.XmlWebApplicationContext: Carga la configuracin desde un archivo XML ubicado en el contexto de una aplicacin web

Hablaremos de "XmlWebApplicationContext" cuando hablemos de aplicaciones web en uno de los siguientes tutoriales. En este caso usaremos "ClassPathXmlApplicationContext". En este caso el constructor recibe una cadena (o cadenas) indicando la ubicacin de este archivo (o archivos): ApplicationContext applicationContext ClassPathXmlApplicationContext("applicationContext.xml"); = new

Con este ApplicationContext creado ahora podemos recuperar beans de la misma forma que lo hicimos cuando usamos el "BeanFactory", usando el mtodo "getBean", ya que "ApplicationContext" es una interface que extiende de "BeanFactory": ServicioRemoto servicio = applicationContext.getBean("servicioRemoto", ServicioRemoto.class); Adems de la funcionalidad extra, mencionada hace un momento, existe otra diferencia entre "ApplicationContext" y "BeanFactory", y es la manera en la que cargan los beans. Hay que decir que por default todos los beans manejados por Spring son Singletons, esto es, solo existe una instancia de ellos por aplicacin. Como dije antes: "BeanFactory" crea los beans al momento que estos son pedidos (con la invocacin de "getBean"). "ApplicationContext" trabaja de una forma un poco mejor, ya carga todos los singletons cuando se inicia el contexto, y de esta forma se asegura de que estarn listos en el momento en el que sean solicitados. Ahora que tenemos nuestra instancia de "ServicioRemoto", proporcionada por Spring, podemos hacer uso de sus mtodos de forma normal: System.out.println("El valor es " + servicio.consultaDato()); Finalmente, nuestro mtodo "main" queda de la siguiente forma: public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); ServicioRemoto servicio = applicationContext.getBean("servicioRemoto", ServicioRemoto.class); System.out.println("El valor es " + servicio.consultaDato()); } Si ejecutamos nuestra aplicacin, obtendremos una salida similar a esta:

run: XX/xxx/XXXX XX:XX:XX PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions INFO: Loading XML bean definitions from class path resource [applicationContext.xml] El valor es 5 BUILD SUCCESSFUL (total time: 0 seconds) Como podemos ver, hacer el cambio de "BeanFactory" a "ApplicationContext" nos llev solamente una lnea. Y la configuracin en el archivo XML tambin es bastante pequea. Cuando el contenido de nuestro archivo de configuracin comience a crecer podemos separar nuestra configuracin en varios archivos (por ejemplo, uno por cada capa de nuestra aplicacin) y despus hacer referencia a estos archivos en un archivo "maestro" usando el elemento "<import>", por ejemplo, en nuestro archivo "applicationContext.xml" podramos tener: <beans> <import resource="servicios.xml" /> <import resource="persistencia.xml" /> <import resource="presentacion.xml" /> </beans> Esto tambin puede ayudarnos cuando queramos organizar mejor los beans de nuestra aplicacin para agruparlos de alguna manera, y seguir cargando solo un archivo XML de configuracin. Existe una alternativa para el uso de estos archivos XML, y es realizar la configuracin a travs de las anotaciones que nos proporciona Spring, que es lo que veremos a continuacin. 2. Configuracin con Anotaciones El uso de anotaciones nos permite eliminar el tener la definicin de nuestros beans en un archivo XML, y esto es "til" cuando tenemos declarados muchos beans y nuestro archivo se vuelve engorroso (aunque siempre podremos combinar ambas formas de declaracin). Spring proporciona una serie (relativamente grande) de anotaciones con las cuales podemos indicar exactamente cmo queremos que maneje la DI de cada uno de los componentes. Existen en realidad varias formas de manejar estas anotaciones, pero en este momento solo nos centraremos en anotar nuestros beans. Para esto existen tres anotaciones bsicas, las cuales se conocen como "estereotipos":

@Repository Indica que las clases marcadas con esta anotacin estn relacionada de alguna forma con una capa de persistencia de datos. @Service Indica que las clases marcadas con esta anotacin est en una capa de servicios o de lgica de negocios. @Controller Indica que las clases marcadas con esta anotacin son el controlador de una aplicacin web.

Las tres anotaciones anteriores extienden de "@Component", la cual indica que la clase es un componente, y por lo tanto son candidatas para ser auto-detectadas cuando usamos una configuracin basada en anotaciones. Veremos dos formas de configuracin con anotaciones, en la primera (irnicamente) usaremos un archivo XML para indicar dnde estn nuestras clases anotadas. En la segunda forma veremos cmo hacer esto mismo, pero sin necesidad de el archivo XML. 2.1. Anotaciones con Archivo XML En esta configuracin lo primero que haremos es eliminar el contenido del archivo "applicationContext.xml" que creamos hace un momento, dejndolo de esta forma: <?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 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> </beans> Ahora agregaremos un namespace especial a este archivo de configuracin que hace referencia a los elementos de configuracin del contexto de Spring. En XML un namespace es una forma que se usa para proporcionar elementos con nombres nicos. Spring utiliza estos namespaces para separar conjuntos de etiquetas que estn relacionadas y que ofrecen ciertas funcionalidades especiales. Adems esto hace que leer y escribir los archivos de configuracin sea

ms

fcil.

Algunas

veces

escucharn

que

se

refieren

estos

namespaces

como

"esquemas"

Cada uno de estos namespaces hace referencia a un esquema XML distinto. As por ejemplo tenemos un namespace para programacin orientada a aspectos ("aop"), otro para manejo de configuracin de elementos jee ("jee"), otro para manejo de mensajes ("jme"), otro para transacciones ("tx"), etc. El namespace "context" se encarga de la configuracin del "ApplicationContext". Para indicar que haremos uso de este namespace, solo lo agregamos la siguiente lnea dentro del elemento "beans" de archivo "applicationContext.xml": xmlns:context="http://www.springframework.org/schema/context" Dejndolo de la siguiente forma: <?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> </beans> Ahora indicaremos, usando el namespace "context", que queremos activar la configuracin de Spring para que detecte las anotaciones (propias de Spring) en las clases. Para eso usamos el elemento "annotation-config": <context:annotation-config/> Ahora debemos indicar en dnde (en qu paquetes) se encuentran las clases que hemos anotado. Si no indicamos este paquete Spring no buscar de forma automtica las clases (no s realmente por qu). Usamos el elemento "component-scan" para indicar, mediante su elemento "base-package", el paquete raz en el que se encuentran nuestros beans anotados. Para este ejemplo el paquete raz es "ejemplos.spring.ioc.beans". Por lo que el elemento queda de la siguiente forma: <context:component-scan base-package="ejemplos.spring.ioc.beans" /> Y el archivo de configuracin as: <?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:annotation-config/> <context:component-scan base-package="ejemplos.spring.ioc.beans" /> </beans> Como vemos no hemos definido ni un solo bean en el archivo, as que ahora deberemos indicarlo directamente en las clases que se convertirn en nuestros beans (que en ese caso solo es "ServicioRemoto". Para indicar esto usaremos las anotaciones que mencion antes ("@Repository", "@Service", "@Controller"). Como "ServicioRemoto" pertenece a la capa de servicios, lo mercaremos con la anotacin "@Service", de esta forma: @Service public class ServicioRemoto { } Si recuerdan, hacemos referencia a los beans mediante su identificador. Pero "ServicioRemoto" no tiene indicado ninguno. Spring asigna un nombre por default a sus beans, que es el nombre de la case pero con la primer letra en minscula. As que en este caso el nombre del bean ser "servicioRemoto". Si quisiramos darle a nuestro bean un nombre distinto podemos hacerlo mediante el atributo "value" de la anotacin "@Service", de la siguiente forma: @Service(value="servicioRemoto")

Por lo que nuestra clase "ServicioRemoto" queda de la siguiente forma: @Service(value="servicioRemoto") public class ServicioRemoto { public int consultaDato() { return (int) (Math.random() * 10.0); } } No hay que hacerle ningn cambio al cdigo de la clase "Main". Seguimos obteniendo una instancia de "ApplicationContext" (o de "BeanFactory") y le indicamos la ubicacin del archivo que contiene la configuracin de Spring, que en este caso es "applicationContext.xml". De la misma forma seguimos obteniendo el bean "servicioRemoto" invocando al mtodo "getBean" del objeto "ApplicationContext". Finalmente llamamos al mtodo "consultaDato" del bean "servicioRemoto". Nuestro Mtodo "main" queda de la siguiente forma: public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); ServicioRemoto servicioRemoto = applicationContext.getBean("servicioRemoto", ServicioRemoto.class); System.out.println("El valor es: " + servicioRemoto.consultaDato()); } Si ejecutamos nuestra aplicacin veremos la siguiente salida en la consola: run: XX/xx/XXXX XX:XX:XX PM org.springframework.context.support.AbstractApplicationContext prepareRefresh INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@19c26f5: startup date [Xxx Xxx XX XX:XX:XX CST XXXX]; root of context hierarchy XX/xx/XXXX XX:XX:XX PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions INFO: Loading XML bean definitions from class path resource [applicationContext.xml] XX/xx/XXXX XX:XX:XX PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@5329c5: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframewor k.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.in ternalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationPr ocessor,servicioRemoto]; root of factory hierarchy El valor es: 3 BUILD SUCCESSFUL (total time: 0 seconds) Podemos ver que ahora hay ms informacin en la consola pero que finalmente nuestro cdigo se ejecuta y obtenemos la salida esperada. Por lo que nuestra aplicacin ha quedado configurada de forma adecuada ^_^. Como vemos, usando anotaciones, nuestro archivo de configuracin ha quedado an ms pequeo. Sin embargo, an seguimos dependiendo de un archivo XML para que nuestra aplicacin funcione correctamente. Ahora veremos cmo configurar nuestra aplicacin, pero sin depender de ningn XML. 2.2. Anotaciones sin Archivo XML Como para esta ltima configuracin no usaremos el archivo "applicationContext.xml" podemos eliminarlo de la aplicacin. Nuevamente usaremos la clase "ServicioRemoto" con la anotacin "@Service", de esta forma: @Service(value="servicioRemoto") public class ServicioRemoto Para esta configuracin, el nico cambio necesario es en el cdigo que crea el objeto "ApplicationContext" (en el mtodo "main"). En este caso necesitamos un objeto especial ya que, como no existe un archivo XML, debemos indicar cules son las clases anotadas (o el paquete que las contiene). El objeto "especial" que necesitamos crear es una implementacin de "ApplicationContext" (y por lo tanto de "BeanFactory"), la clase "AnnotationConfigApplicationContext". Esta clase tiene dos constructores que nos interesan; el primero recibe una lista, separada por comas, de las clases que tenemos anotadas con @Component (o alguna de sus subclases), como es el caso de "ServicioRemoto". Por lo que crearamos un nuevo objeto de esta clase de la siguiente manera:

new AnnotationConfigApplicationContext(ServicioRemoto.class); Esto es muy cmodo si solo tenemos dos o tres clases anotadas, pero qu pasa en el caso de que tengamos ms? Bueno, en este caso podemos usar el segundo constructor de "AnnotationConfigApplicationContext" en el cual indicamos el paquete (o paquetes) raz en el que se encuentran las clases anotadas, como en el caso del elemento "context:component-scan" del archivo XML, de la siguiente forma: new AnnotationConfigApplicationContext("ejemplos.spring.ioc.beans"); Con este cambio nuestro mtodo "main" queda de la siguiente forma: public static void main(String[] args) { ApplicationContext applicationContext = new AnnotationConfigApplicationContext("ejemplos.spring.ioc.beans"); ServicioRemoto servicio = applicationContext.getBean("servicioRemoto", ServicioRemoto.class); System.out.println("El valor es " + servicio.consultaDato()); } Si ejecutamos nuestra aplicacin veremos la siguiente salida en la consola: run: XX-xxx-XXXX XX:XX:XX org.springframework.context.support.AbstractApplicationContext prepareRefresh INFO: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@d1e604: startup date [Xxx Xxx XX XX:XX:XX CST XXXX]; root of context hierarchy XX-xxx-XXXX XX:XX:XX org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@186d4c1: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframewor k.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.in ternalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationPr ocessor,servicioRemoto]; root of factory hierarchy El valor es 4 BUILD SUCCESSFUL (total time: 0 seconds) Que como podemos observar indica que todo qued configurado correctamente ^_^. De esta forma podemos declarar todas las dependencias y la configuracin (casi toda) de nuestros beans directamente en las clases. Esta manera de configuracin de beans, aunque es ms cmoda y fcil para nosotros como desarrolladores al momento de estar escribiendo el cdigo, es mucho menos clara y (para ser sinceros) no nos permite usar todo el poder que Spring nos proporciona. Es por esto que en estos tutoriales nos centraremos ms en cmo hacer las cosas usando el archivo de configuracin, haciendo las respectivas indicaciones para hacer lo mismo con anotaciones (en caso de que sea posible hacerlo). Ahora que hemos visto 4 formas distintas de configurar el contenedor de beans de Spring para indicarle cuales son los beans que debe manejar, veremos algunos detalles un poco ms interesantes de este framework con respecto a la inyeccin de dependencias. Inyeccin de Dependencias Una aplicacin empresarial tpica no consiste de un solo objeto o bean (como en el caso de nuestra prueba con "ServicioRemoto"). An la aplicacin ms simple tiene unos cuantos objetos que trabajan juntos para realizar sus procesos de una manera coherente. Como ya haba dicho antes, Spring nos proporciona la forma de unir estos objetos sin tener que indicarlo de manera explcita en el cdigo. Ahora veremos (por fin ^_^) como hacer esto de una manera rpida y sencilla. Cuando usamos el mecanismo de DI de Spring, el cdigo es ms limpio, y est desacoplado de una forma ms efectiva. El objeto no busca sus dependencias, de hecho ni siquiera conoce la ubicacin o clase de su dependencia. Por esta misma razn, las clases se hacen ms fciles de probar, en particular cuando las dependencias las definimos como interfaces o clases abstractas, ya que podemos usar objetos mock (que veremos en algn otro tutorial sobre pruebas) para realizar pruebas. En Spring, la DI existe en dos formas principales:

Inyeccin de dependencia basada en constructor Inyeccin de dependencia basada en setter

Ahora veremos ambas formas de inyeccin de dependencia y entraremos en detalle de cada una de ellas. Pero para esto, modificaremos un poco nuestra clase "ServicioRemoto" para que haga uso de un par de dependencias y por lo tanto la cosa se vuelva ms interesante :D. Lo primero que haremos es crear una nueva interface llamada "Proceso". Esta interface representar... bueno el proceso que se realizar dentro del servicio remoto. Tendr un mtodo llamado "ejecuta()", que ser el que se encargar de realizar el proceso. Colocamos esta interface en el paquete de nuestros beans. "Proceso" queda de la siguiente forma: public interface Proceso { Object ejecuta(); } Como vemos, "ejecuta" regresa un "Object". Este ir cambiando de acuerdo a las implementaciones que realicemos de esta interface, de las cuales por cierto haremos 3. La primer implementacin ser la clase "Calculo". La cual solo regresar un nmero al azar entre 0 y 100 (que es lo que ya actualmente est haciendo la clase "ServicioRemoto"), quedando de la siguiente forma: public class Calculo implements Proceso { public Object ejecuta() { return (int)(Math.random()*100.0); } } La siguiente implementacin de "Proceso" se llamar "Concatenacion" y simplemente concatener las cadenas "Hola " y "mundo" y nos regresar esta cadena. La clase queda de la siguiente forma: public class Concatenacion implements Proceso { public Object ejecuta() { return new StringBuilder().append("Hola ").append(" mundo"); } } La tercer y ltima implementacin de "Proceso" se llamar "Ordenamiento" y lo que har es regresar una lista de enteros de forma ordenada. La clase "Ordenamiento" queda de la siguiente forma: public class Ordenamiento implements Proceso { public Object ejecuta() { List< Integer> listaEnteros = new ArrayList<Integer>(); listaEnteros.add(9); listaEnteros.add(3); listaEnteros.add(1); listaEnteros.add(6); listaEnteros.add(5); listaEnteros.add(10); Collections.sort(listaEnteros); return listaEnteros; } } Ahora que tenemos nuestros tres "Procesos" modifiquemos un poco nuestra clase "ServicioRemoto" para que en vez de ser l quien realice la funcionalidad, delegue este trabajo a una de las implementaciones de "Proceso". "ServicioRemoto" podr recibir el Proceso que ejecutar de dos formas, la primera es mediante su constructor, y la segunda es pasando este Proceso mediante un setter. Como ahora "ServicioRemoto" delegar la ejecucin de los Procesos a otras clases, su nica funcin ser invocar el mtodo "ejecuta" del Proceso correspondiente, y como estos regresan Objects, cambiar su tipo de retorno. Con las modificaciones hechas, la clase "ServicioRemoto" queda de la siguiente forma:

public class ServicioRemoto { private Proceso proceso; public ServicioRemoto() { } public ServicioRemoto(Proceso proceso) { this.proceso = proceso; } public Object consultaDato() { return proceso.ejecuta(); } } Ahora s, veremos cmo hacer que Spring inyecte estas dependencias de forma automtica, haciendo uso de sus dos formas de DI. 3. Inyeccin de Dependencia basada en Constructor En este tipo de inyeccin de dependencia, el contenedor invoca a un constructor de la clase, que recibe cierto nmero de argumentos, cada uno de los cuales representa una dependencia. Spring invocar al constructor correspondiente dependiendo del nmero y tipo de dependencias que pasemos, ya sea a travs de los archivos de configuracin en XML (que ser la primera forma que veremos) o haciendo uso de anotaciones. 3.1. Inyeccin de Dependencia basada en Constructor con Archivos XML Lo primero que haremos es indicar, en el archivo de configuracin "applicationContext.xml", que usaremos un bean llamado "proceso", que en este caso ser de tipo "Ordenamiento": <bean id="proceso" class="ejemplos.spring.ioc.beans.Ordenamiento" /> Ahora modificaremos la declaracin actual de nuestro bean "servicioRemoto" que actualmente est de esta forma: <bean id="servicioRemoto" class="ejemplos.spring.ioc.beans.ServicioRemoto" /> Lo primero que haremos es que en vez de que el elemento se auto-cierre, agregar una etiqueta de cierre, esto es porque agregaremos un contenido en el cuerpo de la etiqueta: <bean id="servicioRemoto" class="ejemplos.spring.ioc.beans.ServicioRemoto"> </bean> Para indicar que haremos inyeccin de dependencia basada en constructor, usamos el elemento "<constructor-arg>". Si no indicamos este elemento se usa el constructor por default de la clase (como en los ejemplos anteriores), pero si se usa, Spring buscar un constructor que reciba el tipo de objeto indicado en l. Tenemos dos maneras de usar este elemento, la primera es indicando el valor que pasaremos al constructor (til para "constantes") usando el atributo "value". Por ejemplo, si "ServicioRemoto" tuviera un constructor que recibiera una cadena, podramos usar "<constructor-arg>" de la siguiente forma: <constructor-arg value="5" /> Pero como no es el caso, usaremos la otra forma de "<constructor-arg>" que recibe una referencia a otro bean declarado en el archivo de configuracin, usando su elemento "ref", de esta forma: <constructor-arg ref="proceso" /> En "ref" indicamos el identificador del bean al que haremos referencia, en este caso es el bean "proceso" que creamos antes. La declaracin del bean "servicioRemoto" queda de la siguiente forma: <bean id="servicioRemoto" class="ejemplos.spring.ioc.beans.ServicioRemoto"> <constructor-arg ref="proceso" /> </bean>

Recuerdan que anteriormente dijimos que tambin podan declararse beans internos para usarse dentro de otras declaraciones? Pues aqu podemos hacerlo para ahorrarnos la declaracin del bean "proceso", de esta forma: <bean id="servicioRemoto" class="ejemplos.spring.ioc.beans.ServicioRemoto" > <constructor-arg> <bean class="ejemplos.spring.ioc.beans.Ordenamiento" /> </constructor-arg> </bean> Pero para hacer las cosas ms claras lo dejaremos declarado como lo tenamos ^_^. Nuestro archivo de configuracin queda de la siguiente forma: <?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="proceso" class="ejemplos.spring.ioc.beans.Ordenamiento" /> <bean id="servicioRemoto" class="ejemplos.spring.ioc.beans.ServicioRemoto"> <constructor-arg ref="proceso" /> </bean> </beans> Si nuestro constructor tuviera ms de un argumento, bastara con agregar otro elemento "<constructor-arg>". Ahora ejecutaremos nuestra aplicacin de forma normal. Con el siguiente contenido en el mtodo "main": public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); ServicioRemoto servicio = applicationContext.getBean("servicioRemoto", ServicioRemoto.class); System.out.println("El valor es " + servicio.consultaDato()); } Que es el mismo cdigo que ya tenamos. Al correr nuestro cdigo obtendremos la siguiente salida (le he quitado algo de la "basura" que genera Spring, para poder concentrarnos en la parte importante): run: El valor es [1, 3, 5, 6, 9, 10] BUILD SUCCESSFUL (total time: 0 seconds) Como vemos, hemos obtenido la salida esperada, sin tener que escribir ninguna lnea de cdigo para resolver las dependencias que usa la clase "ServicioRemoto", que en este caso es el proceso. Es ms, "ServicioRemoto" ni siquiera sabe de qu tipo es el "Proceso" que est ejecutando, ni cmo encontrarlo, es el motor de IoC de Spring, que haciendo uso de DI se encarga de crear una instancia de la clase apropiada e inyectarla, en este caso mediante el constructor, a "ServicioRemoto". Ahora veremos otro de los encantos de Spring. Sin tocar una sola lnea de nuestro cdigo (o ms bien dicho, sin mover ninguna clase) haremos que "ServicioRemoto" obtenga una dependencia distinta. Para esto cambiaremos la lnea: <bean id="proceso" class="ejemplos.spring.ioc.beans.Ordenamiento" /> Por <bean id="proceso" class="ejemplos.spring.ioc.beans.Concatenacion" /> Si volvemos a ejecutar nuestra aplicacin ahora obtendremos la siguiente salida: run: El valor es Hola mundo BUILD SUCCESSFUL (total time: 0 seconds) Ahora se ha inyectado una instancia de "Concatenacion" y "ServicioRemoto" la usa para ejecutar su Proceso. Por qu es til esto? Pues imagnense el caso que tengamos nuestra aplicacin ya compilada y en produccin. Si quisiramos hacer un cambio sera solo cuestin de modificar el archivo XML de configuracin (que siempre est en texto plano) y reiniciar la aplicacin para que haya un cambio. Esta es una de las ventajas que tiene la configuracin en XML sobre las anotaciones.

Pero, para efectos acadmicos, veamos cmo hacer la inyeccin por constructor, usando anotaciones. 3.2. Inyeccin de Dependencia basada en Constructor con Anotaciones En este caso debemos recordar colocar alguna de las anotaciones que extienden de "@Component" en las clases que implementan nuestra lgica de Procesos. Nosotros, nuevamente, usaremos la anotacin "@Service". Las clases que implementan la interface "Proceso" se ven as (omitiendo los cuerpos de las mismas): @Service public class Calculo implements Proceso { } @Service public class Concatenacion implements Proceso { } @Service public class Ordenamiento implements Proceso { } Ahora modificaremos nuestra clase "ServicioRemoto". Lo primero que haremos es indicarle que queremos que Spring realice el wiring de forma automtica para el constructor de "ServicioRemoto" que recibe como parmetro la instancia de "Proceso". La anotacin "@Autowired" nos permite hacer esto. "@Autowired" nos permite marcar un constructor, campo, setter, o mtodo de configuracin para ser auto-cableado por el proceso de inyeccin de dependencia de Spring. Si colocamos esta anotacin en un constructor, solo podemos anotar uno de los que tenga la clase. As que ser este constructor el que se invoque, aunque la clase tenga ms. Colocamos la anotacin justo sobre el constructor, de esta forma: @Autowired public ServicioRemoto(Proceso proceso) { this.proceso = proceso; } Si ejecutamos nuestra aplicacin en este momento veremos que en la consola obtenemos el siguiente mensaje de error: Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'servicioRemoto' defined in file [ejemplos\spring\ioc\beans\ServicioRemoto.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [ejemplos.spring.ioc.beans.Proceso]: No unique bean of type [ejemplos.spring.ioc.beans.Proceso] is defined: expected single matching bean but found 3: [calculo, concatenacion, ordenamiento]; Lo que este error trata, tan sutilmente, de decirnos, es que Spring no sabe de cul de las clases que implementa la interface "Proceso" debe inyectar ya que encuentra 3 clases candidatas: "calculo", "concatencacion", y "ordenamiento". Debemos indicar de cul de estas tres clases queremos que sea inyectada una instancia. Para hacer esto Spring proporciona la anotacin "@Qualifier" para poder referirnos a un bean a travs de su nombre (que si recordamos, cuando usamos anotaciones, por default es el mismo nombre que la clase, pero iniciando con la primer letra en minscula). Esta anotacin la colocamos directamente dentro de los parntesis que representan el parmetro al que haremos referencia (esta anotacin tambin puede colocarse a nivel de campo) e indicamos el nombre del bean que queremos usar, que en este caso ser "ordenamiento": @Autowired public ServicioRemoto(@Qualifier("ordenamiento")Proceso proceso) { this.proceso = proceso; } Finalmente, nuestra clase "ServicioRemoto" queda de la siguiente forma: @Service(value="servicioRemoto") public class ServicioRemoto { private Proceso proceso;

public ServicioRemoto() { } @Autowired public ServicioRemoto(@Qualifier("ordenamiento")Proceso proceso) { this.proceso = proceso; } public Object consultaDato() { return proceso.ejecuta(); } } Ahora s, si ejecutamos nuestra aplicacin veremos la siguiente salida en la consola: run: El valor es: [1, 3, 5, 6, 9, 10] BUILD SUCCESSFUL (total time: 0 seconds) Como vemos, tambin ha resultado bastante simple hacer la inyeccin basada en constructor mediante anotaciones. De la misma forma en la que, usando el archivo XML, pudimos hacer que nuestra aplicacin usara una instancia de una clase o de otra moviendo solo una lnea, aqu podemos hacer lo mismo; si cambiamos el valor de la anotacin "@Qualifier" de "ordenamiento" a "calculo", de esta forma: public ServicioRemoto(@Qualifier("calculo")Proceso proceso) { } Obtendremos la siguiente salida: run: El valor es: 49 BUILD SUCCESSFUL (total time: 0 seconds) Como vemos, todo ha salido perfectamente usando la inyeccin de dependencia por constructor. Ahora veamos la segunda forma de inyeccin de dependencia que nos proporciona Spring: inyeccin de dependencia basada en setter. 4. Inyeccin de Dependencia basada en Setter Las propiedades de los JavaBeans, tpicamente son declaradas como private y tienen un par de mtodos de acceso, un setter y un getter. La inyeccin de dependencia basada en setter se realiza cuando el contenedor llama a los mtodos setter de los beans, para inyectar sus dependencias requeridas. Para mostrar este ejemplo modificaremos nuestra clase "ServicioRemoto" para que ahora ejecute el Proceso correspondiente un cierto nmero de veces. Este nmero de veces ser representado por un objeto de tipo Integer, que ser insertado haciendo uso de la inyeccin de dependencia por setter. Agregaremos esta variable, llamada "repeticiones", junto con su setter, de la siguiente forma: private Integer repeticiones; public void setRepeticiones(Integer repeticiones) { this.repeticiones = repeticiones; } Ahora modificaremos el mtodo "consultaDato" para colocar un ciclo que ejecutar el mtodo el nmero de veces indicado, a travs de la variable "repeticiones": public Object consultaDato() { StringBuilder stringBuilder = new StringBuilder(); for(int i = 0; i < repeticiones; i++) { stringBuilder.append(i + 1).append(" ").append(proceso.ejecuta()).append("\n"); } return stringBuilder.toString(); } Ahora haremos que Spring inyecte el valor de la propiedad "repeticiones" haciendo uso de inyeccin por setter. Primero veremos cmo hacerlo usando el archivo de configuracin en XML.

4.1. Inyeccin de Dependencia Basado en Setter, mediante archivo XML Para este ejemplo, modificaremos el archivo "applicationContext.xml". La inyeccin por setter se realiza utilizando el elemento "<property>" del archivo de configuracin. "<property>", al igual que "<constructor-arg>", permite recibir un valor, a travs del atributo "value", o usar una referencia a otro bean declarado en el archivo, a travs del atributo "ref". En este elemento debemos indicar cul atributo, o propiedad, es el que queremos que sea inyectado, para esto usamos el atributo "name" del elemento "<property>". Como nosotros pasaremos un valor constante a la propiedad "repeticiones" del "servicioRemoto" usaremos el atributo "value", que estableceremos con un valor de "5" (aunque pueden poner el valor que quieran). Colocaremos el elemento "<property>" dentro de las etiquetas "<bean>" que definen al bean "servicioRemoto", justo debajo del "<constructor-arg>" que colocamos hace un momento, de esta forma: <bean id="servicioRemoto" class="ejemplos.spring.ioc.beans.ServicioRemoto" > <constructor-arg ref="proceso" /> <property name="repeticiones" value="5" /> </bean> Este es el nico cambio que necesitamos hacer para realizar la inyeccin de dependencias por setter. Recuerden que si quisieran inyectar un objeto, en vez de una constante, deben declarar el bean (o usar un bean interno), y el atributo "ref" de "<property>". Si ejecutamos nuestra aplicacin, obtenemos la siguiente salida en la consola: run: El valor es 1 2 - [1, 3, 5, 3 - [1, 3, 5, 4 - [1, 3, 5, 5 - [1, 3, 5,

- [1, 6, 9, 6, 9, 6, 9, 6, 9,

3, 5, 6, 9, 10] 10] 10] 10] 10]

Si modifican el valor de "repeticiones", en el archivo de configuracin, debern ver reflejado este cambio, de forma inmediata, en la aplicacin. Ahora veamos cmo hacer esta misma inyeccin de dependencias, pero usando anotaciones. 4.2. Inyeccin de Dependencia Basado en Setter, mediante Anotaciones Cuando trabajamos con anotaciones, hacer inyeccin de dependencias se hace de forma distinta si vamos a inyectar una referencia a un objeto que si vamos a inyectar un valor constante. Si quisiramos inyectar una referencia a un objeto lo haramos como vimos en el caso de la DI basada en constructor (usando las anotaciones "@Autowired" y "@Qualifier"). Cuando vamos a inyectar un valor constante usamos la anotacin "@Value" e indicamos en su atributo "value" el valor que inyectaremos. En la DI basada en setter, podemos colocar estas anotaciones en dos lugares. El primero es directamente sobre el setter del atributo que vamos a establecer, en el caso de "repeticiones" sera de esta forma: @Value(value="5") public void setRepeticiones(Integer repeticiones) { this.repeticiones = repeticiones; } El segundo es directamente en el atributo que queremos establecer, de esta forma: @Value(value="5") private Integer repeticiones; Yo usar esta segunda forma, ya que me parece un poco ms clara que la anterior. Al final, nuestra clase "ServicioRemoto" anotada queda de la siguiente forma: @Service(value="servicioRemoto") public class ServicioRemoto { private Proceso proceso; @Value(value="5") private Integer repeticiones;

public ServicioRemoto() { } @Autowired public ServicioRemoto(@Qualifier("calculo")Proceso proceso) { this.proceso = proceso; } public Object consultaDato() { StringBuilder stringBuilder = new StringBuilder(); for(int i = 0; i < repeticiones; i++) { stringBuilder.append(i + 1).append(" - ").append(proceso.ejecuta()).append("\n"); } return stringBuilder.toString(); } public void setRepeticiones(Integer repeticiones) { this.repeticiones = repeticiones; } } Si ejecutamos este cdigo veremos la siguiente salida en consola: El valor es: 1 - 8 2 - 64 3 - 50 4 - 45 5 50 Como vemos, nuevamente ha sido muy fcil modificar nuestra aplicacin para agregar este tipo de inyeccin de dependencias. Cul Forma de Inyeccin de Dependencias Elegir? La eleccin entre cul forma de inyeccin de dependencia, por setter o por constructor, elegir no es fcil, ya que ambas tienen sus ventajas y sus desventajas. Spring nos permite elegir el mtodo que ms nos guste (o nos convenga), adems de que nos permite mezclar ambas formas, como lo hemos hecho en el ejemplo. Sin embargo hay una regla o consejo que podemos seguir: usar DI basada en constructor para las dependencias obligatorias y la DI basada en setter para las dependencias opcionales. El equipo desarrollador de Spring (y yo tambin) generalmente sugieren usar inyeccin por setter, porque tener constructores con un nmero grande de argumentos pueden ser engorrosos, especialmente si algunos de los argumentos son opcionales. Los mtodos setter tambin hacen que los objetos de esas clases sean ms fciles de reconfigurar o re-inyectar despus. Lo mejor es usar el tipo de DI que tenga ms sentido para la clase en la que estamos trabajando. Dejaremos este tutorial aqu. Hemos aprendido a realizar inyeccin de dependencias de las dos formas que nos proporciona Spring: basada en constructor y basada en setter, y a inyectar referencias a otros objetos y valores constantes, tanto con archivos de configuracin en XML como con anotaciones. Solo hemos visto un par de ejemplos muy simples, pero recuerden que usando esta misma lgica pueden extender estos ejemplos para armar aplicaciones grandes. Tambin es importante recordar que es posible combinar ambas formas de configuracin, anotando unos beans, y declarando otros en el archivo de configuracin XML. Espero que el tutorial les sea de utilidad. En los siguientes tutoriales veremos cmo inyectar colecciones en nuestros beans, adems del scope y ciclo de vida de los mismos para saber cmo sacar una mayor ventaja de estos. No olviden dejar sus dudas, comentarios, y sugerencias. Todo es bien recibido ^_^. Saludos.

Spring 3 - Parte 3: Inyeccin de Colecciones En el tutorial anterior vimos cmo hacer la configuracin de Spring para poder hacer el cableado o wiring de propiedades simples, ya fuera un valor constante o una referencia a un objeto. Esto es muy til cuando esperamos solo una referencia o un valor, pero qu ocurre en el caso en el que necesitemos hacer la inyeccin de varios objetos? Java proporciona un conjunto de clases que nos permiten manejar conjuntos de objetos. Estas clases son conocidas como colecciones. En este tutorial aprenderemos cmo realizar la inyeccin de dependencias en 3 tipos de colecciones ("List", "Set", y "Map") y, adicionalmente, aprenderemos a inyectar propiedades ("properties") y arreglos ("arrays"). Adems veremos cmo insertar valores nulos en las propiedades de nuestros beans. Spring ofrece cinco tipos de elementos para configuracin de colecciones. La siguiente tabla muestra estos elementos y una descripcin de dnde pueden usarse: Elemento <list> <array> <set> <map> <props> til para Wiring de una lista de valores, que permite duplicados y mantienen un orden. Wiring de un arreglo de objetos, que permite duplicados y mantienen un orden. Wiring de un conjunto de valores, asegurando que no hay duplicados. Wiring de una coleccin de pares nombre-valor donde el nombre y el valor pueden ser de cualquier tipo. Wiring de una coleccin de pares nombre-valor donde el nombre y el valor son de tipo String.

Para este ejemplo crearemos una clase a la que le inyectaremos varias colecciones, de los distintos tipos mencionados arriba, y que las recorrer para poder mostrarlas en pantalla. Algunos de los elementos de las colecciones sern constantes y otros sern referencias a objetos de un tipo "Persona", que crearemos en unos momentos. Lo primero que haremos es crear un nuevo proyecto en NetBeans. Para esto vamos al Men "File->New Project...". En la ventana que se abre seleccionamos la categora "Java" y en el tipo de proyecto "Java Application". Le damos una ubicacin y un nombre al proyecto, en mi caso ser "SpringColecciones". Nos aseguramos que las opciones "Create Main Class" y "Set as Main Project" estn habilitadas. Presionamos el botn "Finish" y veremos aparecer en el editor nuestra clase "Main". Agregamos la biblioteca "Spring 3" que creamos en el primer tutorial de la serie. Hacemos clic derecho sobre el nodo "Libraries" del proyecto, en el men que aparece elegimos la opcin "Add Library...". En la ventana que se abre seleccionamos la biblioteca "Spring 3" y presionamos el botn "Add Library". Con esto los archivos de la biblioteca deben agregarse a nuestro proyecto. Ahora crearemos un nuevo paquete que contendr a nuestros beans, este paquete se llamar "beans". Hacemos clic derecho en el paquete en el que se encuentra nuestra clase "Main" (que en mi caso es "ejemplos.spring.colecciones") y en el men que se abre seleccionamos la opcin "New -> Java package..." y al nombre del paquete le agregamos "beans". Presionamos el botn "Finish" y con esto aparecer nuestro nuevo paquete. Hasta ahora nuestro proyecto debe verse as:

Ahora podemos crear nuestro archivo de configuracin XML, "applicationContext.xml", en el paquete raz (default package). Para esto hacemos clic derecho sobre el nodo "Source Packages" de nuestro proyecto, y en el men contextual que se abre seleccionamos "new -> Other...". En la ventana que se abre, seleccionamos la categora "Other" y como tipo de archivo "Spring XML Configuration File". Le damos un nombre al archivo, en mi caso ser "applicationContext". Hacemos clic en el botn "Next". En la siguiente pantalla debemos seleccionar los namespaces que queremos que tenga nuestro archivo. No seleccionaremos ninguno. Presionamos el botn "Finish" y con eso aparecer en nuestro editor el archivo "applicationContext.xml". Ahora crearemos nuestra clase "Persona", dentro del paquete "beans", cuyas instancias sern inyectadas dentro de las colecciones que crearemos en unos momentos. "Persona" ser una clase muy sencilla que solo tendr 2 atributos: "nombre", de tipo String, y "edad", de tipo int, con sus respectivos setters y getters. Por lo que "Persona" queda de la siguiente forma: public class Persona { private String nombre;

private int edad; public int getEdad() { return edad; } public void setEdad(int edad) { this.edad = edad; } public String getNombre() { return nombre; } public void setNombre(String nombre) { this.nombre = nombre; } } Tambin sobre-escribiremos el mtodo "toString" de la clase "Persona". Esto con la finalidad de que al mostrar una de sus instancias, usando "System.out.println()", podamos ver los valores de sus atributos sin llamar a sus mtodos getter de forma explcita: @Override public String toString() { return new StringBuilder("nombre: ").append(nombre).append(", edad: ").append(edad).toString(); } La clase "Persona" queda de la siguiente forma: public class Persona { private String nombre; private int edad; public int getEdad() { return edad; } public void setEdad(int edad) { this.edad = edad; } public String getNombre() { return nombre; } public void setNombre(String nombre) { this.nombre = nombre; } @Override public String toString() { return new StringBuilder("nombre: ").append(edad).toString(); } }

").append(nombre).append(",

edad:

Ahora crearemos una clase llamada "ManejadorColecciones", en el paquete "beans". Esta clase ser a la que le inyectaremos las colecciones que declararemos en el archivo de configuracin, y que se encargar de mostrar en consola los contenidos de estas colecciones. Esta clase tendr una variable para cada uno de los tipos de colecciones que inyectaremos (list, arreglo, set, map, y properties), y como haremos inyeccin por setter (si no saben qu es esto, vean el segundo tutorial de la serie), tendr un setter para cada una de las propiedades anteriores, de esta forma: public class ManejadorColecciones { private List lista; private Persona[] arreglo; private Set conjunto; private Map mapa; private Properties propiedades; public void setArreglo(Persona[] arreglo) {

this.arreglo = arreglo; } public void setConjunto(Set conjunto) { this.conjunto = conjunto; } public void setLista(List lista) { this.lista = lista; } public void setMapa(Map mapa) { this.mapa = mapa; } public void setPropiedades(Properties propiedades) { this.propiedades = propiedades; } } Como podemos ver, "ManejadorColecciones" tiene una propiedad de cada uno de los tipos de colecciones. Tambin podemos ver que en este caso no hemos usado "generics" al marcar las colecciones. Esto es porque dentro de la coleccin pondremos objetos de distintos tipos. Ahora crearemos un mtodo para mostrar el contenido de cada uno de estas colecciones. Estos mtodos sern muy simples, solo las recorreremos en un ciclo for, y las mostraremos con un "System.out.println". Este es el mtodo para mostrar la lista: public void muestraLista() { System.out.println("---Mostrando lista---"); for(Object o : lista) { System.out.println(o.getClass() + ": " + o); } } Este el mtodo para mostrar el arreglo: public void muestraArreglo() { System.out.println("---Mostrando arreglo---"); for(Object o : arreglo) { System.out.println(o.getClass() + ": " + o); } } Este es el mtodo para mostrar el Set: public void muestraConjunto() { System.out.println("---Mostrando conjunto---"); for (Iterator it = conjunto.iterator(); it.hasNext();) { Object o = it.next(); System.out.println(o.getClass() + ": " + o); } } Este es el mtodo para mostrar el Map: public void muestraMapa() { System.out.println("---Mostrando mapa---"); for (Iterator it = mapa.keySet().iterator(); it.hasNext();) { Object o = it.next();

System.out.println("[llave] " mapa.get(o).getClass() + ": " + mapa.get(o) ); } } Y, finalmente, este es el mtodo para mostrar el objeto "Properties":

o.getClass()

":

"

",

[valor]"

public void muestraPropiedades() { System.out.println("\n---Mostrando propiedades---"); for (Iterator it = propiedades.keySet().iterator(); it.hasNext();) { Object o = it.next(); System.out.println("[llave] " + o.getClass() + ": propiedades.get(o).getClass() + ": " + propiedades.get(o) ); } }

"

",

[valor]"

Como podemos ver, los 5 mtodos anteriores son muy sencillos, por lo que no necesitan ms explicacin. La clase "ManejadorColecciones" queda finalmente de la siguiente manera: public class ManejadorColecciones { private List lista; private Persona[] arreglo; private Set conjunto; private Map mapa; private Properties propiedades; public void muestraLista() { System.out.println("\n---Mostrando lista---"); for (Object o : lista) { System.out.println(o.getClass() + ": " + o); } } public void muestraArreglo() { System.out.println("\n---Mostrando arreglo---"); for (Object o : arreglo) { System.out.println(o.getClass() + ": " + o); } } public void muestraConjunto() { System.out.println("\n---Mostrando conjunto---"); for (Iterator it = conjunto.iterator(); it.hasNext();) { Object o = it.next(); System.out.println(o.getClass() + ": " + o); } } public void muestraMapa() { System.out.println("\n---Mostrando mapa---"); for (Iterator it = mapa.keySet().iterator(); it.hasNext();) { Object o = it.next(); System.out.println("[llave] " + o.getClass() + mapa.get(o).getClass() + ": " + mapa.get(o) ); } } public void muestraPropiedades() { System.out.println("\n---Mostrando propiedades---");

":

"

",

[valor]"

for (Iterator it = propiedades.keySet().iterator(); it.hasNext();) { Object o = it.next(); System.out.println("[llave] " + o.getClass() propiedades.get(o).getClass() + ": " + propiedades.get(o) ); + ": " + o + ", [valor]" +

} } public void setArreglo(Persona[] arreglo) { this.arreglo = arreglo; } public void setConjunto(Set conjunto) { this.conjunto = conjunto; } public void setLista(List lista) { this.lista = lista; } public void setMapa(Map mapa) { this.mapa = mapa; } public void setPropiedades(Properties propiedades) { this.propiedades = propiedades; } } Ahora regresemos al archivo de "applicationContext.xml" para configurar la inyeccin de todos los objetos que se inyectarn a "ManejadorBeans". Lo primero que haremos es declarar dos objetos de tipo "Persona": <bean id="persona1" class="ejemplos.spring.colecciones.beans.Persona"> </bean> <bean id="persona2" class="ejemplos.spring.colecciones.beans.Persona"> </bean> Ahora, haciendo uso de la inyeccin por setter, estableceremos los valores de los atributos "nombre" y "edad" de estos dos beans. Pueden colocar los valores que quieran: <bean id="persona1" class="ejemplos.spring.colecciones.beans.Persona"> <property name="nombre" value="Persona1" /> <property name="edad" value="26" /> </bean> <bean id="persona2" class="ejemplos.spring.colecciones.beans.Persona"> <property name="nombre" value="Persona2" /> <property name="edad" value="62" /> </bean> Lo siguiente que debemos hacer es declarar un bean de tipo "ManejadorColecciones" que ser el que usaremos en nuestro mtodo "main", y al que le inyectaremos, en unos momentos ms, las colecciones: <bean id="manejador" class="ejemplos.spring.colecciones.beans.ManejadorColecciones"> </bean> Comencemos con la inyeccin de cada una de nuestras colecciones. En general, todas nuestras colecciones (incluyendo los arreglos) se declaran como beans internos, as que no tendrn un identificador propio. Comencemos inyectando las listas: Inyeccin de Listas Para declarar una lista en el archivo de configuracin usamos el elemento "<list>" en la propiedad correspondiente, que en este caso se llama "lista": <property name="lista"> <list> </list> </property> Cuando queremos declarar una referencia a un bean dentro de una lista, usamos el elemento "<ref>", y dentro de este usamos el atributo "bean" para indicar el identificador del bean al que queremos hacer referencia, en nuestro caso sern los beans "persona1" y "persona2": <property name="lista"> <list> <ref bean="persona1" /> <ref bean="persona2" /> </list> </property>

Cuando queremos declarar algn valor primitivo, como un int o un String (ya lo s, los String son objetos, no tipos primitivos, pero en Java los manejamos como si lo fueran u_u!), usamos el elemento "<value>". Dentro de ese elemento declaramos el valor que usaremos, de esta forma: <value>Cadena</value> <value>5</value> Si lo dejamos de la forma anterior, Spring entender ambos valores como si fueran Strings, sin embargo, si queremos declarar algn valor como otro tipo, como en el caso del "5" que queremos que sea un entero, usamos el atributo "type" del elemento "<value>" para indicar el tipo del valor. En este caso ser de tipo "java.lang.Integer": <value type="java.lang.Integer">5</value> La declaracin de nuestra lista queda de la siguiente forma: <property name="lista"> <list> <ref bean="persona1" /> <ref bean="persona2" /> <value>Cadena</value> <value type="java.lang.Integer">5</value> </list> </property> Si recordamos, en una lista el orden en el que se encuentran los elementos dentro de la coleccin es importante. Cuando inyectamos una lista a un bean, los elementos de la misma sern inyectados en el orden en el que los declaramos en el archivo de configuracin. Esto quiere decir que en este caso, el orden de los elementos en la lista ser: "persona1", "persona2", "Cadena", "5". Ahora veremos cmo inyectar los elementos para la siguiente "coleccin", los arreglos. Inyeccin de Arreglos Ahora inyectaremos un arreglo a nuestro bean "ManejadorColecciones". Spring proporciona el elemento "<array>" para declarar un arreglo dentro del archivo de configuracin: <property name="arreglo"> <array> </array> </property> Al igual que con las listas, podemos declarar una referencia a un bean que se agregar a nuestro arreglo, usando el elemento "<ref>", o podemos inyectar un valor "primitivo" usando el elemento "<value>". Como en nuestra clase "ManejadorColecciones" tenemos declarada la variable "arreglo" de tipo "Persona[]", solo podemos pasar referencias de tipo "Persona" al arreglo que inyectaremos. Para esto pasaremos las referencias a los beans "persona1" y "persona2" que ya tenemos declarados: <array> <ref bean="persona2" /> <ref bean="persona1" /> </array> Agregaremos una Personas ms a nuestro arreglo, pero en este caso en forma de bean interno: <array> <ref bean="persona2" /> <ref bean="persona1" /> <bean class="ejemplos.spring.colecciones.beans.Persona"> <property name="nombre" value="Persona Nueva" /> <property name="edad" value="10" /> </bean> </array> Con esto ya tenemos declarado un arreglo de 3 elementos, de tipo "Persona", que sern inyectados en el momento de que nuestro bean sea creado. La declaracin del arreglo queda as: <property name="arreglo"> <array> <ref bean="persona2" /> <ref bean="persona1" /> <bean class="ejemplos.spring.colecciones.beans.Persona"> <property name="nombre" value="Persona Nueva" /> <property name="edad" value="10" /> </bean>

</array> </property> En los arreglos, igual que en las listas, el orden en el que se encuentran los elementos dentro de la coleccin es importante. En este caso tambin, los elementos del arreglo sern inyectados en el orden en el que los declaramos en el archivo de configuracin. Esto quiere decir que en este caso, el orden de los elementos en la lista ser: "persona2", "persona1", "Persona Interna". Pasemos a ver cmo inyectar el siguiente tipo de coleccin, los conjuntos o Sets. Inyeccin de Sets Cuando queremos inyectar un Set a un bean, usamos el elemento "<set>" del archivo de configuracin: <property name="conjunto"> <set> </set> </property> Igual que en los casos anteriores, podemos pasar referencias a otros beans, usando en elemento "<ref>", o valores "primitivos", usando el elemento "<value>". Nosotros pasaremos cuatro referencias a 2 beans: 2 referencias al bean "persona1" y 2 referencias al bean "persona2", de la siguiente forma: <set> <ref <ref <ref <ref </set> bean="persona1" bean="persona2" bean="persona2" bean="persona1" /> /> /> />

Por qu hacemos esto? Bueno, esto lo hemos hecho porque los Sets son un tipo especial de coleccin que NO permite tener elementos repetidos. Esto quiere decir que aunque hayamos pasado 4 referencias, como en realidad solo estamos pasando 2 objetos (y 2 repetidos) la coleccin al final solo tendr 2 objetos, esto lo veremos al momento de mostrar los valores en la consola. Al final, la declaracin de nuestro conjunto queda de la siguiente forma: <property name="conjunto"> <set> <ref bean="persona1" <ref bean="persona2" <ref bean="persona2" <ref bean="persona1" </set> </property>

/> /> /> />

Ahora veamos cmo inyectar nuestra cuarta coleccin, los mapas. Inyeccin de Maps Para hacer inyeccin de Maps, Spring proporciona el elemento as es, adivinaron, el elemento "<map>": <property name="mapa"> <map> </map> </property> Recordemos que un mapa es una coleccin que tiene elementos de tipo llave-valor, donde tanto la llave como el valor pueden ser de cualquier tipo. Para declarar los miembros del mapa, usamos el elemento "<entry>". Dentro de este elemento podemos indicar dos tipos de llaves, una llave que es un valor, usando el atributo "key", que es tomado como String, o una llave que es una referencia a un bean, usando el atributo "key-ref". De la misma forma, podemos declarar dos tipos de valores, unos que son referencias a otros beans, usando "value-ref", y otros que son valores que son tomados como String, usando "value". La siguiente tabla da el nombre y una descripcin de estos atributos: Atributo Propsito key Especifica la llave de la entrada del mapa como un String. key-ref Especifica la llave de la entrada del mapa como una referencia a un bean. Value Especifica el valor de la entrada del mapa como un String. value-ref Especifica el valor de la entrada del mapa como una referencia a un bean. Nosotros inyectaremos 4 entradas a nuestro mapa. Trataremos de combinar varios tipos de objetos, tanto de beans como de valores. La primer entrada tendr como llave una cadena y como valor una referencia a uno de nuestros beans de tipo "Persona": <entry key="persona1" value-ref="persona1" />

La siguiente entrada ser al revs, la llave ser una referencia a uno de los beans de tipo "Persona" y el valor ser una cadena: <entry key-ref="persona2" value="otra persona" /> La tercer entrada tendr como llave una cadena y como valor otra cadena: <entry key="sin persona" value="no personas" /> La cuarta y ltima entrada tendr como llave una referencia a un objeto "Persona" y como valor otra referencia a un objeto "Persona": <entry key-ref="persona1" value-ref="persona2" /> La declaracin final de nuestro mapa queda de la siguiente forma: <property name="mapa"> <map> <entry key="persona1" value-ref="persona1" /> <entry key-ref="persona2" value="otra persona" /> <entry key="sin persona" value="no personas" /> <entry key-ref="persona1" value-ref="persona2" /> </map> </property> Veremos cmo configurar nuestra ltima "coleccin", las propiedades. Inyeccin de Propiedades Las propiedades son muy similares a los mapas; son colecciones donde se tienen pares llave-valor. De hecho la clase "Properties" implementa la interface "Map". La diferencia principal es que, mientras que en los mapas la llave y el valor pueden ser de cualquier tipo, en las propiedades ambos elementos solo pueden ser de tipo String. Spring proporciona el elemento "<props>" para declarar atributos de tipo "java.util.Properties". <property name="propiedades"> <props> </props> </property> Para agregar cada uno de los miembros de las propiedades tenemos dos formas. La primera es usando el elemento "<prop>", en el cual indicamos la llave usando el atributo "key", y el valor lo colocamos como contenido del elemento. Por ejemplo, si quisiramos declarar cuatro propiedades: nombre, pas, sitio, y facebook, lo haramos de la siguiente manera: <prop <prop <prop <prop key="nombre">Alex</prop> key="pais">Mexico</prop> key="sitio">http://javatutoriales.blogspot.com/</prop> key="facebook">http://www.facebook.com/pages/Java-Tutoriales/121935157864634</prop>

La segunda forma es aprovechando el soporte que nos proporciona Spring para manejo de propiedades usando su "PropertyEditor" integrado para escribir directamente las llaves y valores de las propiedades, como cuerpo del elemento "<value>" que colocamos directamente dentro de la propiedad (sin hacer uso del elemento "<props>"), de esta forma: <property name="propiedades"> <value> nombre=Alex pais=Mexico sitio=http://javatutoriales.blogspot.com facebook=http://www.facebook.com/pages/Java-Tutoriales/121935157864634 </value> </property> Y esto es todo, ya tenemos configuradas todas las colecciones de nuestro ejemplo. Al final el archivo de configuracin, "applicationContext.xml", queda de la siguiente forma: <?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="persona1" class="ejemplos.spring.colecciones.beans.Persona"> <property name="nombre" value="Persona1" /> <property name="edad" value="26" />

</bean> <bean id="persona2" class="ejemplos.spring.colecciones.beans.Persona"> <property name="nombre" value="Persona2" /> <property name="edad" value="62" /> </bean> <bean id="manejador" class="ejemplos.spring.colecciones.beans.ManejadorColecciones"> <property name="lista"> <list> <ref bean="persona1" /> <ref bean="persona2" /> <value>Cadena</value> <value type="java.lang.Integer">5</value> </list> </property> <property name="arreglo"> <array> <ref bean="persona2" /> <ref bean="persona1" /> <bean class="ejemplos.spring.colecciones.beans.Persona"> <property name="nombre" value="Persona Nueva" /> <property name="edad" value="10" /> </bean> </array> </property> <property name="conjunto"> <set> <ref bean="persona1" /> <ref bean="persona2" /> <ref bean="persona2" /> <ref bean="persona1" /> </set> </property> <property name="mapa"> <map> <entry key="persona1" value-ref="persona1" /> <entry key-ref="persona2" value="otra persona" /> <entry key="sin persona" value="no personas" /> <entry key-ref="persona1" value-ref="persona2" /> </map> </property> <property name="propiedades"> <props> <prop key="nombre">Alex</prop> <prop key="pais">Mexico</prop> <prop key="sitio">http://javatutoriales.blogspot.com/</prop> <prop key="facebook">http://www.facebook.com/pages/JavaTutoriales/121935157864634</prop> </props> </property> </bean> </beans> Lo siguiente que debemos hacer es, en nuestro mtodo "main", crear un objeto de tipo "ApplicationContext" para poder obtener nuestros beans. Para ver ms a detalle cmo hacer esto, pueden consultar el segundo tutorial de la serie, aqu lo resumir todo diciendo que crearemos una instancia de "ClassPathXmlApplicationContext" y pasaremos como parmetro de su constructor la ubicacin del archivo de configuracin dentro del classpath, de la siguiente forma: ApplicationContext applicationContext ClassPathXmlApplicationContext("applicationContext.xml"); = new

Lo siguiente que haremos es obtener una referencia al bean "manejador", declarado en el archivo de configuracin, usando el mtodo "getBean" de nuestro objeto "ApplicationContext": ManejadorColecciones ManejadorColecciones.class); manejador = applicationContext.getBean("manejador",

Para terminar invocaremos, en el objeto "manejador", cada uno de los mtodos para mostrar los valores de las colecciones, de la siguiente forma: manejador.muestraLista(); manejador.muestraArreglo(); manejador.muestraConjunto(); manejador.muestraMapa(); manejador.muestraPropiedades();

El mtodo "main" queda de la siguiente forma: public static void main(String[] args) { ApplicationContext ClassPathXmlApplicationContext("applicationContext.xml"); ManejadorColecciones ManejadorColecciones.class); manejador.muestraLista(); manejador.muestraArreglo(); manejador.muestraConjunto(); manejador.muestraMapa(); manejador.muestraPropiedades(); } Al ejecutar nuestra aplicacin obtenemos la siguiente salida: ---Mostrando lista--class ejemplos.spring.colecciones.beans.Persona: nombre: Persona1, edad: 26 class ejemplos.spring.colecciones.beans.Persona: nombre: Persona2, edad: 62 class java.lang.String: Cadena class java.lang.Integer: 5 ---Mostrando arreglo--class ejemplos.spring.colecciones.beans.Persona: nombre: Persona2, edad: 62 class ejemplos.spring.colecciones.beans.Persona: nombre: Persona1, edad: 26 class ejemplos.spring.colecciones.beans.Persona: nombre: Persona Nueva, edad: 10 ---Mostrando conjunto--class ejemplos.spring.colecciones.beans.Persona: nombre: Persona1, edad: 26 class ejemplos.spring.colecciones.beans.Persona: nombre: Persona2, edad: 62 ---Mostrando mapa--[llave] class java.lang.String: persona1, [valor]class ejemplos.spring.colecciones.beans.Persona: nombre: Persona1, edad: 26 [llave] class ejemplos.spring.colecciones.beans.Persona: nombre: Persona2, edad: 62, [valor]class java.lang.String: otra persona [llave] class java.lang.String: sin persona, [valor]class java.lang.String: no personas [llave] class ejemplos.spring.colecciones.beans.Persona: nombre: Persona1, edad: 26, [valor]class ejemplos.spring.colecciones.beans.Persona: nombre: Persona2, edad: 62 ---Mostrando propiedades--[llave] class java.lang.String: facebook, [valor]class http://www.facebook.com/pages/Java-Tutoriales/121935157864634 [llave] class java.lang.String: pais, [valor]class java.lang.String: Mexico [llave] class java.lang.String: nombre, [valor]class java.lang.String: Alex [llave] class java.lang.String: sitio, [valor]class http://javatutoriales.blogspot.com/ Analicemos un poco esta salida. La primera que obtenemos es la salida de la lista. En esta, podemos comprobar que los elementos de la misma se encuentran en el mismo orden en el que los declaramos en el archivo de configuracin. Primero los dos beans de tipo "Persona", despus la cadena "Cadena" que declaramos como un valor, y finalmente el valor "5" que declaramos como un objeto de tipo "java.lang.Integer": java.lang.String: manejador =

applicationContext

new

applicationContext.getBean("manejador",

java.lang.String:

En la siguiente parte de la salida, tenemos el valor del arreglo. Aqu nuevamente, los elementos se encuentran en el mismo orden en el que los declaramos en el archivo de configuracin. Tenemos primero los dos beans de tipo "Persona", y despus el bean interno que declaramos, con el "nombre" de "Persona Nueva" y la "edad" de "10":

Posteriormente est el segmento de la salida correspondiente con el Set. Aqu vemos que aunque en el archivo de configuracin declaramos 4 miembros para esta coleccin, al final en esta solo se insertan 2 objetos, ya que los Sets son colecciones que no permiten duplicados:

La que sigue es la salida de los elementos del mapa. Aqu podemos observar que, efectivamente, tenemos una combinacin tanto de llaves como de valores de tipos "Persona" y "String", de la misma forma que en el archivo de configuracin:

La ltima parte de la salida es la que corresponde con las propiedades. En esta, podemos ver que tanto las llaves como los valores son de tipo "String":

Como vemos, nuestras colecciones se han inyectado de forma correcta ^_^. Tal vez algunos se hayan preguntado y qu ocurre si quiero insertar una propiedad con un valor de "null", o un elemento de las colecciones como "null"? Bueno, responderemos esta pregunta en la ltima parte del tutorial Inyectando valores nulos En casi cada situacin, usaremos DI para cablear un valor constante o una referencia a un objeto dentro de una propiedad de un bean. Sin embargo en algunas ocasiones ser necesario inyectar un valor null a una propiedad. Aunque en Java las referencias a objetos son por default nulas, algunas veces asumir esto no es suficiente para lograr nuestros propsitos. Para establecer una propiedad como "null" usamos el elemento... "<null />". Por ejemplo, si quisiramos establecer la propiedad "nombre" de un bean de tipo "Persona" como "null", lo declararamos de la siguiente forma: <bean id="persona1" class="ejemplos.spring.colecciones.beans.Persona"> <property name="nombre"><null /></property > <property name="edad" value="26" /> </bean> Y eso es todo lo que debemos hacer ^_^. Hemos llegado al final de este tercer tutorial sobre Spring 3, espero que les sea de utilidad. No olviden dejar sus dudas, comentarios y sugerencias. Saludos. Descarga los archivos de este tutorial desde aqu: domingo, 6 de febrero de 2011 Spring 3 - Parte 4: Ciclo de Vida de los Beans En los tutoriales anteriores hemos visto cmo trabajar configurar beans, tanto con anotaciones como con archivo de configuracin en XML, y cmo cablearlos a las propiedades de otros beans. Sin embargo Spring nos proporciona mecanismos para controlar la creacin de beans y ejecutar ciertas acciones en las distintas etapas del ciclo de vida de nuestros beans. En este tutorial aprenderemos cmo controlar cundo deben ser creadas las instancias de los beans y a crearlos a travs de un mtodo esttico de factora, adems de recibir notificaciones cuando un bean es creado y antes de que sea destruido. Crearemos un proyecto en el que iremos probando cada uno de los conceptos que veamos. Lo primero que haremos es crear un nuevo proyecto en NetBeans. Para esto vamos al Men "File->New Project...". En la ventana que se abre seleccionamos la categora "Java" y en el tipo de proyecto "Java Application". Le damos una ubicacin y un nombre al proyecto. Nos aseguramos que las opciones "Create Main Class" y "Set as Main Project" estn habilitadas. Presionamos el botn "Finish" y veremos aparecer en el editor nuestra clase "Main". Agregamos la biblioteca "Spring3" que creamos en el primer tutorial de la serie. Hacemos clic derecho sobre el nodo "Libraries" del proyecto, en el men que aparece elegimos la opcin "Add Library...". En la ventana que se abre

seleccionamos la biblioteca "Spring3" y presionamos el botn "Add Library". Con esto los archivos de la biblioteca deben agregarse a nuestro proyecto. Ahora crearemos un nuevo paquete que contendr a nuestros beans, este paquete se llamar "beans". Hacemos clic derecho en el paquete en el que se encuentra nuestra clase "Main" (que en mi caso es "ejemplos.spring.ciclovida") y en el men que se abre seleccionamos la opcin "New -> Java package..." y al nombre del paquete le agregamos "beans". Presionamos el botn "Finish" y con esto aparecer nuestro nuevo paquete. El proyecto debe verse as:

Crearemos, en el paquete "beans", una interface llamada "Estudiante" que ser la que usaremos para realizar nuestras inyecciones de dependencias y pruebas. Esta interface solo tendr un mtodo llamado "presentaExamen()" que regresar un entero entre 0 y 10 que representar la calificacin del Estudiante en el examen. Esta interface queda de la siguiente forma: public interface Estudiante { int presentaExamen(); } Tambin crearemos, en ese mismo paquete, una clase que implemente esta interface. La clase se llamar "Universitario". Su implementacin del mtodo "presentaExamen()" simplemente ser regresar un nmero aleatorio entre 0 y 10. Esta clase queda de la siguiente forma: public class Universitario implements Estudiante { public int presentaExamen() { return (int) (Math.random() * 10.0); } } Ahora crearemos, en el paquete default (default package), el archivo de configuracin de Spring, "applicationContext.xml". Para esto hacemos clic derecho sobre el nodo "Source Packages" de nuestro proyecto, y en el men contextual que se abre seleccionamos "new -> Other...". En la ventana que se abre, seleccionamos la categora "Other" y como tipo de archivo "Spring XML Configuration File". Le damos un nombre al archivo, en mi caso ser "applicationContext". Hacemos clic en el botn "Next". En la siguiente pantalla debemos seleccionar los namespaces que queremos que tenga nuestro archivo. No seleccionaremos ninguno. Presionamos el botn "Finish" y con eso aparecer en nuestro editor el archivo "applicationContext.xml". Declaramos un bean llamado "estudiante" de tipo "Universitario" dentro del archivo de configuracin, de la siguiente forma: <bean id="estudiante" class="ejemplos.spring.ciclovida.beans.Universitario" /> Comencemos viendo cmo podemos controlar el momento en el que los beans se crean. A esto se le conoce como el scope del bean. Scope de los Beans Por default, los beans en Spring son Singletons...que qu es un singleton?...Singleton es un patrn de diseo con el que se asegura que solo hay una instancia de un bean en nuestra aplicacin. Si, leyeron bien, una y solo una instancia del bean por aplicacin (o ms exactamente por ClassLoader). Esto normalmente se logra haciendo que el constructor de la clase sea privado y proporcionando un mtodo esttico de fbrica que se encarga de controlar que solo haya una instancia de la clase. No entrar ms en detalles porque ese es tema de otro tutorial.

Lo importante es remarcar el hecho de que en Spring, por default, todos los beans son singletons, o sea que el contenedor crea una sola instancia de un bean, no importa cuntas veces llamemos al mtodo "getBean" de "ApplicationContext" (siempre que llamemos al mismo bean, claro est ^_^) Spring siempre nos regresar la misma instancia. Cmo podemos comprobar que esto es verdad? Muy fcilmente ^_^. En Java, cada vez que un objeto es construido, se invoca el constructor de dicho objeto, los beans son objetos; por lo tanto, cada vez que un bean es creado se invoca su constructor. Por lo tanto, podemos poner un mensaje en el constructor para que nos muestre algo en la consola cada vez que un bean de tipo "Universitario" sea creado. Modificaremos por un momento la clase "Universitario" para agregarle un constructor, que no reciba ningn parmetro, que nos muestre un mensaje de creacin del objeto. Agregaremos el siguiente constructor a la clase "Universitario": public Universitario() { System.out.println("--Construyendo un universitario--"); } Ahora obtendremos, en nuestro mtodo "main", un bean de este tipo haciendo uso de un "ApplicationContext" (si no recuerdan bien cmo hacer eso pueden ver cmo en el segundo tutorial de la serie):

ApplicationContext applicationContext ClassPathXmlApplicationContext("applicationContext.xml");

new

A continuacin invocaremos dos veces el mtodo "getBean" del applicationContext para obtener una referencia al bean "estudiante", y lo mostraremos en la consola: System.out.println("Estudiante 1: " + applicationContext.getBean("estudiante")); System.out.println("Estudiante 2: " + applicationContext.getBean("estudiante"));

No hacemos nada especial, solo obtenemos dos veces una referencia al bean "estudiante" y lo mostramos en la consola. Nuestro mtodo "main" queda de la siguiente forma: public static void main(String[] args) { ApplicationContext applicationContext ClassPathXmlApplicationContext("applicationContext.xml"); System.out.println("Estudiante 1: " + applicationContext.getBean("estudiante")); System.out.println("Estudiante 2: " + applicationContext.getBean("estudiante")); } Si ejecutamos nuestra aplicacin obtendremos la siguiente salida en la consola: --Construyendo un universitario-Estudiante 1: ejemplos.spring.ciclovida.beans.Universitario@a46701 Estudiante 2: ejemplos.spring.ciclovida.beans.Universitario@a46701 Como podemos ver, solo se invoc una vez al constructor de la clase "Universitario" y, por lo tanto, solo se construy un objeto de esta clase. Las dos veces que invocamos al mtodo "getBean" este nos regres las dos veces la misma instancia. Esto suena lgico no? Ya que solo declaramos una vez el bean "estudiante" solo debera crearse una vez y siempre que queramos usar este bean deberamos obtener la misma instancia cierto? Si bien esta idea es muy correcta, algunas veces en las que necesitaremos una nueva instancia de un bean cada vez que la pidamos (que llamemos a "getBean"). Afortunadamente existe una forma de hacer esto. Cuando declaramos un elemento "<bean>" en el archivo de configuracin de Spring, tenemos la opcin de declarar un scope para ese bean. Por default el valor de este elemento es "singleton". Spring proporciona 5 posibles valores para este elemento:

new

singleton Existir una sola instancia del bean por contenedor. Este es el scope por defult. prototype Se crear una nueva instancia del bean por cada llamada a "getBean", o sea, cada vez que el bean vaya a ser usado.

request Existir una sola instancia del bean por cada peticin HTTP; esto es, cada peticin HTTP tiene su propia instancia de un bean. Este scope solo es vlido cundo se usa un contenedor de Spring con capacidades web como Spring MVC. session Existir una instancia del bean por cada sesin HTTP. Este scope solo es vlido cuando se usa un contenedor de Spring con capacidades web como Spring MVC. globalSession Existir una instancia del bean por cada sesin global HTTP. Tpicamente solo es vlida cuando se trabaja con portlets. Este scope solo es vlido cuando se usa un contenedor de Spring con capacidades web como Spring MVC.

En Spring 3 existe un nuevo y secreto sexto scope llamado "thread scope", pero no est registrado por default. Pueden encontrar ms informacin de este scope en la documentacin de Spring. Veamos cada uno de estos scopes en detalle: El scope singleton Con este scope, como dije anteriormente, solo existe una instancia del bean por contenedor, y esta instancia es obtenida cada vez que se llama al mtodo "getBean". Dicindolo de otra forma: cundo definimos un bean, y este tiene scope definido como singleton (el default), el contenedor de IoC de Spring crea exactamente una instancia del bean definido. Esa instancia nica es almacenada en un cach especial para estos beans singleton, y todas las llamadas subsecuentes para obtener ese bean, recibirn el objeto que se encuentra en el cach. El scope prototype Este scope es, se podra decir, el opuesto a singleton, ya que en este caso se crea una nueva instancia del bean cada vez que se solicita un bean especfico, esto es, cada vez que pedimos un bean invocando al mtodo "getBean". Como regla general, usamos el scope prototype para todos los beans con estado, y el scope singleton para todos los beans sin estado. A diferencia de los otros scopes, Spring no administra el ciclo de vida completo de los beans prototype (esto es muy importante para lo que veremos un poco ms adelante); el contenedor crea una instancia, la configura, y la ensambla, tambin la enva al cliente, pero despus de eso Spring ya no mantiene un registro de esa instancia. Entonces, aunque los mtodos de callback de inicializacin del ciclo de vida son llamados en todos los objetos sin importar su scope, en el caso de los objetos prototype, los mtodos de callback de destruccin NO son llamados. Los scopes request, session, y globalSession Los scopes request, session, y globalSession, solo estn disponibles si usamos usando Spring en una aplicacin web, y usamos una implementacin de "ApplicationContext" que funcione en web (como "XmlWebApplicationContext"). Si intentamos usar estos scopes con alguna otra implementacin (como con "ClassPathXmlApplicationContext"), obtendremos una excepcin de tipo "IllegalStateException". El scope request Con este scope, el contenedor una nueva instancia del bean por cada peticin HTTP. Cuando la peticin termina de ser procesada, el bean es descartado. El scope session Los beans con scope "session" son creados cada vez que se crea una sesin HTTP, y vive mientras la sesin permanezca viva, o sea que cundo la sesin se descarta, el bean almacenado en esa sesin tambin es descartado. El scope globalSession El scope "globalSession" es similar al scope al scope "session" y solo es aplicable en el contexto de aplicaciones web basadas en portlets. La especificacin de portlets define la nocin de una sesin global que es compartida por todos los portlets que componen una aplicacin web. Los beans con este scope viven por el tiempo de la sesin global de los portlets. Si estamos creando una aplicacin web no-portlet (basada en servlets) y definimos algn bean con este scope, entonces se usar el scope "session" normal y no obtendremos ningn error. Ahora que hemos visto que existen varios scopes, y las deferencias entre estos, veamos cmo arreglar el problema que tenamos anteriormente, en donde nicamente obtenamos una instancia del bean "estudiante", sin importar el

nmero de veces que llamemos al mtodo "getBean". En esta ocasin lo que queremos es que se cree una nueva instancia del bean cada vez que lo requiramos. Como vimos en la definicin de los scopes, esto es posible lograrlo si definimos el bean con el scope "prototype", por lo que modificaremos la declaracin del bean, agregndole el atributo "scope" de la siguiente forma: <bean id="estudiante" class="ejemplos.spring.ciclovida.beans.Universitario" scope="prototype" /> Si volvemos a ejecutar nuestra aplicacin, veremos la siguiente salida en la consola: --Construyendo un universitario-Estudiante 1: ejemplos.spring.ciclovida.beans.Universitario@1808199 --Construyendo un universitario-Estudiante 2: ejemplos.spring.ciclovida.beans.Universitario@1bc887 Como podemos ver, en esta ocasin Spring ha construido un nuevo objeto de tipo "Universitario" por cada llamada el mtodo "getBean". El resto de los scopes los revisaremos cuando veamos cmo crear aplicaciones web con Spring. Ahora veamos cmo podemos crear beans usando mtodos estticos de fbrica, como se hace en el patrn de diseo factory. Creando Beans desde Mtodos Estticos de Factory La mayor parte del tiempo, los beans que configuramos en el contexto de aplicacin de Spring son creados invocando uno de los constructores de la clase. Esto est bien si es que creamos nuestros beans siempre con constructores pblicos. Pero qu ocurre si por alguna razn no podemos usar un constructor pblico? O qu pasa si usamos el API de un tercero que expone los objetos a travs de un mtodo esttico de fbrica? Afortunadamente Spring nos permite seguir creando beans con este tipo de clases. Para ejemplificar esto veamos el siguiente bean, el cul es una implementacin del patrn de diseo singleton, del cual hablamos anteriormente. Crearemos una nueva clase, en el paquete "beans", llamada "Sun", por Sun Microsystems ^_^ (ya saben, por el asunto de que solo hay un Sun Microsystems _ ). La clase "Sun", como dije, ser una implementacin del patrn de diseo singleton. Agregaremos un mtodo de instancia, el cual solo se encargar de regresar un cadena que podremos postrar en la consola. La clase queda de la siguiente forma: public class Sun { private static Sun instancia; static { instancia = new Sun(); } private Sun() { } public static Sun getInstancia() { return instancia; } public String getMensaje() { return "Hola a todos los desarrolladores Java"; } } La clase anterior tiene un constructor privado, lo que significa que solo puede usarse desde dentro de la misma aplicacin. Adems tiene una instancia del mismo tipo "Sun", la cual se inicializa dentro de un mtodo de inicializacin esttico, o sea que la instancia se crear en cuanto la clase se cargue en el classloader. Como el constructor y la instancia de la clase son privadas, necesitamos una forma de obtener dicha instancia. Para eso proporcionamos un mtodo de fbrica, el mtodo "getInstancia", el cual nos regresar la instancia cada vez que la necesitemos. Con las dos consideraciones anteriores, nos aseguramos de que solo existir una instancia de la clase anterior en todo el classloader y que no se hay forma de crear otra instancia. Podemos ver que con esta medida ya no podemos crear

una instancia de la clase usando el operador "new", sino que debemos usar el mtodo "getInstancia". Entonces, cmo haramos para que Spring creara un bean de esta clase? Para casos como este, el elemento "<bean>" proporciona un atributo llamado "factory-method". Este atributo nos permite especificar un mtodo esttico que ser invocado, en vez del constructor, para crear una instancia de la clase. As que ahora configuraremos un bean de tipo "Sun" en el archivo de configuracin, para esto agregamos un nuevo elemento "<bean>" de esta forma: <bean id="sun" class="ejemplos.spring.ciclovida.beans.Sun" factory-method="getInstancia" /> Ahora modificaremos nuestro mtodo "main". Seguiremos creando una instancia de "ApplicationContext" a partir del archivo "applicationContext.xml", pero ahora obtendremos una referencia al bean llamado "sun". Tambin invocaremos a su mtodo "getMensaje" y mostraremos la cadena que regresa en la consola, de la siguiente forma: Sun sun = applicationContext.getBean("sun", Sun.class); System.out.println(sun.getMensaje()); Por lo que el mtodo "main" queda de la siguiente forma: public static void main(String[] args) { ApplicationContext ClassPathXmlApplicationContext("applicationContext.xml"); Sun sun = applicationContext.getBean("sun", Sun.class); System.out.println(sun.getMensaje()); } Al ejecutar la aplicacin obtendremos la siguiente salida en la consola: Hola a todos los desarrolladores Java Con lo cual podemos darnos cuenta de que la instancia del bean se ha creado correctamente, usando el mtodo de fbrica, y que podemos usar sus mtodos de forma normal ^_^. Ahora veremos el ciclo de vida de un bean en Spring, y cmo recibir notificaciones durante algunos de los distintos eventos del ciclo de vida de nuestros beans. El ciclo de vida de un bean En una aplicacin Java tradicional, el ciclo de vida de un bean es muy simple. Se usa el operador "new" para instanciar el bean, y est listo para ser usado. Una vez que dejamos de usar el bean, es elegible para ser recolectado por el garbage collector. En contraste, el ciclo de vida de un bean dentro del contenedor de Spring es un poco ms elaborado. Es importante entender el ciclo de vida de un bean de Spring, ya que es posible que querramos tener ventaja de algunas de las oportunidades que Spring nos ofrece para personalizar la forma en la que un bean es creado. La siguiente figura muestra el ciclo de vida de un bean tpico que es cargado en un contenedor de tipo, y pongan atencin porque esto es importante, "BeanFactory":

applicationContext

new

Despus de ver esta figura, podemos darnos cuenta de que Spring realiza bastantes pasos de configuracin antes de que un bean est listo para ser usado por un, y nuevamente pongan atencin, "BeanFactory". La siguiente tabla explica cada uno de estos pasos con ms detalle:

Paso 1. Instanciar 2. Llenar Propiedades Spring instancia el bean Spring inyecta las propiedades del bean

Descripcin

3. Establecer el nombre Si el bean implementa "BeanNameAware", Spring pasa el id del bean a "setBeanName()" del bean 4. Establecer el bean factory Si el bean implementa "BeanFactoryAware", Spring pasa el bean factory a "setBeanFactory()"

5. Post procesar (antes Si hay algn "BeanPostProcessors", Spring llama a sus mtodos de la inicializacin) "postProcessBeforeInitialization()" Si el bean implementa "InitializingBean", se llamar a su mtodo "afterPropertiesSet()". Si el bean tiene un mtodo "init-method" propio (que veremos en la siguiente seccin), el mtodo ser llamado. Si hay algn "BeanPostProcessors", Spring llama a sus mtodos "postProcessAfterInitialization()" En este punto el bean est listo para ser usado por la aplicacin y permanecer en el bean factory hasta que deje de ser ocupado. Si el bean implementa "DisposableBean", se llama a su mtodo "destroy()". Si el bean tiene un mtodo "destroy-bean" propio, el mtodo especificado ser llamado.

6. Inicializar beans

7. Post procesar (despus de la inicializacin) 8. El bean est listo para usarse 9. Destruir el bean

Por qu recalqu el hecho de que este es el ciclo de vida de un bean en un "BeanFactory"? Pues bien, esto lo hice por el hecho de que el ciclo de vida del bean es un poco diferente dentro de un "ApplicationContext", el cual podemos ver en la siguiente imagen:

La nica diferencia es que si el bean implementa la interface "ApplicationContextAware", se llama a su mtodo "setApplicationContext". Ahora que ya tenemos una mejor idea del ciclo de vida de los beans, veamos cmo podemos recibir notificaciones cuando nuestros beans son creados o destruidos. Callbacks de creacin y destruccin de beans Cuando un nuevo bean es creado, puede ser necesario que debamos realizar algn proceso de inicializacin para dejarlo en un estado razonable para su uso. De la misma forma, cuando ya no necesitamos un bean, y este va a ser removido del contenedor, podra ser necesario realizar algn proceso de limpieza. Spring nos proporciona varios mecanismos para interactuar con la administracin del ciclo de vida, de los beans, de nuestro contenedor; ms especficamente para el momento en el que los beans son creados y en el momento en el que sern destruidos. Estos mecanismos se conocen como mtodos de retrollamada, o callback en ingls. Cada uno de estos mecanismos, como ocurre regularmente, tiene sus ventajas y sus desventajas, pero los tres son igual de fciles de usar. Los tres mecanismos son:

Implementacin de interfaces para recibir notificaciones. Declaracin de los mtodos que recibirn las notificaciones, usando archivos de configuracin. Marcar los mtodos que recibirn las notificaciones, usando anotaciones.

Implementacin de Interfaces para Recibir Notificaciones Para recibir las notificaciones de la creacin o destruccin de un bean, podemos implementar las interfaces "org.springframework.beans.factory.InitializingBean" y "org.springframework.beans.factory.DisposableBean". El contenedor llama al mtodo "afterPropertiesSet()" al momento de inicializar al vean, y a "destroy()" antes de destruir al bean, cada uno en su interface correspondiente. Vemos un ejemplo del uso de estas interfaces. Para esto modificaremos nuestra clase "Universitario" haciendo que implemente estas dos interfaces. El mtodo "afterPropertiesSet()" servir para indicar cuando nuestro objeto sea creado, o sea cuando nuestro nuevo Universitario entre a la escuela ^_^. Usaremos este mtodo para mostrar un mensaje de bienvenida en la consola; y usaremos el mtodo "destroy()" para mostrar un mensaje de despedida, tambin en la consola. La clase "Universitario" queda de la siguiente forma: public class Universitario implements Estudiante, InitializingBean, DisposableBean { public Universitario() { System.out.println("--Construyendo un universitario--"); } public int presentaExamen() { return (int) (Math.random() * 10.0); } public void afterPropertiesSet() throws Exception { System.out.println("Bienvenido universitario a tu nuevo segundo hogar."); } public void destroy() throws Exception { System.out.println("Vuela libre con tus alas propias."); } } Un poco dramtico pero muestra la idea del ejemplo ^_^!. Si ejecutamos nuestra aplicacin, obteniendo en el mtodo "main" nuestro bean "estudiante", veremos la siguiente salida en consola: --Construyendo un universitario-INFO: Pre-instantiating singletons org.springframework.beans.factory.support.DefaultListableBeanFactory@134bed0: [estudiante,sun]; root of factory hierarchy Bienvenido universitario a tu nuevo segundo hogar. Estudiante 1: ejemplos.spring.ciclovida.beans.Universitario@6e293a

defining

in beans

Si observamos la salida anterior con calma, podremos observar que falta un mensaje, el mensaje correspondiente con la destruccin del bean. Esto ocurre porque Spring no sabe que la aplicacin ha dejado de ejecutarse (ya que esta termina de manera sbita al terminarse el mtodo "main") y por lo tanto no sabe cundo llamar al mtodo "destroy". Entonces cmo hacemos para que Spring sepa cundo es que la aplicacin se termina? O dicho de otra forma cmo sabe Spring cundo debe destruir el contenedor de beans y por lo tanto llamar al mtodo "destroy"? Afortunadamente Spring nos proporciona una manera elegante de hacer esto. Si recuerdan estamos usando, como contenedor de beans, una clase que implementa la interface "ApplicationContext", en este caso la clase "ClassPathXmlApplicationContext". Esta clase tiene una clase base llamada "AbstractApplicationContext", la cual contiene un mtodo "close" que nos sirve para indicarle a Spring cundo debe cerrar el ApplicationContext, y destruir todos los beans que se encuentran en el. Modificamos nuestro mtodo "main" para declarar nuestra variable "applicatonContext" para que haga uso de una referencia de tipo "AbstractApplicationContext", y llamamos, al final del "main", a su mtodo "close". El mtodo "main" queda de la siguiente forma: AbstractApplicationContext applicationContext ClassPathXmlApplicationContext("applicationContext.xml"); = new

System.out.println("Estudiante 1: " + applicationContext.getBean("estudiante"));

applicationContext.close(); Adems de este cambio debemos modificar una cosa en el archivo de configuracin de Spring. En este momento el bean "estudiante" est declarado como un bean con scope "prototype", o sea que se crea uno cada vez que se llama al mtodo "getBean". Si recuerdan en la explicacin de los scopes de los beans, dijimos que los mtodos de destruccin de beans no sern llamados en los beans "prototype", por lo que debemos cambiar el scope del bean para que siga siendo un singleton. Cambiamos la siguiente declaracin:

<bean id="estudiante" class="ejemplos.spring.ciclovida.beans.Universitario" scope="prototype" /> Para que quede de esta forma: <bean id="estudiante" class="ejemplos.spring.ciclovida.beans.Universitario" /> Si volvemos a ejecutar nuestra aplicacin, veremos la siguiente salida en la consola: --Construyendo un universitario-INFO: Pre-instantiating singletons org.springframework.beans.factory.support.DefaultListableBeanFactory@1db4f6f: [estudiante,sun]; root of factory hierarchy Bienvenido universitario a tu nuevo segundo hogar. Estudiante 1: ejemplos.spring.ciclovida.beans.Universitario@54a328

defining

in beans

31/01/2011 01:31:44 AM org.springframework.context.support.AbstractApplicationContext doClose INFO: Closing org.springframework.context.support.ClassPathXmlApplicationContext@c1b531: startup date [Mon Jan 31 01:31:43 CST 2011]; root of context hierarchy 31/01/2011 01:31:44 AM org.springframework.beans.factory.support.DefaultSingletonBeanRegistry destroySingletons INFO: Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1db4f6f: defining beans [estudiante,sun]; root of factory hierarchy Vuela libre con tus alas propias. Con esto comprobamos que los mtodos se han llamado en los momentos correspondientes. Sin embargo ahora nuestra aplicacin ha quedado acoplada a las libreras de Spring (lo cual no queremos). Como siempre, Spring nos proporciona una forma de evitar el tener que hacer este acomplamiento, declarando en el archivo de configuracin los mtodos que sern usados para la inicializacin y destruccin del bean. Declaracin de los mtodos que recibirn las notificaciones, usando archivos de configuracin Como pasa con todo en Spring, el declarar los mtodos que se usarn para la inicializacin y destruccin del bean es de lo ms simple. Lo nico que debemos hacer es declarar, en el elemento "&lt;bean>", el atributo "init-method", para el mtodo de inicializacin, y "destroy-method", para el mtodo de destruccin. Estos mtodos pueden ser cualquiera que exista dentro de nuestra clase. Para ilustrar eso modificaremos nuestra clase "Universitario" agregando dos nuevos mtodos. El primero ser el mtodo "preparaEstudiante", el cual mostrar un mensaje en la consola mostrando la inicializacin del bean. El segundo mtodo ser "despideEstudiante", que tambin mostrar un mensaje en consola, pero indicando que el bean ser destruido: public void preparaEstudiante() { System.out.println("Preparando al nuevo estudiante para entrar en la universidad."); } public void despideEstudiante() { System.out.println("Finalmente podemos decir adios a este estudiante."); } Y declaramos, en el archivo "applicationContext.xml", que el bean "estudiante" usar estos dos mtodos: <bean id="estudiante" class="ejemplos.spring.ciclovida.beans.Universitario" method="preparaEstudiante" destroy-method="despideEstudiante" /> init-

Si ejecutamos nuestra aplicacin en este momento obtendremos los mensajes combinados de la implementacin de las interfaces del punto anterior y de los mtodos declarados en el archivo de configuracin. Para evitar esto eliminaremos temporalmente la declaracin de las interfaces de nuestra clase "Universitario", dejndolo de esta forma: public class Universitario implements Estudiante

{ public Universitario() { System.out.println("--Construyendo un universitario--"); } public int presentaExamen() { return (int) (Math.random() * 10.0); } public void preparaEstudiante() { System.out.println("Preparando al nuevo estudiante para entrar en la universidad."); } public void despideEstudiante() { System.out.println("Finalmente podemos decir adios a este estudiante."); } } Si ejecutamos nuestra aplicacin obtendremos la siguiente salida: --Construyendo un universitario-Preparando al nuevo estudiante para entrar en la universidad. Estudiante 1: ejemplos.spring.ciclovida.beans.Universitario@6e293a Finalmente podemos decir adios a este estudiante. Como podemos ver, los mtodos han sido llamados sin necesidad de implementar ninguna interface, por lo que ahora estn completamente desacoplados de Spring. Esto nos sirve bastante si tenemos una o dos clases que debemos inicializar de esta manera. Pero qu ocurre si queremos realizar procesos de inicializacin o destruccin en muchos beans? Si usamos alguna convencin de nombres para estos mtodos de inicializacin y destruccin (como por ejemplo "inicializa" y "destruye") no es necesario que declaremos "init-method" y "destroy-method" en cada bean de forma individual. En vez de eso, podemos tomar ventaja de los atributos "default-init-method" y "default-destroy-method" de elemento "<beans>". De esta forma estamos configurando el contenedor de beans de Spring para que busque estos mtodos de inicializacin y destruccin en cada bean que declaremos en el contenedor. El contenedor de IoC de Spring llamar a estos mtodos, de forma automtica, cada vez que un bean sea creado o destruido. Esto tambin nos ayuda a usar una convencin de nombres consistente para mtodos callback de inicializacin y destruccin ^_^. Para ejemplificar esto, modifiquemos una vez ms nuestra clase "Universitario", agregando un nuevo mtodo de inicializacin llamado "inicializa", que nuevamente mostrar un mensaje en la consola, y un mtodo de destruccin llamado "destruye", que tambin mostrar un mensaje en la consola: public void inicializa() { System.out.println("Realizando inicializacion de rutina en el bean."); } public void destruye() { System.out.println("Realizando destruccion de rutina en el bean."); } Y modificamos el archivo "applicationContext.xml" para que quede de esta forma: <?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" default-init-method="inicializa" default-destroy-method="destruye" > <bean id="estudiante" class="ejemplos.spring.ciclovida.beans.Universitario" /> </beans> Si ejecutamos nuevamente nuestra aplicacin obtendremos la siguiente salida en la consola:

--Construyendo un universitario-Realizando inicializacion de rutina en el bean. Estudiante 1: ejemplos.spring.ciclovida.beans.Universitario@6e293a Realizando destruccion de rutina en el bean. Que como podemos ver, ha ejecutado los mtodos de inicializacin y destruccin por default de manera correcta. Qu pasa si indicamos dos mtodos, uno con "init-method" y otro con "default-init-method"? En ese caso, el mtodo ms especfico ("init-method" que se indica a nivel de bean) toma precedencia sobre el mtodo ms general. Estas dos formas de configurar los mtodos de inicializacin y destruccin de beans es muy buena, pero qu ocurre si estamos trabajando con anotaciones? Afortunadamente tambin tenemos una forma de indicar estos mtodos callback en caso de que estemos usando anotaciones. Marcar los mtodos que recibirn las notificaciones, usando anotaciones. Spring (bueno, en realidad la especificacin JEE) proporciona un par de anotaciones para el ciclo de vida. Para que estas anotaciones tengan efecto, debemos configurar nuestra aplicacin para el uso de anotaciones. Si no recuerdan cmo hacer eso, pueden revisar el tutorial de la configuracin del contenedor de IoC de Spring. Una vez que tenemos nuestro bean, lo nico que debemos hacer es marcar el mtodo de inicializacin usando la anotacin "@PostConstruct", y el mtodo de destruccin usando la anotacin "@PreDestroy", de la siguiente forma: @PostConstruct public void inicializa() { System.out.println("Realizando inicializacion de rutina en el bean."); } @PreDestroy public void destruye() { System.out.println("Realizando destruccion de rutina en el bean."); } Cuando ejecutemos esta aplicacin veremos aparecer la siguiente salida en la consola: --Construyendo un universitario-Realizando inicializacion de rutina en el bean. Estudiante 1: ejemplos.spring.ciclovida.beans.Universitario@187814 Realizando destruccion de rutina en el bean. Que como podemos ver nos indica que esta configuracin tambin ha funcionado adecuadamente ^_^. Combinando Mecanismos de Callback del Ciclo de Vida Como vimos, tenemos 3 opciones para recibir notificaciones sobre la creacin y destruccin del bean. Si es necesario, tenemos la posibilidad de combinar estos tres mecanismos en el mismo bean. En el caso de la construccin del bean, las llamadas a los distintos mtodos se realizan en el siguiente orden:

Mtodos marcados con la anotacin "@PostConstruct". El mtodo "afterPropertiesSet", de la interface "InitializingBean". El mtodo que indiquemos en el archivo de configuracin (recordemos que si indicamos un valor para "initmethod", este toma precedencia sobre "default-init-method").

En la destruccin del bean, los mtodos se ejecutan en el mismo orden:

Mtodos marcados con la anotacin "@PreDestroy". El mtodo "destroy" de la interface "DisposableBean". El mtodo que indiquemos en el archivo de configuracin ("destroy-method" o "default-destroy-method").

Si por alguna razn marcramos un mtodo para usar ms de un mecanismo (digamos que marcramos el mtodo "afterPropertiesSet", de la interface "InitializingBean", con la anotacin "@PostConstruct") el mtodo ejecutar una sola vez. Ahora que sabemos todo lo que debemos saber al respecto del ciclo de vida de los beans en Spring, podemos terminar tranquilos este tutorial ^_^. Espero que les sea de utilidad, y como siempre no olviden dejar todas sus dudas, comentarios, y sugerencias.

Saludos. Descarga los archivos de este tutorial desde aqu:

También podría gustarte