Введение в Vert.x

1. Обзор

В этой статье мы обсудим Vert.x , рассмотрим его основные концепции и создадим с ним простой веб-сервис RESTfull.

Мы начнем с рассмотрения основных принципов работы инструментария, постепенно перейдем к HTTP-серверу и затем создадим сервис RESTfull.

2. О Vert.x

  • Vert.x - это инструментарий разработки программного обеспечения с открытым исходным кодом, реактивной и полиглотной разработки ** от разработчиков Eclipse.

Реактивное программирование - это парадигма программирования, связанная с асинхронными потоками, которые реагируют на любые изменения или события.

Аналогично, Vert.x использует шину событий для связи с различными частями приложения и асинхронно передает события обработчикам, когда они доступны.

  • Мы называем это полиглотом из-за его поддержки нескольких языков JVM и не-JVM, таких как Java, Groovy, Ruby, Python и JavaScript. **

3. Настроить

Чтобы использовать Vert.x нам нужно добавить зависимость Maven:

<dependency>
    <groupId>io.vertx</groupId>
    <artifactId>vertx-core</artifactId>
    <version>3.4.1</version>
</dependency>

Последнюю версию зависимости можно найти по адресу here ,

3. Verticles

Версии - это фрагменты кода, которые выполняет движок Vert.x. Инструментарий предоставляет нам множество абстрактных классов вертикалей, которые могут быть расширены и реализованы так, как мы хотим.

Будучи полиглотом, статьи могут быть написаны на любом из поддерживаемых языков. Приложение обычно состоит из нескольких вершин, запущенных в одном и том же экземпляре Vert.x, и связывается друг с другом, используя события через шину событий.

Чтобы создать вертикаль в JAVA, класс должен реализовать интерфейс io.vertx.core.Verticle или любой из его подклассов.

4. Event Bus

Это нервная система любого приложения Vert.x.

Будучи реагирующими, вертикали остаются бездействующими, пока не получат сообщение или событие. Вершины общаются друг с другом через шину событий. Сообщение может быть чем угодно, от строки до сложного объекта.

Обработка сообщений в идеале асинхронна, сообщения помещаются в очередь на шину событий, а управление возвращается отправителю. Позже он переводится в прослушивание. Ответ отправляется с использованием методов Future и callback .

5. Простое приложение Vert.x

  • Давайте создадим простое приложение с вертикалью и развернем его, используя экземпляр vertx ** . Чтобы создать нашу статью, мы расширим

Чтобы создать нашу статью, мы расширим класс io.vertx.core.AbstractVerticle и переопределим метод start () :

public class HelloVerticle extends AbstractVerticle {

    @Override
    public void start(Future<Void> future) {
        LOGGER.info("Welcome to Vertx");
    }
}

Метод start () будет вызываться экземпляром vertx при развертывании вертикали. Метод принимает в качестве параметра io.vertx.core.Future , который можно использовать для определения состояния асинхронного развертывания вертикали.

Теперь давайте развернем вертикаль:

public static void main(String[]args) {
    Vertx vertx = Vertx.vertx();
    vertx.deployVerticle(new HelloVerticle());
}

Точно так же мы можем переопределить метод stop () из класса AbstractVerticle , который будет вызываться при выключении вертикали:

@Override
public void stop() {
    LOGGER.info("Shutting down application");
}

6. HTTP-сервер

Теперь давайте раскрутим HTTP-сервер, используя вертикуру:

@Override
public void start(Future<Void> future) {
    vertx.createHttpServer()
      .requestHandler(r -> r.response().end("Welcome to Vert.x Intro");
      })
      .listen(config().getInteger("http.port", 9090),
        result -> {
          if (result.succeeded()) {
              future.complete();
          } else {
              future.fail(result.cause());
          }
      });
}

Мы переопределили метод start () , чтобы создать HTTP-сервер, и прикрепили к нему обработчик запросов. Метод requestHandler () вызывается каждый раз, когда сервер получает запрос.

Наконец, сервер привязан к порту, и обработчик AsyncResult <HttpServer> передается методу listen () независимо от того, было ли соединение или запуск сервера успешным с помощью future.complete () или future.fail ( ) в случае каких-либо ошибок.

Обратите внимание: метод config.getInteger () читает значение для конфигурации порта HTTP, которое загружается из внешнего файла conf.json .

Давайте проверим наш сервер:

@Test
public void whenReceivedResponse__thenSuccess(TestContext testContext) {
    Async async = testContext.async();

    vertx.createHttpClient()
      .getNow(port, "localhost", "/", response -> {
        response.handler(responseBody -> {
          testContext.assertTrue(responseBody.toString().contains("Hello"));
          async.complete();
        });
      });
}

Для теста давайте используем vertx-unit вместе с JUnit .:

<dependency>
    <groupId>io.vertx</groupId>
    <artifactId>vertx-unit</artifactId>
    <version>3.4.1</version>
    <scope>test</scope>
