Capítulo 2: Conexión de beans Tipos de contenedores, conexiones y vida de los beans En este capítulo hablaremos sobre los contenedores de beans, veremos las diferentes formas que hay en Spring para conectarlos, las conexiones entre los propios beans así como cómo conectar los beans con sus distintas vías. Cerraremos el capítulo con la delimitación, vida e inicio y destrucción que tienen los beans dentro de este framework. Javier Sevilla Sánchez Trabajo de fin de carrera de la Ingeniería Técnica en Informática de Gestión (I.T.I.G) 1 Contenido Conexión de Beans ........................................................................................................................ 3 Introducción .............................................................................................................................. 3 Bean dentro de un contenedor ................................................................................................. 3 Contenedor de beans ................................................................................................................ 3 BeanFactory .............................................................................................................................. 4 ApplicationContext.................................................................................................................... 4 Pasos de la vida de un Bean ..................................................................................................... 5 Ejemplo de creación y conexión de beans ................................................................................ 6 Conectar tipos múltiples ......................................................................................................... 10 Tipos de conexión de beans ........................................................................................................ 13 Auto-conexión byName .......................................................................................................... 13 Auto-conexión byType ............................................................................................................ 14 Auto-conexión constructor ..................................................................................................... 14 Auto-conexión autodetect ...................................................................................................... 14 La auto-conexión default ........................................................................................................ 15 La Auto-conexión no ............................................................................................................... 15 Configuración de la creación de los beans .................................................................................. 16 Delimitación de un bean ......................................................................................................... 16 Creación de beans con clases singleton .................................................................................. 17 Uso de init-method y de destroy-method (inicializar y destruir)............................................ 17 Conexión de Beans Introducción En el capítulo anterior hemos dado los primeros pasos con Spring, hemos visto por primera vez la inyección de dependencia (DI) y la programación orientada a aspectos (AOP) creando unos sencillos proyectos a modo de ejemplo. A lo largo de este capítulo veremos más en profundidad el contenedor de Spring y sus distintas implementaciones. Las principales categorías de las implementaciones son la factoría de beans y el contexto de aplicación. En este capítulo veremos cómo conectar beans dentro del contenedor y qué información daremos al fichero XML para crear una aplicación con una DI potente. Bean dentro de un contenedor A diferencia de Java tradicional en el que el ciclo de vida del objeto es desde su instanciación con new hasta su etiquetado por el recolector, en Spring el ciclo de vida es más complejo. Aunque dependa de si el bean ha sido creado por una factoría o un contexto, el bean pasa por una serie de pasos entre los que se encuentran la instanciación, la asignación de propiedades y nombre, nombre de la fábrica, procesamiento, iniciación…etc. Así hasta que se ejecuta el método destroy() sobre él. Contenedor de beans Como ya dijimos, en el enfoque tradicional las asociaciones llevan a código complejo y no reutilizable ni “testeable”. En Spring el contenedor es el responsable de la interconexión de beans. El contenedor será el responsable de la inyección de dependencia y del ciclo de vida de los beans, creándolos, interconectándolos y destruyéndolos. Spring tiene diversos contenedores, pero responden a dos grandes grupos según la implementación del interfaz BeanFactory o AplicationContext. BeanFactory La implementación más usual es la XmlBeanFactory al cual se le pasa un objeto que implemente Resource (hay ocho implementaciones) que proporcionará el XML con las definiciones de los beans. Es el contenedor más básico, pero es más que la instanciación y entrega de beans. Cuando una fábrica entrega un bean lo entrega configurado, consciente de sus dependencias y listo para usar. El siguiente ejemplo crea un XmlBeanFactory como implementación de BeanFactory con un FileSystemResource como implementación de Resource y obtiene el bean llamado beanEjemplo. BeanFactory factoria = new XmlBeanFactory(new FileSystemResource(“/home/user/spring/beans.xml”)); BeanExample beanEjemlo = (BeanExample) factory.getBean(“beanEjemplo”); ApplicationContext Las aplicaciones creadas con Spring con normalidad usan implementaciones de AplicationContext en vez de BeanFactory. Esto es debido a que AplicationContext tiene funcionalidades adicionales dejando la BeanFactory para aplicaciones con recursos más limitados como pueda ser un móvil, o sistemas empotrados. Otra diferencia es cómo abren los beans. Mientras la factoría crea el bean cuando se llama a getBean() el contexto abre previamente todos los beans. ApplicationContext tiene la posibilidad de internacionalizar aplicaciones (I18N), generalizar la apertura de recursos de archivo así como otorgar la posibilidad de publicar eventos para beans receptores. De las diversas implementaciones las más comunes son ClassPathXmlApplicationContext, FileSystemXmlApplicationContext y XmlWebApplicationContext. Ésta última la trataremos más adelante en el capítulo destinado a Spring MVC. La diferencia entre FileSystemXmlApplicationContext y ClassPathXmlApplicationContext es que el primero buscará en el sistema de archivos y el segundo según el path de la clase incluyendo archivos jar. Ejemplo de ello sería: ApplicationContext ctx = new ClassPathXmlApplicationContext(“miFichero.xml”); Pasos de la vida de un Bean Como ya hemos visto, un bean en Spring tiene una vida más compleja que en Java puro. Sus pasos son: 1. 2. 3. 4. 5. 6. 7. Instanciar: Spring instancia el bean. Informar de las propiedades: Spring hace la inyección a las propiedades. Asignación del nombre: Spring pasa el nombre del bean si este implementa BeanNameAware. Establecer nombre de la fábrica y el contexto: Si el bean implementa BeanNameAware le pasará el nombre de la fábrica y en el caso de implementar ApplicationContextAware y de estar contenido en un contexto se le pasaría el nombre del contexto. Iniciación del Bean: Si el bean implementa InitializingBean, se llamaría a su método afterPropertiesSet(). Existen dos métodos que se llamarían si hubiese algún BeanPostProccessor, uno antes de la inicialización y otro después. Estado de listo para su uso: Tras esto, el bean ya estaría listo para usarse. Destrucción del bean: Si el bean implementa DisposableBean se llamará al método destroy(). Ejemplo de creación y conexión de beans Hasta ahora hemos visto distintos proyectos con Spring que creaban y usaban beans, pero no habíamos entrado en detalle en la explicación de estas conexiones. Existe un eterno debate de cuál es la mejor opción para la inyección de dependencias si por constructor o por el contrario por setter. Como para casi todos los debates la respuesta es “depende”. Inyección por constructor Por un lado la inyección por constructor crea una fuerte dependencia con el instanciador ya que este ha de tener todas las dependencias antes, así garantiza que un bean está completamente configurado antes de usarse. Si se inyecta por constructor es posible que no sean necesarios métodos setter, con lo que la clase será más sencilla e inalterables sus dependencias. Inyección por setter Sin embargo, la inyección por constructor tiene también sus inconvenientes. Si el bean tiene muchas dependencias el constructor será complejo, si existen varios parámetros del mismo tipo pues puede confundir su instanciación y acaba siendo más complejo cuando la clase hereda. La configuración por setter puede realizar construcciones más complejas. Spring permite ambas configuraciones, con lo que no restringe a una forma la inyección. Ejemplo de Conexión Continuando con la filosofía de anteriores ejemplos, veamos cómo se conectan beans tomando como ejemplo de nuevo un escenario universitario. Al inicio del curso, los responsables de hostelería han visto que este año habrá más alumnos, con lo que han decidido contratar a más gente. Para el puesto en cuestión se valoraran distintas cualidades como saber cocinar, limpiar, el trato con la gente… etc. El código del interfaz trabajador sería el siguiente: public interface Worker { void work() throws WorkingException; } La siguiente clase define los candidatos camareros: package es.uah.uahconnection.cafe.model; public class Waiter implements Worker { private int coffeesServedDaily = 1; public Waiter() { } public Waiter(int coffeesServedDaily) { this.coffeesServedDaily = coffeesServedDaily; } public void work() throws WorkingException { System.out.println("el camarero está sirviendo " + coffeesServedDaily + " cafés"); } } Veamos cuál sería la implementación más básica de camarero: <bean id="joselito" class="es.uah.uahconnection.cafe.model.Waiter"/> Esta es la definición más básica de un bean, tan sólo se le da un identificador y la clase a la que pertenece el objeto. De los dos constructores que tienen los camareros, Joselito será creado con el constructor sin parámetros. Tal y como vemos no es muy complicado que se te considere como camarero, con servir un café al día vale. Pero no creo que Joselito consiga el trabajo con tan poco esfuerzo. Pepe viene con más entusiasmo, él asegura que es capaz de servir al menos 30 cafés al día. Para ello hacemos uso del constructor con parámetro, en Spring el modo de definirlo es así: <bean id="pepe" class="es.uah.uahconnection.cafe.model.Waiter"> <constructor-arg value="30"/> </bean> Con la etiqueta <constructor-arg> se pasan los parámetros que el constructor precise siempre que coincidan en número, tipo y posición así obtenemos la inyección mediante constructor. Pepe es capaz de servir 30 cafés, pero hay competidores más preparados. Alberto es capaz de poner el mismo número de cafés mientras limpia el local. Veamos como es el código del camarero-limpiador. public class WaiterDustman extends Waiter { private Local local; public WaiterDustman(int coffeesServedDaily, Restaurant restaurant) { super(coffeesServedDaily); this.local = restaurant; } @Override public void work() throws WorkingException{ super.work(); local.clean(); } } Siendo el interfaz local y su implementación restaurante la siguiente: interface Local { void clean(); } public class Restaurant implements Local { public void clean() { System.out.println("El ha sido limpiado"); } } La definición del bean Alberto que haremos en Spring le inyectaremos otro bean “cafeteriaPolitecnica” el cual es de la clase restaurante. <bean id="alberto" class="es.uah.uahconnection.cafe.model.WaiterDustman"> <constructor-arg value="25"/> <constructor-arg ref="cafeteriaPolitecnica"/> </bean> Lo que Spring internamente ejecutaría sería algo similar a esto: Local restaurant = new Restaurant(); Worker alberto = new WaiterDustman(coffeesServedDaily, restaurant); Como hemos visto en anteriores ejemplos y hemos comentado al principio de este punto, Spring permite configurar dependencias con los métodos setter como es el caso del cocinero y su receta. public class Kitchener implements Worker { private Recipe recipe;//receta private int diners;//comensales public Kitchener() { } public void setRecipe(Recipe recipe) { } public void setDiners(int diners) { this.diners = diners; } public void work() throws WorkingException { System.out.println("Se dispone a cocinar " + recipe.getName()); recipe.develop(); } } La interfaz receta sería: public interface Recipe { void develop(); public String getName(); } Y la clase paella valenciana sería la siguiente: public class PaellaValenciana implements Recipe { private static final String NAME = "Paella valenciana"; public void develop() { fryTheMeat(); sauteVegetables(); pourWater(); addRice(); } public String getName() { return NAME; } public void fryTheMeat(){ System.out.println("La carne se está friendo"); } public void sauteVegetables(){ System.out.println("las verduras se están rehogando"); } public void pourWater(){ System.out.println("se vierte agua"); } public void addRice(){ System.out.println("se añade el arroz"); } } Ernesto es un buen cocinero cuya especialidad es la paella valenciana receta de Arguiñano. La definición de Ernesto así como de su paella valenciana sería la siguiente. <bean id="paellaValencianaArguiñano" class="es.uah.uahconnection.cafe.model.PaellaValenciana"/> <bean id="ernesto" class="es.uah.uahconnection.cafe.model.Kitchener"> <property name="recipe" ref="paellaValencianaArguiñano"/> <property name="diners" value="6"/> </bean> Como vemos en el código podemos asignar valores mediante el tag <property>. Esto sólo será así si en la clase tenemos un método setter para tal propiedad. Para inyectar valores simples se hará con el campo value mientras que para inyectar un bean definido en Spring se hará mediante el campo ref. Spring sabrá si los valores simples son de tipo numérico, cadena o booleano. Para definir a Ernesto se ha usado una inyección de bean y otra de valor simple, se ha pasado la receta de paella que aprendió de Arguiñano y el número de comensales para el que es capaz de cocinar. Inyectar beans internos Los beans internos, al igual que pasaría con las clases declaradas de manera interna dentro de otra clase, son Beans definidos dentro del rango de bean. El siguiente aspirante al puesto de trabajo es también cocinero, pero su receta de la paella valencia la guarda celosamente, no quiere compartirla con el resto. <bean id="alfredo" class="es.uah.uahconnection.cafe.model.Kitchener"> <property name="diners" value="5"/> <property name="recipe"> <bean class="es.uah.uahconnection.cafe.model.PaellaValenciana"/> </property> </bean> Si la clase cocinero pudiera configurarse por constructor también se podría crear un bean interno de la siguiente manera: <bean id="alfredo" class="es.uah.uahconnection.cafe.model.Kitchener"> <constructor-arg value="5"/> <constructor-arg> <bean class="es.uah.uahconnection.cafe.model.PaellaValenciana"/> </constructor-arg> </bean> Conectar tipos múltiples Hemos visto como en Spring se inyectan dependencias mediante los operadores value y ref. Sin embargo se pueden inyectar tipos múltiples como List (cuando sea una lista), Set (una lista sin duplicados), Map (clave y valor de cualquier tipo) o Properties (clave y valor de tipo cadena). Saber cocinar un plato está bien, pero lo útil sería poder acumular un gran número de recetas para poder ser un buen Chef. La clase Chef refleja esto. public class Chef implements Worker { private Collection<Recipe> recipes;//también un Array o una lista private int diners;//comensales public Chef() { } public void setRecipe(Recipe recipe) { } public void setDiners(int diners) { this.diners = diners; } public void work() throws WorkingException { for (Recipe recipe : recipes) { System.out.println("Se dispone a cocinar " + recipe.getName()); recipe.develop(); } System.out.println("Todo ello para " + diners + " comensales"); } } Raimundo es un buen Chef, ha estudiado varias recetas. Veamos su definición. <bean id="raimundo" class="es.uah.uahconnection.cafe.model.Chef"> <property name="recipes"> <list> <ref bean="paellaValencianaArguiñano"/> <ref bean="tortillaDePatatas"/> <ref bean="pizzaItaliana"/> </list> </property> <property name="diners" value="50"/> </bean> La clase de la propiedad recipes podría ser también una lista o incluso un array al igual que a la hora de definirlo podríamos haberlo hecho con la etiqueta <set> en vez de <list>, esto aseguraría que no hubiese repetidos. El trato con la gente es algo muy valorado, ya que todo cliente estará más contento si alguien le atiende de una manera amable. Borja Mari es un poco pedante, pero cae bien. Mientras sirve cafés suele amenizar con frases amables. Borja Mari pertenece a la clase camarero amable cuyo código es el siguiente: public class KindWaiter extends Waiter { private Properties kindSpeach; public void setKindSpeach(Properties kindSpeach) { this.kindSpeach = kindSpeach; } @Override public void work() throws WorkingException { super.work(); System.out.println("Mientras da una buena conversación a sus clientes: "); for (Iterator it = kindSpeach.keySet().iterator(); it.hasNext();) { String speachType = (String) it.next(); System.out.println(" - para " + speachType + " dice \"" + kindSpeach.getProperty(speachType) + "\""); } } } Para poder definirlo en el contenedor de Spring incluiremos el siguiente código en el fichero xml. <bean id="borjaMari" class="es.uah.uahconnection.cafe.model.KindWaiter"> <property name="kindSpeach"> <props> <prop key="buenosDias">Buenos días, que bonita mañana hace hoy</prop> <prop key="buenasTardes">Buenas y maravillosas tardes</prop> <prop key="servir">Aquí está su café</prop> <prop key="cuenta">Le traigo su cuenta enseguida</prop> <prop key="despedirse">Muchas gracias y vuelva otra vez</prop> </props> </property> </bean> Hasta ahora todos nuestros aspirantes al puesto vacante para la cafetería de la universidad han sido muy buenos, pero también se valoran dotes de liderazgo. El señor Antunez es un buen coordinador y no sólo trabaja sino que sabe organizar a los demás. Para la definición de la clase coordinador utilizaremos un mapa en el cual queden reflejados los nombres de los trabajadores para que el señor Antunez pueda referirse por su nombre (la clave de la clase Map) y el propio trabajador. La clase Jefe refleja lo comentado: public class Boos implements Worker { private Map<String, Worker> employees; public void work() throws WorkingException { for (String name : employees.keySet()) { System.out.println("Organiza el trabajo para " + name); Worker worker = employees.get(name); worker.work(); } } public void setEmployees(Map<String, Worker> employees) { this.employees = employees; } } Su definición en el fichero xml sería la siguiente <bean id="antunez" class="es.uah.uahconnection.cafe.model.Boos"> <property name="employees"> <map> <entry key="Alberto" value-ref="alberto"/> <entry key="Alfredo" value-ref="alfredo"/> <entry key="Ernesto" value-ref="ernesto"/> <entry key="Joselito" value-ref="joselito"/> <entry key="Pepe" value-ref="pepe"/> <entry key="Raimundo" value-ref="raimundo"/> <entry key="BorjaMari" value-ref="borjaMari"/> </map> </property> </bean> Tipos de conexión de beans Existen dos vías para conectar dependencias de beans, la manual y la automática. La manual es la que hemos ido viendo en los ejemplos que hemos hecho hasta ahora ya sea vía constructor o vía setter. La principal razón por la que existe la auto conexión es la reducción de código xml haciéndolo más simple y más vistoso. Para ello tenemos cuatro tipos distintos de auto conexión, por nombre, por tipo, por constructor y otra última que combina el constructor y el tipo. Si tenemos definido un bean cuyo id en el contenedor tenga el mismo nombre que una propiedad del bean que estamos definiendo podemos usar la auto conexión por nombre (byName). La auto conexión por tipo nos será útil cuando haya un único bean del mismo tipo que la propiedad a conectar, si hubiese más se lanzaría una excepción y si no hubiese la propiedad tendría null. También se le puede indicar al bean que intente auto conectarse por constructor intentando que Spring haga corresponder los beans del contenedor con los constructores. Si hubiese ambigüedades se lanzaría una excepción. Por último existe la auto conexión con auto detección, esto sería una mezcla de la auto conexión por tipo y por constructor. Hay que comentar que también se puede conectar tipos null, gracias a la etiqueta <null/>, esto es útil aquí en la auto conexión, ya que es posible que no queramos que determinadas propiedades se conecten. La autoconexión y la conexión especificada pueden perfectamente convivir. También hay que decir que hay otro debate si es útil la auto-conexión o no. Auto-conexión byName Si el nombre que le damos a un bean coincide con el nombre de la propiedad, éste se autoconectará con la propiedad si lleva el campo autowire=”byName”. Como ejemplo podríamos cambiar la definición de estudiante y carrera del ejemplo de la Inyección de dependencia: <bean id="itig" class="es.uah.uahdi.model.CarrerImp"> <property name="universityName" value="Universidad de Alcalá de Henares"/> <property name="name" value="Ingeniería Técnica en Informática de Gestión"/> </bean> <bean id="juanito" class="es.uah.uahdi.model.StudentImp"> <property name="name" value="Juan Aurelio Gonzalez"/> <property name="carrer" ref="itig"/> </bean> Por el siguiente código: <bean id="carrer" class="es.uah.uahdi.model.CarrerImp"> <property name="universityName" value="Universidad de Alcalá de Henares"/> <property name="name" value="Ingeniería Técnica en Informática de Gestión"/> </bean> <bean id="juanito" class="es.uah.uahdi.model.StudentImp" autowire="byName"> <property name="name" value="Juan Aurelio Gonzalez"/> </bean> Cuando asignamos la auto-conexión por nombre estamos diciéndole a Spring que busque en el contenedor beans no los mismo nombres que las propiedades. Las propiedades que definamos de la manera convencional no se auto-conectarán. El ejemplo sólo podríamos auto-conectar la misma carrera, si quisiésemos inyectar más beans de distinto tipo en otros lo tendríamos que hacer sin auto-conexión. Auto-conexión byType La auto-conexión por tipo es similar a por nombre. Su funcionamiento es que Spring busca beans del mismo tipo de la propiedad y las inyecta. En el caso de que Spring encuentre varias se lanzará una excepción de tipo UnsatisfiedDepedencyException. Si en el ejemplo anterior sólo podíamos auto-conectar aquellas propiedades cuyo nombre fuese el mismo que el del bean y si queríamos conectar otras de distinto nombre tenía que ser con el método normal, con la auto-conexión por tipo no podremos conectar ningún otro bean del mismo tipo. Es decir, la propiedad que tenga autowire=”byType” obliga a que no haya más beans de la misma clase en el contenedor. <bean id=”exampleBean” class=”example.ExampleClass” autowire=”byType”/> Auto-conexión constructor La auto-conexión por constructor tiene las mismas limitaciones que la auto-conexión por tipo pero sólo para las propiedades del constructor, Spring no intentará adivinar que bean autoconectar si hay más de uno del mismo tipo. <bean id=”exampleBean” class=”example.ExampleClass” autowire=”constructor”/> Auto-conexión autodetect La conexión por auto-detección hace que Spring primero intente conectar mediante constructor y luego mediante tipo. <bean id=”exampleBean” class=”example.ExampleClass” autowire=”autodetect”/> La auto-conexión default Si en el tag de beans configuramos el campo default-autowire los beans que definamos en su cuerpo se autoconectarán de esa forma. También se puede incluir explícitamente en el tag del bean el valor default. <beans default-autowire=”byType”> … </beans> Si se especifica en el propio bean algo distinto se hará de esa manera. La Auto-conexión no Si se especifica en la propiedad del bean autowire=”no” no se hará autoconexión, incluso si en el tag beans indiquemos lo contrario en el campo default-autowire, no se hará. Configuración de la creación de los beans A Spring se le pueden dar distintas directrices para alterar la simple creación del bean como hasta ahora hemos hecho en los ejemplos. Las opciones serían las siguientes: Inicializar un bean una vez ya creado y ejecutar código antes de su destrucción. Crear beans desde métodos estáticos de fábrica en vez de constructores públicos. Controlar el número de instancias de un bean. Una instancia por sesión, por petición, por cada uso o por aplicación. Delimitación de un bean Si no se especifica nada, Spring instancia cada bean de forma única, por cada petición siempre se entrega el mismo bean. Con el campo prototype del tag bean podemos alterar este comportamiento. Las delimitaciones de bean de Spring permiten declarar el límite bajo en el que se crean los beans sin tener que codificar las reglas de limitación en la clase del bean. Al igual que pasaba con bean, el término Singleton en Spring no es sinónimo del aplicado tradicionalmente en java. Como veremos, a diferencia de éste, en Spring no son otorgados por la obligatoriedad de la clase en sí, sino que Spring otorga este diseño de manera ajena a la propia clase. Típo de límite Singleton Prototype Request Session Global-session Limita a una única instancia por contenedor. Es la opción predeterminada. Permite que un bean sea instanciado cualquier número de veces (se instanciará cada vez que se use). En Spring MVC es usado para que el bean se instanciado una vez por petición HTTP (request). Al igual que request es usado en entorno web y la instancia del bean durará lo mismo que dure la sesión en el servidor. Limita el bean a una sesión global en el servidor en entornos web. Dependiendo de las necesidades del sistema de información, unas veces será útil dejar la configuración por defecto, es decir, la instanciación singleton y otras veces será útil tener varias instancias con prototype. Con respecto al servidor web, más tarde veremos todas las utilidades que podemos encontrar para la construcción de distintos beans. Creación de beans con clases singleton Esto es útil si se están usando clases de terceras partes cuyos métodos públicos sean estáticos. Es decir, para la inclusión de clases tipo singleton dentro del contenedor de Spring. En Spring, como ya hemos dicho, por defecto se crea una instancia de cada bean, pero no tiene por qué ser de cada clase. Continuando con el anterior ejemplo, cambiemos la definición de la cafetería de la universidad, ya que siempre va a ser la misma. package es.uah.uahconnection.cafe.model; public class Restaurant implements Local { public void clean() { System.out.println("El restaurante ha sido limpiado"); } private static class RestaurantSingletonHolder { static Restaurant instance = new Restaurant(); } public static Restaurant getInstance() { return RestaurantSingletonHolder.instance; } } En el anterior ejemplo hemos definido una clase estática interna cuya función es devolver una instancia de la clase restaurante, cumpliendo el patrón de diseño tradicional de singleton. Para instanciar correctamente este bean en Spring le deberemos especificar en su definición el campo factory-method el método de instanciación. El código xml sería el siguiente. <bean id="cafeteriaPolitecnica" class="es.uah.uahconnection.cafe.model.Restaurant" factory-method="getInstance"/> Uso de init-method y de destroy-method (inicializar y destruir) Es posible que queramos ejecutar cierto código de inicialización o de destrucción al instanciar un bean, ya sea para ponerlo en un estado en particular o para eliminar o limpiar ciertas vicisitudes. Para ello (y para todo aquello que se nos pueda ocurrir), tenemos la posibilidad de configurar dos campos en la declaración. Éstos son init-method y destroy-method. El primero ejecutará el código del método al inicio y el segundo al final. Un ejemplo del código xml sería el siguiente: <bean id="exampleBean" class="exampleClass" init-method="initExample" destroy-method="cleanUpExample"/> También si tenemos varios beans a los cuales tenemos que inicializar y todos ellos tienen el mismo nombre de método (usualmente init y clean) podríamos definirlo por defecto en el tag de beans como muestra el código de ejemplo. <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd" default-init-method="init" default-destroy-method="clean"> Continuando con el ejemplo de la cafetería, algo muy importante para todo cocinero es limpiarse las manos antes de cocinar y vestirse adecuadamente con el delantal. Cuando éste acabe con su jornada laboral deberá quitarse el delantal. Así que, como queremos cocineros limpios en la universidad modifiquemos el código del cocinero. public class Kitchener implements Worker { private Recipe recipe;//receta private int diners;//comensales public Kitchener() { } public void setRecipe(Recipe recipe) { this.recipe = recipe; } public void setDiners(int diners) { this.diners = diners; } public void work() throws WorkingException { System.out.println("Se dispone a cocinar " + recipe.getName()); recipe.develop(); System.out.println("Para " + diners + " comensales"); } public void init(){ System.out.println("El cocinero se pone el delantal"); System.out.println("El cocinero se lava las manos"); } public void clean(){ System.out.println("El cocinero se quita el delantal"); } } Ahora la definición de cocinero sería tan simple como esta: <bean id="alfredo" class="es.uah.uahconnection.cafe.model.Kitchener" init-method="init" destroy-method="clean"> <property name="diners" value="5"/> <property name="recipe"> <bean class="es.uah.uahconnection.cafe.model.PaellaValenciana"/> </property> </bean> Como no sólo el cocinero manipula alimentos creemos que todos los chef deberían antes de comenzar su jornada laboral limpiarse y ponerse vestimenta adecuada así como de la misma forma, cuando terminen su jornada laboral cambiarse de ropa, con lo que todos los chef implementarán el método init y también el método destroy. Spring tiene una forma más útil de poder definir un método por defecto de inicio así como otro de destrucción como ya hemos visto. El código perteneciente a esto sería: <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd" default-init-method="init" default-destroy-method="clean"> Aún sigue teniendo Spring una forma más de hacer todo esto. Si la clase que definimos implementa el interfaz InitializingBean y el DisposableBean. Utilizará los métodos afterPropertiesSet y destroy, como ya comentamos al inicio de éste capítulo. Vemos como sería el código del cocinero si implementase esto: public class Kitchener implements Worker, InitializingBean, DisposableBean { private Recipe recipe;//receta private int diners;//comensales public Kitchener() { } public void setRecipe(Recipe recipe) { this.recipe = recipe; } public void setDiners(int diners) { this.diners = diners; } public void work() throws WorkingException { System.out.println("Se dispone a cocinar " + recipe.getName()); recipe.develop(); System.out.println("Para " + diners + " comensales"); } public void init(){ System.out.println("El cocinero se pone el delantal"); System.out.println("El cocinero se lava las manos"); } public void clean(){ System.out.println("El cocinero se quita el delantal"); } public void afterPropertiesSet() throws Exception { init(); } public void destroy() throws Exception { clean(); } } Como seguramente se haya percatado, esta opción liga el desarrollo de las clases de nuestro sistema de información al framework de Spring, haciéndolas menos reutilizables. Es por ello que aún que la opción esté y haga que nuestro xml de configuración sea más limpio esta opción se descarte en muchas ocasiones.