Einführung in Vert.x.

1. Übersicht

In diesem Artikel werden wir Vert.x diskutieren, seine Kernkonzepte behandeln und damit einen einfachen RESTfull-Webdienst erstellen.

Wir werden zunächst die grundlegenden Konzepte des Toolkits behandeln, langsam zu einem HTTP-Server übergehen und dann den RESTfull-Service erstellen.

2. Über Vert.x.

Vert.x ist ein Open-Source-, reaktives und polyglottes Softwareentwicklungs-Toolkit der Entwickler von Eclipse.

Reaktive Programmierung ist ein Programmierparadigma, das mit asynchronen Streams verbunden ist, die auf Änderungen oder Ereignisse reagieren.

In ähnlicher Weise verwendet Vert.x einen Ereignisbus, um mit verschiedenen Teilen der Anwendung zu kommunizieren, und leitet Ereignisse asynchron an Handler weiter, wenn sie verfügbar sind.

Wir nennen es polyglot, da es mehrere JVM- und Nicht-JVM-Sprachen wie Java, Groovy, Ruby, Python und JavaScript unterstützt.

3. Setup

Um Vert.x verwenden zu können, müssen wir die Maven-Abhängigkeit hinzufügen:

 io.vertx vertx-core 3.4.1 

Die neueste Version der Abhängigkeit finden Sie hier.

3. Verticles

Verticles sind Codeteile, die von der Vert.x-Engine ausgeführt werden. Das Toolkit bietet uns viele abstrakte Vertikelklassen, die erweitert und nach Belieben implementiert werden können.

Als Polyglot können Verticles in jeder der unterstützten Sprachen geschrieben werden. Eine Anwendung besteht normalerweise aus mehreren Vertikeln, die in derselben Vert.x-Instanz ausgeführt werden und über Ereignisse über den Ereignisbus miteinander kommunizieren.

Um einen Vertikel in JAVA zu erstellen, muss die Klasse die Schnittstelle io.vertx.core.Verticle oder eine ihrer Unterklassen implementieren .

4. Ereignisbus

Es ist das Nervensystem jeder Vert.x-Anwendung.

Da die Vertikel reaktiv sind, bleiben sie inaktiv, bis sie eine Nachricht oder ein Ereignis erhalten. Vertikel kommunizieren über den Ereignisbus miteinander. Die Nachricht kann von einer Zeichenfolge bis zu einem komplexen Objekt reichen.

Die Nachrichtenbehandlung ist idealerweise asynchron, Nachrichten werden in die Warteschlange des Ereignisbusses gestellt und die Steuerung wird an den Absender zurückgegeben. Später wird es in den hörenden Vertikel eingereiht. Die Antwort wird mit Future- und Callback- Methoden gesendet .

5. Einfache Vert.x-Anwendung

Lassen Sie uns eine einfache Anwendung mit einem Verticle erstellen und diese mithilfe einer Vertx- Instanz bereitstellen . Um unseren Vertikel zu erstellen, erweitern wir den

Um unseren Verticle zu erstellen, erweitern wir die Klasse io.vertx.core.AbstractVerticle und überschreiben die Methode start () :

public class HelloVerticle extends AbstractVerticle { @Override public void start(Future future) { LOGGER.info("Welcome to Vertx"); } }

Die start () -Methode wird von der vertx- Instanz aufgerufen, wenn der verticle bereitgestellt wird. Die Methode verwendet io.vertx.core.Future als Parameter, mit dem der Status einer asynchronen Bereitstellung des Vertikels ermittelt werden kann.

Lassen Sie uns nun den Vertikel einsetzen:

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

In ähnlicher Weise können wir die stop () -Methode aus der AbstractVerticle- Klasse überschreiben , die beim Herunterfahren des Vertikels aufgerufen wird:

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

6. HTTP-Server

Lassen Sie uns nun einen HTTP-Server mithilfe eines Vertikels hochfahren:

@Override public void start(Future 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()); } }); }