</dependency>

Мы можем получить последнюю версию here .

Вертикаль развернута и в экземпляре vertx в методе setup () модульного теста:

@Before
public void setup(TestContext testContext) {
    vertx = Vertx.vertx();

    vertx.deployVerticle(SimpleServerVerticle.class.getName(),
      testContext.asyncAssertSuccess());
}

Аналогично, экземпляр vertx закрывается в методе @ AfterClass tearDown () :

@After
public void tearDown(TestContext testContext) {
    vertx.close(testContext.asyncAssertSuccess());
}

Обратите внимание, что метод @ BeforeClass setup () принимает аргумент TestContext . Это помогает контролировать и тестировать асинхронное поведение теста. Например, развертывание вертикали является асинхронным, поэтому мы не можем ничего протестировать, если оно не развернуто правильно.

У нас есть второй параметр в методе deployVerticle () , testContext.asyncAssertSuccess () . _T his используется для определения правильности развертывания сервера или возникновения сбоев. Он ожидает вызова future.complete () или future.fail () _ в тексте сервера. В случае сбоя он не проходит тест.

7. RESTful WebService

Мы создали HTTP-сервер, теперь давайте используем его для размещения RESTfull WebService. Для этого нам понадобится другой модуль Vert.x с именем vertx-web . Это дает множество дополнительных возможностей для веб-разработки поверх vertx-core .

Давайте добавим зависимость к нашему pom.xml:

<dependency>
    <groupId>io.vertx</groupId>
    <artifactId>vertx-web</artifactId>
    <version>3.4.1</version>
</dependency>

Мы можем найти последнюю версию here .

7.1. Router и Routes

Давайте создадим router для нашего WebService. Этот маршрутизатор будет использовать простой маршрут метода GET и метода-обработчика getArtilces () :

Router router = Router.router(vertx);
router.get("/api/baeldung/articles/article/:id")
  .handler(this::getArticles);

Метод getArticle () - это простой метод, который возвращает новый объект Article :

private void getArticles(RoutingContext routingContext) {
    String articleId = routingContext.request()
      .getParam("id");
    Article article = new Article(articleId,
      "This is an intro to vertx", "baeldung", "01-02-2017", 1578);

    routingContext.response()
      .putHeader("content-type", "application/json")
      .setStatusCode(200)
      .end(Json.encodePrettily(article));
}

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

В нашем случае обработчик вызывает метод getArticle () . Он получает объект routingContext в качестве аргумента. Получает параметр пути id, и создает объект Article с ним.

В последней части метода давайте вызовем метод response () для объекта routingContext и поместим заголовки, установите код ответа HTTP и завершим ответ, используя объект article в кодировке JSON.

7.2. Добавление Router на сервер

Теперь давайте добавим router, , созданный в предыдущем разделе, на HTTP-сервер:

vertx.createHttpServer()
  .requestHandler(router::accept)
  .listen(config().getInteger("http.port", 8080),
    result -> {
      if (result.succeeded()) {
          future.complete();
      } else {
          future.fail(result.cause());
      }
});
Обратите внимание, что мы добавили __requestHandler (router

accept) на сервер. Это дает команду серверу вызывать accept () объекта router__ при получении любого запроса.

Теперь давайте проверим наш веб-сервис:

@Test
public void givenId__whenReceivedArticle__thenSuccess(TestContext testContext) {
    Async async = testContext.async();

    vertx.createHttpClient()
      .getNow(8080, "localhost", "/api/baeldung/articles/article/12345",
        response -> {
            response.handler(responseBody -> {
            testContext.assertTrue(
              responseBody.toString().contains("\"id\" : \"12345\""));
            async.complete();
        });
      });
}

8. Упаковка Vert.x Применение

Чтобы упаковать приложение в развертываемый Java-архив (.jar), давайте воспользуемся плагином Maven Shade и настройками в теге execution :

<configuration>
    <transformers>
        <transformer
          implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
            <manifestEntries>
                <Main-Class>io.vertx.core.Starter</Main-Class>
                <Main-Verticle>com.baeldung.SimpleServerVerticle</Main-Verticle>
            </manifestEntries>
        </transformer>
    </transformers>
    <artifactSet/>
    <outputFile>
        ${project.build.directory}/${project.artifactId}-${project.version}-app.jar
    </outputFile>
</configuration>

В manifestEntries Main-Verticle указывает начальную точку приложения, а Main-Class является классом Vert.x, который создает экземпляр vertx и развертывает Main-Verticle.

9. Заключение

В этой вводной статье мы обсудили инструментарий Vert.x и его основные понятия. Увидел, как создать и HTTP-сервер, с Vert.x, а также с RESTFull WebService и показал, как их тестировать с помощью vertx-unit .

Наконец упаковано приложение в виде исполняемого файла jar.

Полная реализация фрагментов кода доступна по адресу over на GitHub .