1. Обзор
В нашей предыдущей статье мы показали, как выглядит создание масштабируемых приложений с использованием Ratpack.
В этом руководстве мы подробнее обсудим, как использовать Google Guice
с Ratpack в качестве механизма управления зависимостями.
2. Почему Google Guice?
Google Guice
— это программная среда с открытым исходным кодом для платформы Java
, выпущенная Google
по лицензии Apache
.
Это чрезвычайно легкий модуль управления зависимостями, который легко настроить. Более того, он позволяет внедрять зависимости на уровне конструктора только для удобства использования.
Подробнее о Guice
можно узнать здесь .
3. Использование Guice с Ratpack
3.1. Зависимость от Maven
Ratpack имеет первоклассную поддержку зависимости от Guice .
Поэтому нам не нужно вручную добавлять какие-либо внешние зависимости для Guice;
он уже поставляется предварительно собранным с Ratpack
. Подробнее о поддержке Ratpack
's Guice
можно узнать здесь .
Следовательно, нам просто нужно добавить следующую основную зависимость Ratpack
в pom.xml
:
<dependency>
<groupId>io.ratpack</groupId>
<artifactId>ratpack-core</artifactId>
<version>1.4.5</version>
</dependency>
Вы можете проверить последнюю версию на Maven Central .
3.2. Модули обслуживания зданий
Закончив с конфигурацией Maven
, мы создадим службу и хорошо воспользуемся простой инъекцией зависимостей в нашем примере здесь.
Давайте создадим один сервисный интерфейс и один сервисный класс:
public interface DataPumpService {
String generate();
}
Это сервисный интерфейс, который будет действовать как инжектор. Теперь нам нужно создать сервисный класс, который будет его реализовывать и определять сервисный метод generate():
public class DataPumpServiceImpl implements DataPumpService {
@Override
public String generate() {
return UUID.randomUUID().toString();
}
}
Здесь важно отметить, что, поскольку мы используем модуль Ratpack Guice
, нам не нужно использовать аннотацию
Guice
@ImplementedBy или @Inject
для ручного внедрения класса службы. ``
3.3. Управление зависимостями
Существует два способа управления зависимостями с помощью Google Guice
.
Первый — использовать AbstractModule
Guice
, а другой — использовать метод механизма привязки экземпляра Guice: ``
public class DependencyModule extends AbstractModule {
@Override
public void configure() {
bind(DataPumpService.class).to(DataPumpServiceImpl.class)
.in(Scopes.SINGLETON);
}
}
Здесь следует отметить несколько моментов:
- расширяя
AbstractModule
, мы переопределяем методconfigure() по умолчанию
- мы сопоставляем класс DataPumpServiceImpl с
интерфейсом
DataPumpService
, который является сервисным уровнем, созданным ранее. - мы также внедрили зависимость как
Singleton
.
3.4. Интеграция с существующим приложением
Поскольку конфигурация управления зависимостями готова, давайте теперь ее интегрируем:
public class Application {
public static void main(String[] args) throws Exception {
RatpackServer
.start(server -> server.registry(Guice
.registry(bindings -> bindings.module(DependencyModule.class)))
.handlers(chain -> chain.get("randomString", ctx -> {
DataPumpService dataPumpService = ctx.get(DataPumpService.class);
ctx.render(dataPumpService.generate().length());
})));
}
}
Здесь с помощью register()
мы связали класс DependencyModule , который расширяет
AbstractModule
. Модуль Ratpack Guice
внутренне сделает все остальное и внедрит сервис в контекст
приложения .
Поскольку он доступен в контексте приложения,
теперь мы можем получить экземпляр службы из любого места в приложении. Здесь мы извлекли экземпляр DataPumpService
из текущего контекста и сопоставили URL-адрес /randomString
с методом generate()
службы .
В результате всякий раз при попадании по URL-адресу /randomString
он будет возвращать случайные фрагменты строки.
3.5. Привязка экземпляра во время выполнения
Как было сказано ранее, теперь мы будем использовать механизм привязки экземпляров Guice для управления зависимостями во время выполнения. Это почти то же самое, что и предыдущая техника, за исключением использования метода bindInstance()
Guice вместо AbstractModule
для внедрения зависимости:
public class Application {
public static void main(String[] args) throws Exception {
RatpackServer.start(server -> server
.registry(Guice.registry(bindings -> bindings
.bindInstance(DataPumpService.class, new DataPumpServiceImpl())))
.handlers(chain -> chain.get("randomString", ctx -> {
DataPumpService dataPumpService = ctx.get(DataPumpService.class);
ctx.render(dataPumpService.generate());
})));
}
}
Здесь, используя bindInstance()
, мы выполняем привязку экземпляра, т.е. внедряем
интерфейс DataPumpService
в класс DataPumpServiceImpl.
Таким образом, мы можем внедрить экземпляр службы в контекст приложения,
как мы это делали в предыдущем примере.
Хотя мы можем использовать любой из двух методов управления зависимостями, всегда лучше использовать AbstractModule
, так как он полностью отделяет модуль управления зависимостями от кода приложения. Таким образом, код будет намного чище и его будет легче поддерживать в будущем.
3.6. Заводская привязка
Также есть еще один способ управления зависимостями, который называется фабричной привязкой
. Это не имеет прямого отношения к реализации Guice,
но может работать и параллельно с Guice
.
Фабричный класс отделяет клиента от реализации. Простая фабрика использует статические методы для получения и установки фиктивных реализаций интерфейсов.
Мы можем использовать уже созданные сервисные классы для включения фабричных привязок. Нам просто нужно создать один фабричный класс, такой же, как DependencyModule
(который расширяет класс AbstractModule Guice
) и связать экземпляры с помощью статических методов:
public class ServiceFactory {
private static DataPumpService instance;
public static void setInstance(DataPumpService dataPumpService) {
instance = dataPumpService;
}
public static DataPumpService getInstance() {
if (instance == null) {
return new DataPumpServiceImpl();
}
return instance;
}
}
Здесь мы статически внедряем сервисный интерфейс в фабричный класс . Следовательно, в каждый момент времени для этого фабричного класса будет доступен только один экземпляр этого интерфейса. Затем мы создали обычные методы получения /
установки для установки и извлечения экземпляра службы.
Здесь следует отметить, что в методе
получения мы сделали одну явную проверку, чтобы убедиться, что только один экземпляр службы присутствует или нет; если он нулевой, то только мы создали экземпляр класса реализации службы и вернули то же самое.
После этого мы можем использовать этот экземпляр фабрики в цепочке приложений:
.get("factory", ctx -> ctx.render(ServiceFactory.getInstance().generate()))
4. Тестирование
Мы будем использовать MainClassApplicationUnderTest
Ratpack для тестирования нашего приложения с помощью внутренней среды тестирования Ratpack
JUnit. Мы должны добавить для него необходимую зависимость ( ratpack-test ).
Здесь следует отметить, что, поскольку содержимое URL-адреса является динамическим, мы не можем предсказать его при написании тестового примера. Следовательно, мы бы сопоставили длину содержимого конечной точки URL-адреса /randomString
в тестовом примере:
@RunWith(JUnit4.class)
public class ApplicationTest {
MainClassApplicationUnderTest appUnderTest
= new MainClassApplicationUnderTest(Application.class);
@Test
public void givenStaticUrl_getDynamicText() {
assertEquals(21, appUnderTest.getHttpClient()
.getText("/randomString").length());
}
@After
public void shutdown() {
appUnderTest.close();
}
}
5. Вывод
В этой быстрой статье мы показали, как использовать Google Guice
с Ratpack
.
Как всегда, полный исходный код доступен на GitHub .