Recorriendo Spring
- Spring: Introducción + Inyección de dependencias
- Spring: AOP Programación Orientada a Aspectos
- Spring: AOP con Aspect mediante archivos xml y Anotation.
- Spring: Mejorando JDBC
- Spring Transaction
- Spring: Mejorando el Trabajo con Hibernate ORM
- Spring MVC una recorrida contando lo bueno y lo malo (En contruccion)
- Spring Security, pensando en seguridad (En contruccion)
- Spring: Remoting gestionando conexiones
- Spring: Spring-WS con JAXB + Hibernate + DAO
- Spring: JMS
- Spring: Automatizando pruebas con JUNIT STUBS Mock (En contruccion)
Es un framework que tiene mucha vida en el mundo JAVA desde hace mucho tiempo, nació en primera instancia como un JAR que proporcionaba soluciones mágicas a programadores en años cuando compilar y trabajar en java requería de mucho tiempo y paciencia por lo limitado del hardware con el que se trabajaba.
Mas Historia,.... un loco durante algunos años escribió sobre como seria programar de una manera mas facil en J2EE, mediante el desacoplamiento ,la reutilizacion de codigo y por supuesto un codigo mucho mas limpio. Este muchacho se llama Rod Johnson quien lógicamente ante esta serie de análisis construyo spring para hacer la vida de todos mas facil.
Nacio con el nombre de interface en correspondencia a su empresa propietaria interface 21, evoluciono mucho con el tiempo hasta convertirse en spring source y la búsqueda de inversores en años venideros convirtió a sus creadores en millonarios por la compra de un gigante de la virtualizacion como vmware.
Cual es el secreto de su exito ?
la comunidad de programadores que hoy impulsan la utilización de este framework en el mundo java y por supuesto las virtudes de este framework que puede ser utilizado en todo tipo de desarrollos, aqui es donde va la aclaración si bien spring cuenta con funcionalidades fuertes muy dedicadas al desarrollo web, su core puede ser utilizado en aplicacion swing sin problema, es mas en la actualidad es utilizado en desarrollo mobile sin problema.
Por que elegir spring ?
Por un lado la capacidad de poder realizar un desarrollo por completo, dado que simplemente hoy proporciona soluciones funcionales para toda necesidad que se pueda tener en nuestro desarrollo.
Flexible: si quiero pongo lo que quiera de spring y tengo la posibilidad integración con otros framework muy populares sin problema. Si quiero utilizo spring en su todo, o si quiero solo el core o alguno de sus subproyecto potentes. Es decir la herramienta no nos obliga a utilizarlo en su magnitud sino que podemos utilizar lo que nos guste. Si utilizo su soporte a base de datos, no estoy obligado a utilizar su MVC y viceversa.
Altamente Cohesivo : Se dedica a lo que tiene que hacer de manera dedicada, es decir los subproyectos como JDBC es especifico para dicha función, si quiero sobre webservice o MVC también lo son. Es atómico en sus funciones, convirtiéndolo en reutilizable en desarrollo en cualquier fase. Con esto puedo insertar spring en nuevos desarrollos o en mantenimientos que requieran de nuevos desarrollo sin problema.
Débilmente acoplado: no me fuerza a utilizar el framework, sino que puedo utilizar sus proyectos como lo necesite.
Lo primero que hay que dejar claro es que no es un framework de desarrollo web. Efectivamente, tiene módulos para desarrollo web como Spring MVC y Spring Web Flow que están entre los mejores, pero, por encima de eso, Spring es un framework para el desarrollo de aplicaciones empresariales Java, sean web o no. La idea es que Spring se encargue de las labores de infraestructura para que los desarrolladores se centren en resolver los problemas del dominio.
Entre algunas de sus virtudes nos proporciona:
- Soporte Core:
- Configuración de aplicaciones: normalmente una aplicación empresarial está compuesta por diferentes módulos que interaccionan entre sí. Spring nos da herramientas para conectar estos módulos y poder intercambiarlos de forma sencilla. En Spring, las partes que componen una aplicación son simples POJOs y veremos como siempre se nos recomienda trabajar con interfaces cuando sea posible, para facilitar el reemplazo de módulos.
- Integración empresarial: las aplicaciones empresariales requieren recursos y servicios como seguridad, transaccionalidad, mensajería, acceso remoto, caché, etc… Spring nos ayuda a integrar todo esto de forma que impacte lo menos posible en el código, manteniéndolo lo más limpio posible. También hace más sencillo el desarrollo de Web Services o el trabajo con tareas programadas.
- Testing: soporte para test unitarios y test de integración.
- Acceso a datos: simplifica la capa de acceso a base de datos y proporciona integración con las principales tecnologías como JDBC, Hibernate, JPA, Ibatis…
- Soporte Web: se integra de forma muy sencilla con frameworks de desarrollo web como JSF o Struts y, además, nos proporciona los suyos propios: Spring MVC y Spring Web Flow.
Spring basa toda su filosofía en esos tres principios
La idea es componer nuestra aplicación a base de objetos simples o POJOs. Normalmente éstos objetos no dependen mucho de la tecnología que utilicemos y eso es una buena práctica porque:
- El código se centra en resolver lógica de negocio y no en integración. Esto permite que si cambiamos de tecnologías nuestra lógica no se vea afectada. Por ejemplo, si tenemos un módulo que hace uso de JDBC para acceder a los datos y mañana queremos cambiar a Hibernate, el impacto sobre nuestros POJOs debería ser mínimo.
- Los programadores son más productivos, ya que invierten su tiempo en resolver los problemas del dominio y no en pegarse con diferentes tecnologías.
- Es más sencillo realizar pruebas sobre estos objetos (tanto unitarias como de integración).
Para mantener nuestro objetos lo más simples posibles, Spring se apoya en los tres principios que hemos visto:
- Inyección de Dependencias (o Inversión de Control): un objeto no se encarga de instanciar a sus colaboradores si no que éstos son inyectados por el framework. El famoso principio de Hollywood, "no me llames, nosotros te llamaremos" , es decir la posibilidad de una bolsa de objetos definida mediante diccionario xml de spring, para la utilización en toda nuestra aplicación, mediante la utilización de interfaces. Si solo se conoce las dependencias vía interfaz, al cambiar la implementación de la dependencia el objeto dependiente no se entera que se hizo. De esta forma, el objeto no depende de la tecnología con la que estén implementados y además es más fácil sustituirlos por tests.
- Programación Orientada a Aspectos: llamamos aspectos a funcionalidades que son transversales a las aplicaciones (por ejemplo la seguridad o la transaccionalidad). Al trabajar con AOP estamos centralizando el código que implementa estas funcionalidades y configurando Spring para que las ejecute donde queramos, en lugar de tener que hacerlo en cada método que haga uso de ellas.
- Abstracción de Servicios de Empresa: Spring se encarga de hacer transparente muchas tareas que hay que realizar al trabajar con servicios utilizados habitualmente en aplicaciones empresariales y que suelen resultar muy repetitivas. Por ejemplo al acceder a bases de datos mediante JDBC, él se encargará de gestionar las conexiones, unificar excepciones, etc…
Ahora con todo esto es mucho mas facil entender para que me sirve spring, y la respuesta seria simple para todo por su fortaleza, por un lado tendría:
- Por medio de la abstracción lograría tener resuelto las tareas comunes como la conexión para la base de datos para mi backend, gestión de excepciones del mismo, la seguridad.
- Por medio de la programación orientada a aspecto tendría trazabilidad y código limpio en la ejecución de triguer sobre acciones que se realicen en mi negocio.
- Con la inyección de dependencias obtendría un modelo basado en contratos sin importar las implementacion obteniendo un desacoplamiento absoluto y un core alta mente escalable.
ahora todo es lindo bonito y barato por el momento pero la realidad es que este modelo se encuentra apoyado en el corazón spring por medio de su contenedor beans o contenedor de inyección de dependencias.
Para construir nuestra aplicación, Spring necesita dos cosas:
- Las clases de la aplicación (POJOs, en adelante los llamaremos beans)
- Una configuración que podremos proporcionarle mediante ficheros XML, anotaciones o código Java
Con estas dos entradas, Spring levantará un contexto de aplicación(ApplicationContext). Este contexto es un interfaz cuya implementación se encargará de instanciar de nuestros beans, configurarlos y conectarlos:
Entendiendo un poco mas de spring.
Tengamos claro que trabaja con Beans y su contenedor.
¿Qué es un bean?
La wikipedia define bean como un componente de software que tiene la particularidad de ser reutilizable.
En java cumplen varios criterios:
- Implementación en serie.
- Tener todos sus atributos privados (private).
- Tener métodos set() y get() públicos de los atributos privados que nos interese.
- Tener un constructor público por defecto
Que es el contenedor de beans de Spring ?
El contenedor se encuentra en el núcleo del marco de trabajo de Spring y utiliza inyección de dependencias para gestionar los componentes que forman la aplicación. Se encarga de varias tareas, como crear, conectar y alojar los objetos definidos por los beans. Además hace de dispensador proporcionando beans por peticion. El contenedor carga las definiciones de beans escritas en archivos XML estructurados de forma ordenada.
Tipos de contenedor de Spring:
- Fabrica de beans (bean factory): contenedor sencillo con soporte básico de inyeccion de dependencias.
- Contexto de aplicacion (aplication context): es una implementacion de la bean factory que proporciona opciones avanzadas como por ejemplo: medios para resolver mensajes de texto e internalizacion, publicación de beans registrados como receptores o formas genéricas de abrir recursos de archivo.
Curso de vida de la bean en Spring
Otra diferencia de los beans de Spring es que a éstos se añade un ciclo nuevo para que la bean sepa cual es su contexto de aplicación. Podemos ordenar las fases de la vida de un bean de la siguiente forma:
- Instanciación
- Inyección de las propiedades
- Nombre del bean
- Nombre de la fábrica
- Postprocesado (pre inicializacion)
- Inicialización
- Postprocesado (post inicialización)
- Bean listo para uso
- Destrucción
Durante la inicialización existen dos pasos bien diferenciados:
- Carga de definiciones de beans: se parsean los ficheros XML, se carga su definición en el BeanFactory del contexto de aplicación (indexados por el id que les hayamos dado) y por último se invocan losBeanFactoryPostProcessor. Éstos pueden modificar la definición de los beans tras haber sido cargada pero antes de que se instancien. Reasultan útiles en muchas situaciones, uno de los más utilizados es elPropertyPlaceholderConfigurer que sustituye variables en los ficheros de configuración por valores de ficheros .properties. Para crear los nuestros propios basta con implementar el interfaz BeanFactoryPostProcessor. No hay que confundirlos con los BeanPostProcessor, veremos estos a continuación.
- Creación e inicialización de beans: por defecto, para cada bean definido y en el orden adecuado, Spring crea una instancia de éste e inyecta sus dependencias (por constructor y por setters). Tras esto, cada bean pasa por una serie de BeanPostProcessor donde puede realizarse configuración adicional. Después de pasar por los BeanPostProcessor, el bean estará preparado para su uso. Existen dos tipos de BeanPostProcessor:
- Inicializadores: realizan inicialización adicional a la inyección de dependencias. A partir de Spring 2.5, la forma común de definirlos es utilizando la notación @PostConstruct. Podemos anotar tantos métodos como queramos dentro de un mismo bean pero no se garantiza en orden en el que serán ejecutados.
- El resto: configuración adicional a la inicialización, pueden ejecutarse antes o después de ésta. Un ejemplo común es la anotación @Required que indica que una inyección de dependencia es obligatoria.
Es posible implementar el interfaz BeanPostProcessor para crear los nuestros propios, sin embargo no es algo muy común (aunque resulta una opción muy potente).
Con esto termina la fase de inicialización y ya tenemos los beans preparados para su utilizarlos.
Formas de crear un bean en SpringBean simples: sin atributos
Bean con inyección por constructor: pasando los atributos por constructor
Bean con referencias de objeto de constructores: cuando pasamos un bean como atributo del constructor de otro.
Bean con inyección de propiedades: cuando en vez del método constructor utilizamos setters de atributos.
- Con valores simples: Enteros, reales, Cadenas…
- Con valores complejos:
- Por referencia de otro objeto: pasando un bean id al método set.
- Colecciones de datos: listas, arrays, maps…
- Con valor nulo: cuando necesitamos pasar un valor nulo.
Ahora esto parece simple pero como trasladarlo a la practica ? para esto realizaremos un ejemplo practico con acceso a datos que permite una visión mas real de los beneficios de la inyección.
Entendiendo Spring en la Practica.
Problemática: En el Hospital del Conocimiento se requiere listar todos los pacientes de una habitación.
La arquitectura que usaremos sera una arquitectura tradicional basada en capas apoyada en la utilizacion de contratos o interfaces:
Para obtención de conocimiento, mirar un poco aqui.
Para nuestro ejemplo utilizaremos HSQL que es una base de dato embebida muy utilizada en tiempos de desarrollo por desarrolladores java, si quiere jugar un poco mira aqui que de seguro encontraras mucha información.
En primera instancia vamos crear un proyecto Maven para los que por supuesto lo podremos realizar con:
Dado que el caso de estudio es dar una mirada a la inyección de dependencias en esta ocasión con un proyecto de consola nos va alcanzar.
Paso 1 : Crear nuestro proyecto.
Paso 2: Definir nuestras dependencias y trabajar con nuestro pom.
Nota: como puede verse realizamos una modificación para que la versión del jar la tome del archivo de propiedades que previamente cargamos.
finalmente nuestro archivo pom.xml queda asi
La arquitectura que usaremos sera una arquitectura tradicional basada en capas apoyada en la utilizacion de contratos o interfaces:
- Services Layer: Expondrá mi negocio a un front-End
- Data Acces Layer: Donde accederemos a la Base de datos.
Dado que el caso de estudio no es como trabajar con base de datos, utilizaremos el soporte de spring para trabajar con base de datos embebidas con JDBC.
Para obtención de conocimiento, mirar un poco aqui.
Para nuestro ejemplo utilizaremos HSQL que es una base de dato embebida muy utilizada en tiempos de desarrollo por desarrolladores java, si quiere jugar un poco mira aqui que de seguro encontraras mucha información.
En primera instancia vamos crear un proyecto Maven para los que por supuesto lo podremos realizar con:
- Maven por linea de comando (en el blog podremos encontrar algunas entradas a este tema).
- Con M2ECLIPSE que tiene que estar instalado en nuestro eclipse
- SPRING TOOLS SUITE que es la herramienta que biene con todo instalado para trabajar con spring y por supuesto entre algunas cosas M2ECLIPSE.
Dado que el caso de estudio es dar una mirada a la inyección de dependencias en esta ocasión con un proyecto de consola nos va alcanzar.
Paso 1 : Crear nuestro proyecto.
Paso 2: Definir nuestras dependencias y trabajar con nuestro pom.
Primero definimos las propiedades de nuestro archivo para indicar versión de las dependencias.
Luego cargamos las dependencias de nuestro proyecto que en nuestro caso no serán muchas
Core y Beans: librerías necesarias para trabajar con spring. La dependencia beans es necesaria dado que es la que nos brinda la posibilidad de trabajar con el contenedor, core como todos ya sabemos es el corazon de spring.
jdbc: utilizaremos el soporte para trabajar con base de datos embebidas con jdbc,
HSQLDB: dependencia necesaria para trabajar con HSQL.
Nota: como puede verse realizamos una modificación para que la versión del jar la tome del archivo de propiedades que previamente cargamos.
finalmente nuestro archivo pom.xml queda asi
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.hostipal</groupId> <artifactId>hospital_01</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <org.springframework.version>3.0.7.RELEASE</org.springframework.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.hsqldb</groupId> <artifactId>hsqldb</artifactId> <version>2.0.0</version> </dependency> </dependencies> </project>
Paso 3: Trabajar en la estructura de nuestro proyecto acorde a la arquitectura propuesta.
Pero comencemos por las entidades o bien por los famosos POJOS
com.hospital.Patient.java: a nivel código no encontramos nada raro en esta clase solo la definición de la estructura de datos de un paciente y sus correspondientes gett y sett.
package com.hospital.modelo; public class Patient { private Integer id; private String name; private String lastName; private Integer roomId; public Patient(String name, String lastName) { this.name = name; this.lastName = lastName; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public Integer getRoomId() { return roomId; } public void setRoomId(Integer roomId) { this.roomId = roomId; } }
com.hospital.Room.java: para esta clase una habitación tiene un identificador y solo un campo para la cantidad maxima de pacientes y sus gett y sett correspondientes.
package com.hospital.modelo; public class Room { private Integer id; private Integer maxPatients; public Room(Integer maxPatients) { this.maxPatients = maxPatients; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public Integer getMaxPatients() { return maxPatients; } public void setMaxPatients(Integer maxPatients) { this.maxPatients = maxPatients; } }Entendiendo Data Acces Objetc Layer.
com.hospital.dao.PatientDao.java: es una interfaz que limitara a la clase que lo implemente en sus metodos y en este caso solo tiene un método definido que recibe un numero de habitación y retorna una lista de pacientes.
package com.hospital.dao; import java.util.List; import com.hospital.modelo.Patient; public interface PatientDao { ListfindByRoom(Integer roomId); }
com.hospital.dao.PatientDaojdbc.java: es la implementacion del contrato que antes describimos y que por supuesto es el como mediante código devolverá la lista de pacientes, en este caso utilizaremos jdbc para implementar una solución pero la realidad es que podria ser hibernate, ebatis o cualquier forma de acceso a base de datos.
a nivel código la clase recibe un datasource por contructor y el metodo lo consume para realizar la operacion de consulta de los pacientes del modelo de datos y los retorna en lista.
import com.hospital.modelo.Patient; public class PatientDaoJdbc implements PatientDao { private DataSource dataSource; public PatientDaoJdbc(DataSource dataSource) { this.dataSource = dataSource; } public ListfindByRoom(Integer roomId) { List patients = new ArrayList (); PreparedStatement query = null; String queryString = "SELECT ID, NAME, LASTNAME FROM T_PATIENT WHERE ROOMID=?"; try { Connection connection = dataSource.getConnection(); query = connection.prepareStatement(queryString); query.setInt(1, roomId); ResultSet rs = query.executeQuery(); while (rs.next()) { Integer id = rs.getInt("ID"); String name = rs.getString("NAME"); String lastName = rs.getString("LASTNAME"); Patient patient = new Patient(name,lastName); patient.setId(id); patient.setRoomId(roomId); patients.add(patient); } } catch (SQLException e) { e.printStackTrace(); } finally { try { if (query != null) { query.close(); } } catch (SQLException e) { e.printStackTrace(); } } return patients; } }
Nota: lo lógico es que alguien externo deberá proporcionarme el datasource que no es otra cosa que la conexión al modelo de datos y aqui es donde comienza la magia de entender una arquitectura acoplada y desacoplada. Por que lamentablemente en una dependencia acoplada de seguro la capa superior me brindara que consumir, lo que me genera grandes problemáticas a la hora de que en un futuro el medio de datos cambie, por que de seguro deberá modificar mi capa de servicio en este escenario.
Pero en una dependencia desacoplada debería tener un orquestador que en este caso es spring que me proporcione dicha información sin afectar a la capa de servicio, lo que hace escalable mi desarrollo y adaptable al cambio del medio de datos sin dolores de cabeza.
Entendiendo Services Layer.
No hay mucho que decir sera quien expondrá la funcionalidad a quien la quiera consumir y en nuestro caso para esta ocacion sera solo una consola, pero podría ser cualquier cosa, una aplicación web , una aplicacion swing.
com.hospital.servicio.PatientServic.java: es nuestro contrato para las clases de implementacion del servicio y que a nivel código tiene un solo metodo que es buscar los pacientes, recibe un código de habitación y retorna una lista de pacientes.
package com.hospital.servicio; import java.util.List; import com.hospital.modelo.Patient; public interface PatientService { public ListfindByRoom(Integer roomId); }
com.hospital.servicio.PatientServiceImpl.java: la clase utiliza la interfaz dao antes comentada para consumir un metodo para buscar los un codigo de habitación y retornar la lista de pacientes, pero hay un tema recibe un dao por contructor, lo que me hace pensar que esa referencia la voy a recibir de algún lado, pero por otro lado nunca esta mandando a la capa dao el datasource para que pueda trabajar, y no veo que el loco instancie nunca ninguna clase, se acabo la mentira este código no funciona y me comi todo el tutorial al pe..!!
package com.hospital.servicio; import java.util.List; import com.hospital.dao.PatientDao; import com.hospital.modelo.Patient; import com.hospital.servicio.PatientService; public class PatientServiceImpl implements PatientService{ private PatientDao patientDao; public PatientServiceImpl(PatientDao patientDao) { this.patientDao = patientDao; } public ListfindByRoom(Integer roomId) { return patientDao.findByRoom(roomId); } }
Nota: Aquí comienza la parte buena del fenómeno inyección de dependencias que de arranque es ni mas ni menos contar con una bolsa de objetos que puedan ser utilizables en toda mi aplicación y que permita comunicación con los componentes que conforman mi aplicación.
por que nadie instancia a nadie ?
por sping
por que nadie le pasa el datasource para que la pobre capa dao pueda trabajar?
por que lo hara spring.
Entendiendo spring bean configuration
Sin esto spring no tiene referencia de los beans de la aplicación, es un archivo xml de configuracion donde definimos los bean para ser consumidos.
vamos a indicarle a Spring cómo ensamblar mediante un fichero XML que llamaremos application-config.xml (normalmente tendremos varios ficheros para las diferentes capas de la aplicación pero de momento utilizaremos sólo uno):
<?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:jdbc="http://www.springframework.org/schema/jdbc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd"> <bean id="patientService" class="com.hospital.servicio.PatientServiceImpl"> <constructor-arg ref="patientDao"/> </bean> <bean id="patientDao" class="com.hospital.dao.PatientDaoJdbc"> <constructor-arg ref="dataSource"/> </bean> <jdbc:embedded-database id="dataSource" type="HSQL"> <jdbc:script location="classpath:schema.sql"/> <jdbc:script location="classpath:test-data.sql"/> </jdbc:embedded-database> </beans>
Entendiendo ApplicationContext
com.hospital.hospital.java: la clase que consumira la capa servicio para obtener la lista de paciente acorde al numero de aplicacion que le indique.
package com.hospital; import java.util.List; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.hospital.modelo.Patient; import com.hospital.servicio.PatientService; public class Hospital { public static void main(String [] args) { ApplicationContext context = new ClassPathXmlApplicationContext("application-config.xml"); PatientService patientService = (PatientService) context.getBean("patientService"); Listpatients = patientService.findByRoom(1); System.out.println("Pacientes en la habitacion 1: "); for(Patient patient : patients) { System.out.println("-->"+patient.getId()+","+patient.getName()+" "+patient.getLastName()); } } }
Nota: Como dijimos antes, ApplicationContext es un interfaz que tiene diferentes implementaciones, para el ejemplo utilizaremosClassPathXmlApplicationContext, que buscará los ficheros de configuración xml en el classpath de la aplicación:
solicita el bean de pacientes
PatientService patientService = (PatientService) context.getBean("patientService");
obtuvo la referencia de la instancia para poder ejecutar los metodos correspondientes
List
finalmente recorre la lista de pacientes que obtuvo.
System.out.println("Pacientes en la habitacion 1: ");
for(Patient patient : patients) {
System.out.println("-->"+patient.getId()+","+patient.getName()+" "+patient.getLastName());
}
Resultado
Entendiendo la inyección de dependencias
¿Qué está ocurriendo en el contexto? Podemos ver que Spring se está encargando de gestionar el ciclo de vida de los objetos que componen nuestra aplicación: los instancia, los inicializa, los inyecta donde hacen falta en el orden correcto y los registra con el id que le indiquemos en el fichero de configuración para que podamos acceder a ellos. Además, el ApplicationContext actúa como un contenedor que encapsula la implementación de éstos.
Por ahora vamos a centrarnos en cómo se definen los beans. Como hemos visto antes, normalmente esta configuración se detalla en un fichero XML dentro de la etiqueta beans, que, además, contendrá una serie de referencias a los espacios de nombres y esquemas que vamos a usar (normalmente esto lo generan los IDE, no es necesario saberlo de memoria).
El bean más sencillo que podemos definir sería algo parecido a esto:
<
bean
id
=
"service"
class
=
"example.ServiceImpl"
/>
Por dentro Spring hará uso de reflexión para traducir esa definición a:
ServiceImpl service =
new
ServiceImpl();
Y, además, registrará en el ApplicationContext esa instancia al identificador “service”
Inyección por contructor
A continuación vamos a inyectar una dependencia a nuestro servicio:
<
bean
id
=
"service"
class
=
"example.ServiceImpl"
>
<
constructor-arg
ref
=
"dao"
/>
</
bean
>
<
bean
id
=
"dao"
class
=
"example.DaoImpl"
/>
Resultado de la reflexión:
DaoImpl dao =
new
DaoImpl();
ServiceImpl service =
new
ServiceImpl(dao);
Inyeccion por Setter
A continuación vamos a inyectar una dependencia a nuestro servicio:
<
bean
id
=
"service"
class
=
"example.ServiceImpl"
>
<
property
name
=
"dao"
ref
=
"dao"
/>
</
bean
>
<
bean
id
=
"dao"
class
=
"example.DaoImpl"
/>
Resultado de la reflexión:
DaoImpl dao =
new
DaoImpl();
ServiceImpl service =
new
ServiceImpl();
service.setDao(dao);
Hasta ahora hemos visto como inyectar otros beans, pero también es posible inyectar valores escalares:
<
bean
id
=
"person"
class
=
"example.Person"
>
<
property
name
=
"name"
value
=
"John"
/>
<
property
name
=
"age"
value
=
"23"
/>
</
bean
>
Resultado de la reflexión:
Person person =
new
Person();
person.setName(
"John"
);
Integer age =
23
;
person.setAge(age);
Existe cierta controversia entre cuál de las dos es más adecuada, en cualquier caso, Spring soporta ambas y se pueden utilizar de forma conjunta. La recomendación general es utilizar inyección por constructor en aquellas propiedades que sean obligatorias y por setter en las que sean opcionales.
Entendiendo finalmente el archivo de configuración de nuestro ejemplo
Es muy recomendable separar los beans de lógica de negocio de los de infraestructura para que no exista acoplamiento. En el ejemplo del hospital, el bean “dataSource” es un candidato idóneo para ser definido en otro fichero al que podríamos llamar “test-infrastructure-config.xml” pero con los fines de educacion lo puse en un solo archivo de configuracion.
como podrán ver definimos un bean para el datasource que es el que me proporciona acceso a la base de datos embebida.
<jdbc:embedded-database id="dataSource" type="HSQL"> <jdbc:script location="classpath:schema.sql"/> <jdbc:script location="classpath:test-data.sql"/> </jdbc:embedded-database>
luego definimos el bean patientDao que hace referencia a la implementacion dao que utiliza jdbc para pegarle a la base HSQL a quien le inyectamos el datasource, con lo que logramos desacoplar el tema del datasource que ya comentamos que alguien debía proporcionarlo y no esta definido en la capa de servicio.
<bean id="patientDao" class="com.hospital.dao.PatientDaoJdbc"> <constructor-arg ref="dataSource"/> </bean>
Para finalizar definimos el bean para la implementacion del servicio a quien le inyectamos nuestro bean dao logrando la conectividad entre las capas de nuestra aplicacion.
<bean id="patientService" class="com.hospital.servicio.PatientServiceImpl"> <constructor-arg ref="patientDao"/> </bean>
Para finalizar pongo a disposición el código fuente del ejemplo, recuerden por favor que para levantarlo desde su entorno deben importar como proyecto maven.
Proyecto Ejemplo
Proyecto Ejemplo
luego definimos el bean patientDao que hace referencia a la implementacion dao que utiliza jdbc para pegarle a la base HSQL a quien le inyectamos el datasource, con lo que logramos desacoplar el tema del datasource que ya comentamos que alguien debía proporcionarlo y no esta definido en la capa de servicio.
ResponderEliminarhttps://coaching-mastery.com/ciencia/