Ir al contenido principal

Inyección de dependencias. Spring y Google Guice

¿Qué es la inyección de dependencias?


La inyección de dependencias (DI) procede de un patrón de diseño más general que es el patrón de Inversión de Control (IoC). Básicamente recomienda que las dependencias de una clase no sean creadas desde el propio objeto, sino que sean configuradas desde fuera de la clase.

Una clase A es dependiente de otra B cuando utiliza una instancia de B bien llamando a su constructor o bien obteniendo una instancia de un método estático...



Si utilizamos el patrón de inyección de dependencias la clase B se pasará una instancia de B a A:

  • Por el constructor de la clase A (inyección por constructor o constructor injection)
  • Por un campo de la clase A (inyección por campo o field injection)
  • Por un método setter (inyección por método set  o setter injection)

Al aplicar este patrón hacemos que nuestras clases sean independientes unas de otras e incrementamos la reutilizacion y la extensibilidad de nuestra aplicación, además de facilitar las pruebas unitarias de las mismas. 

Desde el punto de vista de Java, un diseño basado en DI puede implementarse mediante el estandar del lenguaje. Una clase puede leer las dependencias de una clase por medio del API Reflection de Java y crear una instancia de dicha clase inyectándole sus dependencias. 

Veamos un ejemplo de uso del patrón. Imaginemos que una  clase A contiene un método DAO . Si aplicamos el patron DI, la clase A dependerá de una interfaz Java AccessDAO. Podemos implementar un AccessDAOImpl para acceder a una base de datos concreta y otro llamado AccessDaoImplTest que sería un objeto 'mock' para hacer tests unitarios de la clase sin tener que crear una conexión física a la base de datos. Con el patrón DI, podremos insertar uno u otro objeto si cambiar ni una línea de código de la clase A.




Hay frameworks que nos simplifican la aplicación del patron DI como el archiconocido Spring y Google Guice. En los siguientes apartados realizaré dos ejemplos de ambos frameworks.


Inyección de dependencias con Spring

Spring proporciona un contenedor encargado de la inyección de dependencias (Spring Core Container). Este contenedor nos posibilita inyectar unos objetos sobre otros. Para ello, los objetos deberán ser simplemente JavaBeans.  La inyección de dependencias será bien por constructor o bien por métodos setter.

La configuración podrá realizarse bien por anotaciones Java o mediante un fichero XML (XMLBeanFactory). Para la gestión de los objetos tendrá la clase (BeanFactory). Todos los objetos serán creados como singletons sino se especifica lo contrario.

Lo primero que deberemos hacer es descargar de la web de Spring la distribución del framework donde encontraremos los jars necesarios para nuestra pequeño test de IoC y crear y un proyecto en Eclipse que yo he llamado TestSpring.

He utilizado la versión 2.5.4 por estar disponible ya en mi máquina aunque podéis utilizar otra posterior. Con el spring-{VERSION}.jar, descargaremos también las librerías commons-logging.jar y log4j-{VERSION}.jar y creamos un directorio libs dentro del proyecto con las mismas. 


Proyecto en Eclipse finalizado

A continuación crearemos nuestras clases:

LectorDatosClientes.java

package es.jpascu.ioc.services;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service("lectorDatosClientes")
public class LectorDatosClientes {

 private IClienteDao clientesDao;

 @Autowired
 public void setClientesDao(IClienteDao clientesDao) {
  this.clientesDao = clientesDao;
 }

 public void escribirDatosCliente(String id) {
  clientesDao.leerClienteDao(id);
 }
}

Como vemos esta clase no está acoplada a ninguna clase concreta y sí a una interfaz. Es el contenedor de Spring el que posteriormente inyectará una implementación de esta interfaz. Vamos a realizar la configuración mediante anotaciones, aunque también podemos hacerlo mediante XML.

La anotación Service quiere decir que será un bean gestionado por Spring. Está a nivel de clase. La anotación Autowired está a nivel de método set e indica a Spring que debe pasar en el método setClientesDao una instancia de un objeto que implementa dicha interfaz.
A continuación os muestro el código de la interfaz y su implementación.