Wir haben die start () -Methode zum Erstellen eines HTTP-Servers überschrieben und einen Anforderungshandler daran angehängt. Die requestHandler () -Methode wird jedes Mal aufgerufen, wenn der Server eine Anforderung empfängt.

Schließlich ist der Server an einen Port gebunden, und ein AsyncResult- Handler wird an die listen () -Methode übergeben, unabhängig davon, ob die Verbindung oder der Serverstart mit future.complete () oder future.fail () erfolgreich abgeschlossen wurde Fehler.

Beachten Sie Folgendes : Die Methode config.getInteger () liest den Wert für die HTTP-Portkonfiguration, die aus einer externen Datei conf.json geladen wird .

Testen wir unseren Server:

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

Verwenden wir für den Test vertx-unit zusammen mit JUnit.:

 io.vertx vertx-unit 3.4.1 test 

Wir können die neueste Version hier bekommen.

Der Vertikel wird in einer vertx- Instanz in der setup () -Methode des Komponententests bereitgestellt :

@Before public void setup(TestContext testContext) { vertx = Vertx.vertx(); vertx.deployVerticle(SimpleServerVerticle.class.getName(), testContext.asyncAssertSuccess()); }

Ebenso wird die vertx- Instanz in der Methode @AfterClass tearDown () geschlossen :

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

Beachten Sie, dass die Methode @BeforeClass setup () ein TestContext- Argument verwendet. Dies hilft beim Steuern und Testen des asynchronen Verhaltens des Tests. Zum Beispiel ist die Verticle-Bereitstellung asynchron, sodass wir im Grunde nichts testen können, es sei denn, es wird korrekt bereitgestellt.

We have a second parameter to the deployVerticle() method, testContext.asyncAssertSuccess(). This is used to know if the server is deployed correctly or any failures occurred. It waits for the future.complete() or future.fail() in the server verticle to be called. In the case of a failure, it fails the test.

7. RESTful WebService

We have created an HTTP server, lets now use that to host an RESTfull WebService. In order do so we will need another Vert.x module called vertx-web. This gives a lot of additional features for web development on top of vertx-core.

Let's add the dependency to our pom.xml:

 io.vertx vertx-web 3.4.1 

We can find the latest version here.

7.1. Router and Routes

Let's create a router for our WebService. This router will take a simple route of GET method, and handler method getArtilces():

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

The getArticle() method is a simple method that returns new Article object:

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

A Router, when receives a request, looks for the matching route, and passes the request further. The routes having a handler method associated with it to do sumthing with the request.

In our case, the handler invokes the getArticle() method. It receives the routingContext object as an argument. Derives the path parameter id, and creates an Article object with it.

In the last part of the method, let's invoke the response() method on the routingContext object and put the headers, set the HTTP response code, and end the response using the JSON encoded article object.

7.2. Adding Router to Server

Now let's add the router, created in the previous section to the HTTP server:

vertx.createHttpServer() .requestHandler(router::accept) .listen(config().getInteger("http.port", 8080), result -> { if (result.succeeded()) { future.complete(); } else { future.fail(result.cause()); } });

Notice that we have added requestHandler(router::accept) to the server. This instructs the server, to invoke the accept() of the router object when any request is received.

Now let's test our WebService:

@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. Packaging Vert.x Application

To package the application as a deployable Java Archive (.jar) let's use Maven Shade plugin and the configurations in the execution tag:

    io.vertx.core.Starter com.baeldung.SimpleServerVerticle      ${project.build.directory}/${project.artifactId}-${project.version}-app.jar  

In the manifestEntries, Main-Verticle indicates the starting point of the application and the Main-Class is a Vert.x class which, creates the vertx instance and deploys the Main-Verticle.

9. Conclusion

In diesem Einführungsartikel haben wir das Vert.x-Toolkit und seine grundlegenden Konzepte erörtert. Ich habe gesehen, wie man einen HTTP-Server mit Vert.x und einem RESTFull-WebService erstellt und wie man sie mit vertx-unit testet .

Schließlich packte die Anwendung als ausführbare JAR.

Die vollständige Implementierung der Code-Snippets ist auf GitHub verfügbar.