Ejemplo de Tutorial de Inyección de Dependencias con Google Guice

Google Guice es el marco para automatizar la inyección de dependencias en aplicaciones. Si has llegado directamente aquí, te recomendaría que revises Ejemplo de Inyección de Dependencias donde aprendimos sobre los problemas con el enfoque tradicional de creación de objetos y los beneficios de la implementación de la inyección de dependencias. En el último tutorial, aprendimos cómo podemos implementar manualmente la inyección de dependencias en aplicaciones. Pero cuando el número de clases crece en una aplicación, es mejor buscar algún marco que automatice esta tarea. Google Guice es uno de los marcos líderes cuyo trabajo principal es proporcionar la implementación automática de la inyección de dependencias. Trabajaremos en el mismo ejemplo del último post y aprenderemos cómo podemos usar Google Guice para automatizar el proceso de implementación de la inyección de dependencias. Las dependencias de Google Guice están disponibles en el repositorio central de Maven, así que para proyectos Maven puedes agregar la siguiente dependencia.

<dependency>
	<groupId>com.google.inject</groupId>
	<artifactId>guice</artifactId>
	<version>3.0</version>
</dependency>

Si tienes una aplicación Java simple, puedes descargar el archivo JAR desde la Página de inicio de Google Guice en Google Code. Ten en cuenta que en este caso también necesitarás tener las dependencias transitivas en el classpath o de lo contrario obtendrás una excepción en tiempo de ejecución. En mi ejemplo, tengo un proyecto Maven cuya estructura se ve como en la imagen a continuación. Veamos cada uno de los componentes uno por uno.

Clases de Servicio

package com.journaldev.di.services;

public interface MessageService {

	boolean sendMessage(String msg, String receipient);
}

La interfaz MessageService proporciona el contrato base para los servicios.

package com.journaldev.di.services;

import javax.inject.Singleton;

//import com.google.inject.Singleton;

@Singleton
public class EmailService implements MessageService {

	public boolean sendMessage(String msg, String receipient) {
		//algún código elegante para enviar correos electrónicos
		System.out.println("Email Message sent to "+receipient+" with message="+msg);
		return true;
	}

}

EmailService es una de las implementaciones de MessageService. Observa que la clase está anotada con la anotación @Singleton. Dado que los objetos de servicio se crearán a través de clases de inyector, esta anotación se proporciona para indicarles que las clases de servicio deben ser objetos singleton. Google Guice 3.0 añadió soporte para JSR-330 y podemos usar anotaciones de los paquetes com.google.inject o javax.inject. Supongamos que tenemos otra implementación de servicio para enviar mensajes de Facebook.

package com.journaldev.di.services;

import javax.inject.Singleton;

//import com.google.inject.Singleton;

@Singleton
public class FacebookService implements MessageService {

	public boolean sendMessage(String msg, String receipient) {
		//algún código complejo para enviar mensajes de Facebook
		System.out.println("Message sent to Facebook user "+receipient+" with message="+msg);
		return true;
	}

}

Clase Consumidora

Dado que estamos implementando inyección de dependencias en nuestra aplicación, no inicializaremos la clase de servicio en la aplicación. Google Guice admite tanto la inyección de dependencias basada en setter como en constructor. Nuestra clase de aplicación que consume el servicio se ve así:

package com.journaldev.di.consumer;

import javax.inject.Inject;

//import com.google.inject.Inject;
import com.journaldev.di.services.MessageService;

public class MyApplication {

	private MessageService service;
	
//	constructor based injector
//	@Inject
//	public MyApplication(MessageService svc){
//		this.service=svc;
//	}
	
	//setter method injector
	@Inject
	public void setService(MessageService svc){
		this.service=svc;
	}
	
	public boolean sendMessage(String msg, String rec){
		//some business logic here
		return service.sendMessage(msg, rec);
	}
}

// Observa que he comentado el código para la inyección basada en constructor, esto es útil cuando tu aplicación proporciona otras funciones que no necesitan el objeto de la clase de servicio. También ten en cuenta la anotación @Injector, esto será utilizado por Google Guice para inyectar la clase de implementación del servicio. Si no estás familiarizado con las anotaciones, echa un vistazo al tutorial de anotaciones en Java.

