Ratpack Интеграция с Google Guice

Ratpack Google Guice Интеграция

1. обзор

В наших предыдущихarticle мы показали, как выглядит создание масштабируемых приложений с использованием Ratpack.

В этом руководстве мы обсудим далее, как использоватьGoogle Guice сRatpack в качестве механизма управления зависимостями.

2. Почему Google Guice?

Google Guice - это программный фреймворк с открытым исходным кодом для платформыJava, выпущенныйGoogle подApache License.

Это чрезвычайно легкий модуль управления зависимостями, который легко настроить. Более того, он позволяет только вводить зависимости уровня конструктора для удобства использования.

Более подробную информацию оGuice можно найти вhere.

3. Использование Guice с Ratpack

3.1. Maven Dependency

Ratpack имеет первоклассную поддержку зависимостиGuice. Следовательно, нам не нужно вручную добавлять какую-либо внешнюю зависимость дляGuice;, она уже встроена сRatpack. Более подробную информацию о поддержкеRatpack'sGuice можно найти вhere.

Следовательно, нам просто нужно добавить следующую базовую зависимостьRatpack вpom.xml:


    io.ratpack
    ratpack-core
    1.4.5

Вы можете проверить последнюю версию наMavenCentral.

3.2. Модули обслуживания здания

Завершив настройкуMaven, мы создадим службу и хорошо воспользуемся простой инъекцией зависимостей в нашем примере.

Давайте создадим один интерфейс службы и один класс обслуживания:

public interface DataPumpService {
    String generate();
}

Это сервисный интерфейс, который будет действовать как инжектор. Теперь нам нужно создать класс обслуживания, который будет его реализовывать и определять метод службыgenerate():

public class DataPumpServiceImpl implements DataPumpService {

    @Override
    public String generate() {
        return UUID.randomUUID().toString();
    }

}

Здесь важно отметить, что, поскольку мы используем модульRatpack’s Guice,we don’t need to use Guice‘s @ImplementedBy or @Inject annotation to manually inject the service class.

3.3. Управление зависимостями

Есть два способа выполнить управление зависимостями с помощьюGoogle Guice.

Первый - использоватьGuice‘sAbstractModule, а другой - использовать метод механизма Guiceinstance binding:

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

Здесь сregistry() - мы связали классDependencyModule, который расширяетAbstractModule. МодульRatpack’s Guice внутренне сделает остальную часть необходимого и внедрит службу в приложениеContext.

Поскольку он доступен вapplication-context,, теперь мы можем получить экземпляр службы из любой точки приложения. Здесь мы получили экземплярDataPumpService из текущего контекста и сопоставили URL/randomString с методомgenerate() службы.

В результате при каждом попадании в URL/randomString он будет возвращать случайные фрагменты строки.

3.5. Привязка экземпляра среды выполнения

Как было сказано ранее, теперь мы будем использовать механизм привязки экземпляра Guice для управления зависимостями во время выполнения. Это почти то же самое, что и предыдущая техника, за исключением использования метода GuicebindInstance() вместо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.

Таким образом, мы можем внедрить экземпляр службы вapplication-context, как мы это делали в предыдущем примере.

Хотя мы можем использовать любой из двух методов для управления зависимостями, всегда лучше использоватьAbstractModule, поскольку он полностью отделит модуль управления зависимостями от кода приложения. Таким образом, код будет намного чище и легче поддерживать в будущем.

3.6. Заводская привязка

Есть еще один способ управления зависимостями, который называетсяfactory binding. Это не связано напрямую с реализациейGuice’s, но может работать параллельно сGuice.

Фабричный класс отделяет клиента от реализации. Простая фабрика использует статические методы для получения и установки ложных реализаций для интерфейсов.

Мы можем использовать уже созданные классы обслуживания, чтобы включить привязки к фабрике. Нам просто нужно создать один фабричный класс, какDependencyModule (который расширяет классGuice’s AbstractModule), и связать экземпляры с помощью статических методов:

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

Here, we’re statically injecting the service interface in the factory class. Следовательно, одновременно только один экземпляр этого интерфейса будет доступен для этого фабричного класса. Затем мы создали обычные методыgetter/setter для установки и выборки экземпляра службы.

Здесь следует отметить, что в методеgetter мы сделали одну явную проверку, чтобы убедиться, что присутствует только один экземпляр службы или нет; если он равен нулю, то только мы создали экземпляр класса реализации и вернули его.

После этого мы можем использовать этот экземпляр фабрики в цепочке приложений:

.get("factory", ctx -> ctx.render(ServiceFactory.getInstance().generate()))

4. тестирование

Мы будем использоватьRatpack'sMainClassApplicationUnderTest для тестирования нашего приложения с помощью внутренней среды тестирования JUnitRatpack. Мы должны добавить для него необходимую зависимость (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.

Как всегда, доступен полный исходный кодover on GitHub.