Exemplo de Tutorial de Injeção de Dependência com Google Guice

Google Guice é o framework para automatizar a injeção de dependência em aplicações. Se você chegou diretamente aqui, recomendaria que você confira Exemplo de Injeção de Dependência, onde aprendemos sobre os problemas com a abordagem tradicional de criação de objetos e os benefícios da implementação da injeção de dependência. No último tutorial, aprendemos como podemos implementar a injeção de dependência manualmente em aplicações. Mas quando o número de classes aumenta em uma aplicação, é melhor procurar por um framework para automatizar essa tarefa. O Google Guice é um dos principais frameworks cujo trabalho principal é fornecer a implementação automática da injeção de dependência. Vamos trabalhar no mesmo exemplo do último post e aprender como podemos usar o Google Guice para automatizar o processo de implementação da injeção de dependência. As dependências do Google Guice estão disponíveis no Maven Central, então, para projetos Maven, você pode adicionar a seguinte dependência.

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

Se você tem uma aplicação Java simples, então pode baixar o arquivo JAR na Página Inicial do Google Guice no Google Code. Note que, nesse caso, você também precisará ter as dependências transitivas no classpath, ou então ocorrerá uma exceção em tempo de execução. Para o meu exemplo, tenho um projeto Maven cuja estrutura do projeto se parece com a imagem abaixo. Vamos ver cada um dos componentes um por um.

Classes de Serviço

package com.journaldev.di.services;

public interface MessageService {

	boolean sendMessage(String msg, String receipient);
}

A interface MessageService fornece o contrato base para os serviços.

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) {
		//algum código sofisticado para enviar e-mail
		System.out.println("Email Message sent to "+receipient+" with message="+msg);
		return true;
	}

}

EmailService é uma das implementações de MessageService. Note que a classe é anotada com a anotação @Singleton. Como os objetos de serviço serão criados por meio de classes injetoras, essa anotação é fornecida para informá-las de que as classes de serviço devem ser objetos singleton. O Google Guice 3.0 adicionou o suporte para JSR-330 e podemos usar anotações do pacote com.google.inject ou javax.inject. Digamos que tenhamos outra implementação de serviço para enviar mensagens no 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) {
		//algum código complexo para enviar mensagem no Facebook
		System.out.println("Message sent to Facebook user "+receipient+" with message="+msg);
		return true;
	}

}

Classe Consumidora

Como estamos implementando injeção de dependência em nossa aplicação, não inicializaremos a classe de serviço na aplicação. O Google Guice suporta injeção de dependência baseada em setter e construtor. Nossa classe de aplicativo que consome o serviço parece assim.

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);
	}
}

Aviso que eu comentei o código para injeção baseada no construtor, isso é útil quando sua aplicação fornece outras funcionalidades que não precisam de um objeto da classe de serviço. Observe também a @Injector anotação, esta será usada pelo Google Guice para injetar a classe de implementação do serviço. Se você não está familiarizado com anotações, confira o tutorial de anotações em Java.

Vinculação da implementação do serviço

Obviamente, o Google Guice não saberá qual serviço usar, precisamos configurá-lo estendendo a classe AbstractModule classe abstrata e fornecendo a implementação para o 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() {
		//vincule o serviço à classe de implementação
		//bind(MessageService.class).to(EmailService.class);
		
		//vincule o MessageService à implementação de Mensagem do Facebook
		bind(MessageService.class).to(FacebookService.class);
		
	}

}

Como você pode ver, podemos vincular qualquer implementação à classe de serviço. Por exemplo, se quisermos mudar para EmailService, só precisaríamos alterar os vínculos.

Aplicação Cliente

Nossa configuração está pronta, vamos ver como usá-la com uma classe Java simples.

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]");
	}

}

A implementação é muito fácil de entender. Precisamos criar um objeto Injector usando o método createInjector() da classe Guice, onde passamos nosso objeto de implementação da classe de injetor. Em seguida, usamos o injetor para inicializar nossa classe consumidora. Se executarmos a classe acima, ela produzirá a seguinte saída.

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

Se alterarmos os vínculos para EmailService na classe AppInjector, produzirá a seguinte saída.

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

Casos de Teste JUnit

Como queremos testar a classe MyApplication, não precisamos criar uma implementação de serviço real. Podemos ter uma classe de implementação de serviço simples de simulação como abaixo.

package com.journaldev.di.services;

public class MockMessageService implements MessageService{

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

}

Minha classe de teste JUnit 4 parece com a seguinte.

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]"));;
	}

}

Repare que estou vinculando a classe MockMessageService à MessageService através de uma implementação de classe anônima da AbstractModule. Isso é feito no método setUp(), que é executado antes dos métodos de teste.

Download do Projeto Google Guice

Isso é tudo para o Tutorial de Exemplo do Google Guice. O uso do Google Guice para implementar injeção de dependência em um aplicativo é muito fácil e ele o faz de forma elegante. Ele é utilizado nas APIs do Google, então podemos assumir que é um código altamente testado e confiável. Baixe o projeto acima e explore-o para aprender mais.

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