Поиск по сайту:

Учебное пособие по внедрению зависимостей Google Guice


Google Guice — это платформа для автоматизации внедрения зависимостей в приложения. Если вы столкнулись непосредственно здесь, я бы порекомендовал вам ознакомиться с примером внедрения зависимостей, где мы узнали о проблемах с традиционным подходом к созданию объектов и преимуществах внедрения внедрения зависимостей. В последнем уроке мы узнали, как вручную реализовать внедрение зависимостей в приложения. Но когда количество классов в приложении растет, лучше поискать какой-нибудь фреймворк для автоматизации этой задачи. Google Guice — один из ведущих фреймворков, основной задачей которого является автоматическая реализация внедрения зависимостей. Мы будем работать над тем же примером, что и в предыдущем посте, и узнаем, как мы можем использовать Google Guice для автоматизации процесса внедрения внедрения зависимостей. Зависимости Google Guice доступны в центре maven, поэтому для проектов maven вы можете добавить для него зависимость ниже.

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

Классы обслуживания

package com.journaldev.di.services;

public interface MessageService {

	boolean sendMessage(String msg, String receipient);
}

Интерфейс MessageService предоставляет базовый контракт для служб.

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) {
		//some fancy code to send email
		System.out.println("Email Message sent to "+receipient+" with message="+msg);
		return true;
	}

}

EmailService — это одна из реализаций MessageService. Обратите внимание, что класс помечен аннотацией @Singleton. Поскольку сервисные объекты будут создаваться через классы инжекторов, эта аннотация предоставляется, чтобы сообщить им, что сервисные классы должны быть одноэлементными объектами. В Google Guice 3.0 добавлена поддержка JSR-330, и мы можем использовать аннотации из пакета com.google.inject или javax.inject. Допустим, у нас есть еще одна реализация сервиса для отправки сообщений в 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) {
		//some complex code to send Facebook message
		System.out.println("Message sent to Facebook user "+receipient+" with message="+msg);
		return true;
	}

}

Потребительский класс

Поскольку мы внедряем внедрение зависимостей в наше приложение, мы не будем инициализировать класс службы в приложении. Google Guice поддерживает внедрение зависимостей как на основе установки, так и на основе конструктора. Наш класс приложения, использующий сервис, выглядит следующим образом.

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

Обратите внимание, что я прокомментировал код для внедрения на основе конструктора, это удобно, когда ваше приложение также предоставляет некоторые другие функции, которым не нужен объект класса обслуживания. Также обратите внимание на учебник по аннотациям Java.

Реализация службы привязки

Очевидно, что Google Guice не будет знать, какой сервис использовать, мы должны настроить его, расширив абстрактный класс AbstractModule и предоставив реализацию для метода 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() {
		//bind the service to implementation class
		//bind(MessageService.class).to(EmailService.class);
		
		//bind MessageService to Facebook Message implementation
		bind(MessageService.class).to(FacebookService.class);
		
	}

}

Как видите, мы можем привязать любую реализацию к сервисному классу. Например, если мы хотим перейти на EmailService, нам просто нужно изменить привязки.

Клиентское приложение

Наша установка готова, давайте посмотрим, как использовать ее с простым классом Java.

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", "pankaj@abc.com");
	}

}

Реализация очень проста для понимания. Нам нужно создать объект Injector, используя метод createInjector() класса Guice, куда мы передаем объект реализации нашего класса инжектора. Затем мы используем инжектор для инициализации нашего потребительского класса. Если мы запустим класс выше, он выдаст следующий вывод.

Message sent to Facebook user pankaj@abc.com with message=Hi Pankaj

Если мы изменим привязки на EmailService в классе AppInjector, он выдаст следующий вывод.

Email Message sent to pankaj@abc.com with message=Hi Pankaj

Тестовые примеры JUnit

Поскольку мы хотим протестировать класс MyApplication, нам не нужно создавать фактическую реализацию службы. У нас может быть простой класс реализации службы Mock, как показано ниже.

package com.journaldev.di.services;

public class MockMessageService implements MessageService{

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

}

Мой тестовый класс JUnit 4 выглядит следующим образом.

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", "pankaj@abc.com"));;
	}

}

Обратите внимание, что я привязываю класс MockMessageService к MessageService, имея реализацию анонимного класса AbstractModule. Это делается в методе setUp(), который запускается перед методами тестирования.

Скачать проект Google Guice

Это все для учебника по примерам Google Guice. Использование Google Guice для внедрения внедрения зависимостей в приложение очень простое и прекрасное. Он используется в API Google, поэтому мы можем предположить, что это проверенный и надежный код. Загрузите проект сверху и поэкспериментируйте с ним, чтобы узнать больше.