Google Guice – это фреймворк для автоматизации инъекции зависимостей в приложения. Если вы попали сюда напрямую, я бы порекомендовал вам ознакомиться с Примером инъекции зависимостей, где мы изучили проблемы традиционного подхода к созданию объектов и преимущества реализации инъекции зависимостей. В последнем уроке мы узнали, как можно реализовать инъекцию зависимостей в приложениях вручную. Но когда количество классов растет в приложении, лучше обратить внимание на некоторый фреймворк для автоматизации этой задачи. Google Guice – один из ведущих фреймворков, основная задача которого – предоставить автоматическую реализацию инъекции зависимостей. Мы будем работать над тем же примером из последней записи и узнаем, как мы можем использовать Google Guice для автоматизации процесса реализации инъекции зависимостей. Зависимости Google Guice доступны в центральном репозитории Maven, поэтому для проектов Maven вы можете добавить нижеприведенную зависимость для этого.
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>3.0</version>
</dependency>
Если у вас простое java-приложение, то вы можете скачать файл jar с домашней страницы Google Guice на Google Code. Обратите внимание, что в этом случае вам также понадобится иметь его транзитивные зависимости в classpath, иначе вы получите исключение времени выполнения. Для моего примера у меня есть проект Maven, структура которого выглядит как на изображении ниже. Давайте посмотрим на каждый из компонентов по очереди.
Классы Сервиса
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) {
//какой-то изысканный код для отправки электронной почты
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) {
//некоторый сложный код для отправки сообщения в Facebook
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;
// инжектор на основе конструктора
// @Inject
// public MyApplication(MessageService svc){
// this.service=svc;
// }
// инжектор метода установки
@Inject
public void setService(MessageService svc){
this.service=svc;
}
public boolean sendMessage(String msg, String rec){
// здесь некоторая бизнес-логика
return service.sendMessage(msg, rec);
}
}
Обратите внимание, что я прокомментировал код для инжекции на основе конструктора. Это может быть удобно, если ваше приложение также предоставляет другие функции, которым не нужен объект службы. Также обратите внимание на аннотацию @Injector, которую будет использовать Google Guice для внедрения класса реализации службы. Если вы не знакомы с аннотациями, посмотрите учебник по аннотациям Java java annotations tutorial.
Привязка реализации службы
Очевидно, что Google Guice не будет знать, какую службу использовать. Мы должны настроить это, расширив абстрактный класс AbstractModule
abstract class и предоставив реализацию метода 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(MessageService.class).to(EmailService.class);
// привязать MessageService к реализации Facebook Message
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", "[email protected]");
}
}
Реализация очень легка для понимания. Нам нужно создать объект Injector
с использованием метода createInjector() класса Guice, в котором мы передаем объект реализации нашего класса инжектора. Затем мы используем инжектор для инициализации нашего класса потребителя. Если мы запустим вышеуказанный класс, он выдаст следующий результат.
Message sent to Facebook user [email protected] with message=Hi Pankaj
Если мы изменяем привязки на EmailService
в классе AppInjector
, то результат будет следующим.
Email Message sent to [email protected] with message=Hi Pankaj
Юнит-тесты JUnit
Поскольку мы хотим протестировать класс MyApplication, нам не нужно создавать фактическую реализацию службы. Мы можем использовать простую имитацию класса реализации службы, как показано ниже.
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", "[email protected]"));;
}
}
Обратите внимание, что я привязываю класс MockMessageService
к MessageService
, создав анонимный класс реализации AbstractModule
. Это делается в методе setUp()
, который выполняется перед методами тестирования.
Это все для примера учебника по Google Guice. Использование Google Guice для реализации внедрения зависимостей в приложение очень легко, и он делает это красиво. Он используется в API Google, поэтому мы можем предположить, что это высокотестированный и надежный код. Скачайте проект выше и поиграйтесь с ним, чтобы узнать больше.
Source:
https://www.digitalocean.com/community/tutorials/google-guice-dependency-injection-example-tutorial