Google Guice Dependency Injection Voorbeeld Tutorial

Google Guice is het framework om de afhankelijkheidsinjectie in applicaties te automatiseren. Als je hier direct terecht bent gekomen, raad ik je aan om Dependency Injection Example te bekijken waar we de problemen met de traditionele aanpak van objectcreatie hebben geleerd en de voordelen van afhankelijkheidsinjectie-implementatie. In de laatste tutorial hebben we geleerd hoe we afhankelijkheidsinjectie handmatig kunnen implementeren in applicaties. Maar wanneer het aantal klassen groeit in een applicatie, is het beter om op zoek te gaan naar een framework om deze taak te automatiseren. Google Guice is een van de toonaangevende frameworks waarvan het hoofddoel is om de automatische implementatie van afhankelijkheidsinjectie te bieden. We zullen werken aan hetzelfde voorbeeld als in de vorige post en leren hoe we Google Guice kunnen gebruiken om het implementatieproces voor afhankelijkheidsinjectie te automatiseren. Google Guice-afhankelijkheden zijn beschikbaar op Maven Central, dus voor Maven-projecten kun je de onderstaande afhankelijkheid toevoegen.

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

Als je een eenvoudige Java-applicatie hebt, kun je het jar-bestand downloaden vanaf de Google Guice Home Page op Google Code. Merk op dat je in dit geval ook de overige afhankelijkheden in het classpath moet hebben, anders krijg je een runtime-uitzondering. Voor mijn voorbeeld heb ik een Maven-project waarvan de projectstructuur eruitziet zoals in onderstaande afbeelding. Laten we elk van de componenten één voor één bekijken.

Dienstklassen

package com.journaldev.di.services;

public interface MessageService {

	boolean sendMessage(String msg, String receipient);
}

MessageService-interface biedt het basiscontract voor de services.

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) {
		//wat chique code om een e-mail te versturen
		System.out.println("Email Message sent to "+receipient+" with message="+msg);
		return true;
	}

}

EmailService is een van de implementaties van MessageService. Let op dat de klasse is geannoteerd met @Singleton-annotatie. Aangezien service-objecten worden gemaakt via injector-klassen, wordt deze annotatie toegevoegd om aan te geven dat de serviceklassen singleton-objecten moeten zijn. Google Guice 3.0 heeft ondersteuning toegevoegd voor JSR-330 en we kunnen annotaties gebruiken uit het com.google.inject– of javax.inject-pakket. Laten we zeggen dat we een andere service-implementatie hebben om Facebook-berichten te versturen.

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) {
		//wat complexe code om een Facebook-bericht te versturen
		System.out.println("Message sent to Facebook user "+receipient+" with message="+msg);
		return true;
	}

}

Consumentenklasse

Aangezien we dependency injection implementeren in onze applicatie, initialiseren we de serviceklasse niet in de applicatie. Google Guice ondersteunt zowel setter-gebaseerde als constructor-gebaseerde dependency injection. Onze applicatieklasse die de service consumeert, ziet er als volgt uit.

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

Let op dat ik de code heb gecommentarieerd voor constructor-gebaseerde injectie, dit is handig wanneer je applicatie ook andere functies biedt die geen serviceklasobject nodig hebben. Let ook op de @Injector annotatie, deze zal worden gebruikt door Google Guice om de service-implementatieklasse in te voegen. Als je niet bekend bent met annotaties, bekijk dan de Java-annotaties tutorial.

Binding Service-implementatie

Natuurlijk zal Google Guice niet weten welke service moet worden gebruikt, we moeten dit configureren door AbstractModule uit te breiden abstracte klasse en implementatie te bieden voor configure() methode.

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() {
		//koppel de service aan de implementatieklasse
		//bind(MessageService.class).to(EmailService.class);
		
		//koppel MessageService aan Facebook Message-implementatie
		bind(MessageService.class).to(FacebookService.class);
		
	}

}

Zoals je kunt zien, kunnen we elke implementatie aan de serviceklasse koppelen. Bijvoorbeeld, als we willen overschakelen naar EmailService, hoeven we alleen maar de koppelingen te wijzigen.

Clientapplicatie

Onze setup is gereed, laten we eens kijken hoe we het kunnen gebruiken met een eenvoudige Java-klasse.

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

}

De implementatie is zeer eenvoudig te begrijpen. We moeten een Injector-object maken met behulp van de createInjector() methode van de Guice-klasse waarbij we ons injectorklasse-implementatie-object doorgeven. Vervolgens gebruiken we de injector om onze consumptieklasse te initialiseren. Als we de bovenstaande klasse uitvoeren, zal deze het volgende uitvoer produceren.

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

Als we de koppelingen naar EmailService in de AppInjector-klasse wijzigen, zal dit het volgende resultaat opleveren.

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

JUnit-testgevallen

Aangezien we de MyApplication-klasse willen testen, hoeven we geen daadwerkelijke service-implementatie te maken. We kunnen een eenvoudige mock-service-implementatieklasse hebben zoals hieronder.

package com.journaldev.di.services;

public class MockMessageService implements MessageService{

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

}

Mijn JUnit 4-testklasse ziet er als volgt uit.

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

}

Let op dat ik de klasse MockMessageService koppel aan MessageService door middel van een anonieme klasse-implementatie van AbstractModule. Dit wordt gedaan in de setUp()-methode die vóór de testmethoden wordt uitgevoerd.

Download Google Guice Project

Dat is alles voor de Google Guice voorbeeldtutorial. Het gebruik van Google Guice voor het implementeren van dependency injection in een applicatie is zeer eenvoudig en het doet het prachtig. Het wordt gebruikt in Google API’s, dus we kunnen aannemen dat het zeer geteste en betrouwbare code is. Download het project hierboven en speel ermee om meer te leren.

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