IClienteDao.java

package es.jpascu.ioc.services;

public interface IClienteDao {

 public void leerClienteDao(String id);
}

ClienteDao.java



package es.jpascu.ioc.services;

import org.springframework.stereotype.Service;

@Service
public class ClienteDaoJdbc implements IClienteDao {

 @Override
 public void leerClienteDao(String id) {
  System.out.println("Datos de cliente: " + id);  
 }
}

En la clase ClienteDAO también se encuentra la anotación Service, ya que Spring lo instanciará y lo inyectará como dependencia en la clase LectorDatosClientes.

Por último, creamos el fichero de configuración applicationContext.xml y lo guardamos en el directorio src/META-INF. 

El contenido de este fichero es el siguiente:

  


Con el elemento context:component-scan le indicamos el paquete donde Spring encontrará los servicios en el código fuente. Por último para probar todo el ejemplo nos creamos una clase de prueba con el siguiente código:

package es.jpascu.ioc.test;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import es.jpascu.ioc.services.LectorDatosClientes;

public class TestSpring {

 public static void main(String args[]) {
  ApplicationContext context = new ClassPathXmlApplicationContext("META-INF/applicationContext.xml");
     BeanFactory factory = context;
     LectorDatosClientes test = (LectorDatosClientes) factory
         .getBean("lectorDatosClientes");
     test.escribirDatosCliente("jpascu");
 }
}


Inyección de dependencias con Google Guice

Google Guice es una librería java de Google que implementa el estandar de inyección de dependencias JSR-330. Al igual que con Spring, podemos utilizarlo para tener clases Java independientes entre sí,  teniendo mediante el patron DI un diseño más extensible, mantenible y fácil de testear. manteniente.

A continuación vamos a implementar el ejemplo del apartado anterior con Google Guice. Las librerías nos las podemos descargar de la web del proyecto.

LectorDatosClientes.java


package es.jpascu.ioc.googleguice.services;

import com.google.inject.Inject;

public class LectorDatosClientes {

 private IClienteDao clientesDao;

 @Inject
 public void setClientesDao(IClienteDao clientesDao) {
  this.clientesDao = clientesDao;
 }

 public void escribirDatosCliente(String id) {
  clientesDao.leerClienteDao(id);
 }
}

En lugar de la anotación Autowired ahora ponemos la anotación Inject. Ya veremos más tarde cómo se realizará el binding a la clase particular.

Las clases  IClienteDao y ClienteDao quedarían con el mismo código que antes pero sin ninguna anotación:

IClienteDao.java


package es.jpascu.ioc.googleguice.services;

public interface IClienteDao {

 public void leerClienteDao(String id);
}

ClienteDaoJdbc.java


package es.jpascu.ioc.googleguice.services;

public class ClienteDaoJdbc implements IClienteDao {

 @Override
 public void leerClienteDao(String id) {
  System.out.println("Datos de cliente: " + id);
 }

}

Ahora desde la clase donde queramos utilizar nuesto LectorDatosClientes deberemos incluir la lógica para crear dicha clase y sus dependencias mediante com.google.inject.Injector. Aquí no se cargará la configuración desde un fichero XML. Un ejemplo vale más que 1000 palabras:

TestGoogleGuice.java


package es.jpascu.ioc.test;

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;

import es.jpascu.ioc.googleguice.services.ClienteDaoJdbc;
import es.jpascu.ioc.googleguice.services.IClienteDao;
import es.jpascu.ioc.googleguice.services.LectorDatosClientes;

public class TestGoogleGuice {
 public static void main(String args[]) {
  Injector injector = Guice.createInjector(new JdbcInjectionModule());
  LectorDatosClientes lectorClientes = injector
    .getInstance(LectorDatosClientes.class);

  lectorClientes.escribirDatosCliente("jpascu");
 }

 public static class JdbcInjectionModule extends AbstractModule {
  @Override
  protected void configure() {
   bind(IClienteDao.class).to(ClienteDaoJdbc.class);
  }

 }
}

