Предположительно, вы уже слышали о Vert.x , инструментарии для создания приложений Reactive на JVM. Vert.x — полностью асинхронный, легкий, невероятно быстрый, управляемый событиями, и, безусловно, очень многообещающий проект. Некоторые из вас, возможно, слышали о волокнах — если вы не знакомы с ними, проверьте здесь и здесь . В дополнение к неблокирующему и управляемому событиями инструментарию Vert.x мы можем воспользоваться Vertx-Sync как компонентом, с помощью которого мы можем легко вырваться из известного ада обратного вызова при использовании неблокирующих API. Vertx-Sync позволяет выполнять асинхронные операции и получать события синхронно, но без блокировки потоков ядра. В результате, даже если он синхронный, он ничтожно менее производительный. VertX-Sync использует Quasar для обеспечения своих волокон.
В этой статье я покажу вам, как:
- Создайте простой проект Vert.x
- Написать простой и краткий код с помощью Vertx-Sync.
- Создайте простой REST API через Vertx-Web.
- Получить некоторый веб-контент с помощью HTTP-клиента.
- Используйте MongoDB в качестве примера для использования базы данных с Vert.x.
Вы можете отправиться на GitHub, чтобы следовать здесь . Ради этого блога нам понадобятся:
- JDK 1.8
- специалист
- MongoDB
Установить и настроить MongoDB
Загрузите последнюю версию MongoDB и разархивируйте ее в свой локальный каталог. Вы можете скачать его здесь . Затем создайте следующий каталог / data / db внутри каталога, куда распаковывается MongoDB.
Чтобы запустить сервер, перейдите в {mongo_directory} / bin и запустите mongod .
Теперь пришло время запустить клиент Монго. Перейдите в {mongo_directory} / bin и запустите mongo .
Создайте базу данных testDB и коллекцию Entities:
use testDB;
db.createCollection('Entities');
Создать простой проект Vert.x
Пришло время создать наш проект Vert.x. Давай сделаем это! Наша отправная точка проекта:
import io.vertx.core.Vertx;
import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;
public class Launcher {
private static final Logger logger = LoggerFactory.getLogger(MainVerticle.class);
public static void main(String[] args) {
Vertx.vertx().deployVerticle(MainVerticle.class.getName(), h -> {
if (h.succeeded()) {
logger.info("Success: {0}", h.result());
} else {
logger.error("Something went wrong: {0}", h.cause());
}
});
И наша вертикаль:
import io.vertx.ext.web.client.WebClient;
import io.vertx.ext.web.client.WebClientOptions;
import io.vertx.ext.web.handler.BodyHandler;
import io.vertx.ext.web.handler.ErrorHandler;
import java.util.List;
public class MainVerticle extends SyncVerticle {
private static final Logger
logger = LoggerFactory.getLogger(MainVerticle.class);
private static final String COLLECTION_NAME= "Entities";
private WebClient webClient;
private MongoClient mongoClient;
@Override
@Suspendable
public void start(Future<Void> startFuture) throws Exception {
super.start(startFuture);
HttpServer server = vertx.createHttpServer();
Router router = Router.router(vertx);
// enable BodyHandler globally for easiness of body accessing
router.route().handler(BodyHandler.create()).failureHandler(ErrorHandler.create());
router.route(HttpMethod.GET,
"/getWebContent").handler(Sync.fiberHandler(this::getWebContent));
router.route(HttpMethod.GET,
"/entities").handler(Sync.fiberHandler(this::getAllEntities));
router.route(HttpMethod.GET,
"/entities/:id").handler(Sync.fiberHandler(this::getEntityById));
router.route(HttpMethod.PUT,
"/entities").handler(Sync.fiberHandler(this::saveNewEntity));
// HttpServer will be automatically shared if port matches
server.requestHandler(router::accept).listen(8089);
webClient = WebClient.create(vertx, new WebClientOptions().setSsl(true));
mongoClient = MongoClient.createShared
(vertx, new JsonObject().put("connection_string", "mongodb://127.0.0.1:27017/testDb"));
}
@Suspendable
private void saveNewEntity(RoutingContext routingContext){
final String response = Sync.awaitResult
(h -> mongoClient.save(COLLECTION_NAME, routingContext.getBodyAsJson(), h));
routingContext.response().end(response);
}
@Suspendable
private void getAllEntities(RoutingContext routingContext){
final List<JsonObject> entities = Sync.awaitResult
(h -> mongoClient.find(COLLECTION_NAME, new JsonObject(), h));
routingContext.response().end(Json.encodePrettily(entities));
}
@Suspendable
private void getEntityById(RoutingContext routingContext){
final JsonObject query = new JsonObject()
.put("_id", routingContext.pathParam("id"));
final List<JsonObject> entity = Sync.awaitResult
(h -> mongoClient.find(COLLECTION_NAME, query, h));
routingContext.response()
.end(Json.encodePrettily(entity));
}
@Suspendable
private void getWebContent(RoutingContext routingContext){
final HttpResponse<Buffer> response = Sync.awaitResult
(h -> webClient.getAbs("https://www.google.com").send(h));
final String responseContent = response.bodyAsString("UTF-8");
logger.info("Result of Http request: {0}", responseContent);
routingContext.response()
.putHeader(HttpHeaderNames.CONTENT_TYPE, "text/html")
.end(responseContent);
- Класс Launcher предназначен только для запуска нашей программы и развертывания нашей MainVerticle.
- Необходимо учитывать, что наша MainVerticle расширяет io.vertx.ext.sync.SyncVerticle. Если он не развернут как экземпляр SyncVerticle, волокна не будут работать.
- Создайте HttpServer и маршрутизатор для обработки нашего REST API (выполнив следующие три шага):
- GET http: // localhost: 8089 / getWebContent — запросить « https://www.google.com » только для тестирования асинхронного HTTP-клиента.
- ПОЛУЧИТЕ http: // localhost: 8089 / entity
- GET http: // localhost: 8089 / entity /: id -: id — это параметр пути для поиска какой-либо сущности
- PUT http: // localhost: 8089 / entity — создать новую запись объекта. Примените JSON к полезной нагрузке, например: {«name»: «Charlie Harper»}
- Создайте WebClient и MongoClient и используйте их асинхронные API синхронно через Fibers.
- Очень важно использовать Sync.fiberHandler (), когда нам нужно использовать любые обработчики. Для использования Fibers в обычном обработчике, например в обработчике запросов HTTP-сервера, мы должны сначала преобразовать обычный обработчик в обработчик волокна.
- Получение ответа от асинхронных API, которые возвращают AsyncResult <T> в качестве обратного вызова, очень просто с Sync.awaitResult (). Ниже приведена некоторая скопированная документация Vertx по этому поводу:
«Многие асинхронные операции в Vert.x-land принимают Handler <AsyncResult <T >> в качестве последнего аргумента. Примером может служить выполнение поиска с использованием клиента Vert.x Mongo или отправка сообщения шины событий и получение ответа. Vertx -sync позволяет синхронно получать результат однократной асинхронной операции. Это выполняется с помощью метода Sync.awaitResult. «
Метод выполняется с указанием асинхронной операции, которую вы хотите выполнить в форме Потребителя, потребитель передается обработчику во время выполнения. Использование лямбда-выражений делает это еще проще:
final List<JsonObject> entity = Sync.awaitResult
(h -> mongoClient.find(COLLECTION_NAME, query, h));
final HttpResponse<Buffer>
response = Sync.awaitResult
(h -> webClient.getAbs("https://www.google.com").send(h));
Самое главное, чтобы инструмент нашего байт-кода. Vert.x использует Quasar, а их реализация Fiber использует инструментарий байт-кода. Нам не нужно делать ничего особенного, просто нужно запустить JVM с javaagent в качестве опции VM. Например:
javaagent: /path/to/quasar/core/quasar-core.jar.
Для этого мы используем «exec-maven-plugin». Вот содержание pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.idle.fibers</groupId>
<artifactId>vertx-sync-fibers</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<vertx.version>3.4.1</vertx.version>
<main.verticle>org.idle.easy.fibers.MainVerticle</main.verticle>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-dependencies</artifactId>
<version>${vertx.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web</artifactId>
<version>${vertx.version}</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web-client</artifactId>
<version>${vertx.version}</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-auth-oauth2</artifactId>
<version>${vertx.version}</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-sync</artifactId>
<version>${vertx.version}</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-mongo-client</artifactId>
<version>${vertx.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<filesets>
<fileset>
<directory>${project.basedir}/src/main/generated</directory>
</fileset>
</filesets>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<configuration>
<mainClass>org.idle.easy.fibers.Launcher</mainClass>
<workingDirectory>target/classes</workingDirectory>
<executable>java</executable>
<arguments>
<argument>-javaagent:${co.paralleluniverse:quasar-core:jar}</argument>
</arguments>
</configuration>
</plugin>
</plugins>
</build>
</project>
Наконец, чтобы запустить нашу программу, просто наберите: mvn clean package exec: java
И это все!