Configuración de la implementación del servicio

// Obviamente, Google Guice no sabrá qué servicio usar, debemos configurarlo extendiendo la clase AbstractModule clase abstracta y proporcionar la implementación para el método configure().

package com.journaldev.di.injector;

import com.google.inject.AbstractModule;
import com.journaldev.di.services.EmailService;
import com.journaldev.di.services.FacebookService;
import com.journaldev.di.services.MessageService;

public class AppInjector extends AbstractModule {

	@Override
	protected void configure() {
		//vincula el servicio a la clase de implementación
		//bind(MessageService.class).to(EmailService.class);
		
		//vincula MessageService a la implementación de mensajes de Facebook
		bind(MessageService.class).to(FacebookService.class);
		
	}

}

Como puedes ver, podemos vincular cualquier implementación a la clase de servicio. Por ejemplo, si queremos cambiar a EmailService solo necesitaríamos cambiar los vínculos.

Aplicación Cliente

Nuestra configuración está lista, veamos cómo usarla con una clase Java simple.

package com.journaldev.di.test;

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

import com.journaldev.di.consumer.MyApplication;
import com.journaldev.di.injector.AppInjector;

public class ClientApplication {

	public static void main(String[] args) {
		Injector injector = Guice.createInjector(new AppInjector());		
		
		MyApplication app = injector.getInstance(MyApplication.class);
		
		app.sendMessage("Hi Pankaj", "[email protected]");
	}

}

La implementación es muy fácil de entender. Necesitamos crear un objeto Injector utilizando el método createInjector() de la clase Guice donde pasamos nuestro objeto de implementación de la clase Injector. Luego usamos el inyector para inicializar nuestra clase consumidora. Si ejecutamos la clase anterior, producirá la siguiente salida.

Message sent to Facebook user [email protected] with message=Hi Pankaj

Si cambiamos los vínculos a EmailService en la clase AppInjector, entonces producirá la siguiente salida.

Email Message sent to [email protected] with message=Hi Pankaj

Casos de Prueba JUnit

Dado que queremos probar la clase MyApplication, no es necesario crear una implementación de servicio real. Podemos tener una clase de implementación de servicio ficticia simple como la siguiente.

package com.journaldev.di.services;

public class MockMessageService implements MessageService{

	public boolean sendMessage(String msg, String receipient) {
		return true;
	}

}

Mi clase de prueba JUnit 4 se ve así.

package com.journaldev.di.test;


import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.journaldev.di.consumer.MyApplication;
import com.journaldev.di.services.MessageService;
import com.journaldev.di.services.MockMessageService;

public class MyApplicationTest {

	private Injector injector;
	
	@Before
	public void setUp() throws Exception {
		injector = Guice.createInjector(new AbstractModule() {
			
			@Override
			protected void configure() {
				bind(MessageService.class).to(MockMessageService.class);
			}
		});
	}

	@After
	public void tearDown() throws Exception {
		injector = null;
	}

	@Test
	public void test() {
		MyApplication appTest = injector.getInstance(MyApplication.class);
		Assert.assertEquals(true, appTest.sendMessage("Hi Pankaj", "[email protected]"));;
	}

}

Ten en cuenta que estoy vinculando la clase MockMessageService a MessageService mediante una implementación de clase anónima de AbstractModule. Esto se hace en el método setUp() que se ejecuta antes de los métodos de prueba.

Descarga el Proyecto Google Guice

Eso es todo para el Tutorial de Ejemplo de Google Guice. El uso de Google Guice para implementar la inyección de dependencias en una aplicación es muy fácil y lo hace de manera excelente. Se utiliza en las API de Google, por lo que podemos suponer que es un código altamente probado y confiable. Descarga el proyecto de arriba y juega con él para aprender más.

Source:
https://www.digitalocean.com/community/tutorials/google-guice-dependency-injection-example-tutorial