Ahora tenemos una clase interna que es una subclase de la clase AbstractModule, encargada  del 'binding' de una interfaz con una implementación concreta. Para ello se debe implementar el método configure.

Una vez que hemos creado nuestro JdbcInjectionModule lo pasaremos como parámetro al objeto de la clase com.google.inject.Guice.Injector. A través de este objeto obtendremos una instancia singleton de nuestro LectorDatosClientes con la dependencia correctamente asociada. Por último sólo nos queda utilizarla...

Hasta aquí el artículo. Espero que os haya ayudado a comprender mejor la inyección de dependencias y daros dos puntos de vista mediante ejemplos con dos frameworks diferentes: Spring y Google Guice.

 Fuente: Vogella1 | Vogella2 | metafisicainformatica

Comentarios

Entradas populares de este blog

Soluciones Alchemy Classic 389 elementos

Hace algún tiempo salió una actualización del Juego Alchemy Classic en la que aparecían más elementos (389 en lugar de 238). Aparte de añadir elementos mejoran algunas traducciones en castellano y mejoran la interfaz, aunque todavía hay algún error en algunos nombres de elementos. Aquí os dejo las soluciones para los que estén atascados y no puedan dormir por las noches: Sustancia primaria Aire=Elemento primario  Fuego=Elemento primario  Agua=Elemento primario  Tierra=Sustancia Primaria Arena=Piedra + Aire Piedra=Tierra + Fuego Arcilla=Arena + Pantano Caliza=Tierra + Amonitas Carbono=Fuego + Madera Cloro=Fuego + Sal + Electricidad CO2(Dióxido de Carbono)=Ceniza + Ácido nítrico Electricidad=Relámpago+ Metales Gas natural= Yacimiento de gas + Pozo Helio=Refinería de gas + Gas Natural Hidrógeno=Electricidad + Agua Hielo=Frío + Agua Imán=Piedra + Metales Metano=Deshechos Vegetales + Pantano Oxígeno=Electricidad + Agua Pe...

Soluciones Alchemy Classic 442 elementos

Después de la resaca navideña y de la cuesta de enero, volvemos para informar la agradable sorpresa que nos ha dado a los fans de Alchemy Classic la empresa NIASOF ,  tras actualizar el juego Alchemy Classic. Una nueva versión con 442 elementos , interfaz mejorada de grupos y lo más importante, nuevos elementos que descubrir. La gran novedad de esta actualización son los puntos que tienes asignados , con los que puedes  conseguir pistas sobre los elementos que no has abierto todavía como: Conseguir un subelemento de un elemento, con 100 puntos . Conseguir el grupo de un subelemento de un elemento (qué lío , jeje), con 35 puntos . Me gusta, me gusta el enfoque de esta nueva versión aunque los elementos que han sacado me parecen poco originales. Parece que se van agotando las ideas para los elementos nuevos. Aquí van las soluciones: Carbon = Tierra + Turba Sol = Estrella + Tierra Espacio = 3 x Estrella Estrella = Helio + Hidrógeno Oso Pa...

Alchemy Classic

Dentro de los juegos que he descargado con el Android Market hay dos que destacan sobre todos los demás. El primero es Angry Birds (pájaros furiosos), en el cual comandas un ejercito de pájaros para luchar con una piara de cerdos malotes los cuales han robado sus huevos. Básicamente, tienes que ir pasando nivel tras nivel afinando tu puntería lanzando los pájaros a los cerdos que se esconden tras maderas, cristales y piedras. Pero la verdadera joya que no es tan conocida es Alchemy Classic . En este juego puedes desempeñar el papel  de Dios. Comenzando con 4 elementos básicos, Aire, Agua, Tierra y Fuego tienes que ir obteniendo todos los demás elementos de la creación (animales, plantas, herramientas...) mediante la combinación de los 4 primeros. En total hay 238 elementos. Después de una semana y alguna noche sin dormir por fin los he obtenido todos. El último elemento me ha llevado más de la cuenta por su maravillosa traducción. ¿Qué son abrojos? ¿Lo sabéis? Pues no, ...