Drittes Major Release von Vert.x

Vert.x: Sieg in Runde 3

Jochen Mader

©Shutterstock/Nik Merkulov

Vert.x hat sich in den letzten Jahren als einer der wichtigsten Vertreter reaktiver, aktorenartiger Anwendungs-Frameworks etabliert. Am 24. Juni ist nun endlich das dritte Major Release mit einer Vielzahl an Neuerungen erschienen. In diesem Artikel werde ich einen kurzen Überblick zu den wichtigsten neuen Features und Änderungen geben.

Geschichte

Bevor ich in den technologischen Part einsteige, möchte ich noch kurz etwas zur Geschichte und aktuellen Situation von Vert.x schreiben. Schon seit 2011 – noch während seiner Zeit bei VMware – entwickelte Tim Fox die erste Version von Vert.x. Sie zeigte, dass Node.js-artige, eventgetriebene Frameworks auch mit den Mitteln der JVM umsetzbar sind. Mit seinem Weggang erhielt das Projekt einen deutlichen Aufmerksamkeitssprung, der allerdings mehr mit dem Copyright-Disput zwischen seinem alten und neuen Arbeitgeber (Red Hat) zu tun hatte.

Nachdem man sich darauf geeinigt hatte, das Projekt unter die Schirmherrschaft der Eclipse Foundation zu stellen, konnte Tim seine Arbeit an Version 2 fortsetzen.

Vert.x 2 ist in meinen Augen die Version mit der sich Vert.x endlich aus dem Schatten von Node.js löst und sich als ernsthafte Alternative zu konventionellen Frameworks etabliert. Der verteilte EventBus, die polyglotte Ausrichtung der API und das simple aktorenartige Threading Model weckten die Neugier vieler Entwickler. Gleichzeitig erkannte auch Red Hat sein Potential und begann das Team schrittweise zu vergrößern. 2013 stieß Julien Viet als Vollzeitentwickler hinzu. Vor ein paar Monaten folgten dann noch Paulo Lopes und Clement Escoffier.

Vert.x 3 startet also mit einer aktiven Community, vier von Red Hat bezahlten Vollzeitentwicklern und einem durch Vert.x 2 gut gefüllten Polster an Erwartungen in den neuen Major Releases. Bessere Voraussetzungen haben nur wenige Projekte. Mal sehen was das Team uns da serviert hat.

Eine neue Richtung

Ein wichtiger Aspekt des Vert.x Frameworks war die Möglichkeit es als Bibliothek, statt als Container, zu verwenden. Mit der neuen Version soll dieser Aspekt noch viel stärker in den Vordergrund treten. Um aufkeimende Bedenken einzufangen:

Auch gilt weiterhin, dass Module und Verticles der präferierte Weg sind eine Anwendung zu bauen.

Allerdings möchte man dies dem Entwickler nicht mehr vorschreiben und hat die API so umgestaltet, dass auch Anwendungen komplett ohne Module und Verticles gebaut werden können.

So wird man in Zukunft viel öfter ähnliche Konstrukte wie im folgenden Code-Beispiel sehen:

Vertx vertx = Vertx.vertx();
HttpServer httpServer = vertx.createHttpServer();
Router router = Router.router(vertx);
router.get("/").handler(routingContext -> {
HttpServerResponse response = routingContext.response();
response.putHeader("content-type", "text/plain");
response.end("Hello World!");
});
httpServer.requestHandler(router::accept).listen(8087);

Durch diese geänderte Ausrichtung tritt auch eine andere Form des Deployments in den Vordergrund: Statt eines klassischen Applikations-Deployments in einer Runtime setzt Vert.x verstärkt auf die Möglichkeit Anwendungen als Fat Jars (https://blog.codecentric.de/en/2015/06/realjarshavecurves/) zu starten. Einer Entwicklung, der ich mehr als positiv gegenüber stehe. In Kundenprojekten hat sich das Fat Jar Deployment von Vert.x-2-Anwendungen in einer automatisierten Release Chain als sehr mächtiges Werkzeug erwiesen. Mit Vert.x 3 wird das Ganze noch einfacher als es schon war.

Event Bus

Der Event Bus wurde einer Generalüberholung unterzogen. Bis Version 2 konnte man über diesen ausschließlich Nachrichten im JSON-Format oder bestehend aus primitiven Datentypen verschicken. Mit Version 3 können nun eigene Implementierung von io.vertx.core.eventbus.MessageCodec am Event Bus registriert werden. Sie ermöglichen die Verwendung eigener Serialisierungsmechanismen, wie z.B. Kryo oder Protocol Buffers.

Mit folgendem Code-Fragment kann man einen eigenen Codec für bestimmte Nachrichten verwenden:

MessgeCodec codec = new MessageCodec() {...};
eventBus.registerCodec(codec);
DeliveryOptions options = new DeliveryOptions().setCodecName(codec.name());
eventBus.send("target", <object to send>, options);

Möchte man den Codec für alle gesendeten Nachrichten eines bestimmten Typs verwenden, so kann man diesen als Default registrieren:

eventBus.registerDefaultCodec(<class to be serialized>.class, codec);

Neben den Codecs wurde der Event Bus auch um die Möglichkeit der Verwendung von Headers erweitert:

DeliveryOptions options = new DeliveryOptions();
options.addHeader("importance", "really important");
eventBus.send("is.it.important", "Yesss! I am important!", options);

Headers ermöglichen eine Vielzahl neuer Varianten bei der Steuerung des Nachrichtenflusses. Besonders komplexe Routing-Szenarien sind nun einfach umsetzbar, da für die Betrachtung der Header keine potentiell teure Deserialisierung der Payload durchgeführt werden muss.

Polyglott

Ein wichtiger Grund für den Erfolg von Vert.x war sein polyglotter Ansatz bei der Bereitstellung von APIs. Wo andere Frameworks sich als polyglott bezeichnen, da ihre API theoretisch mit jeder JVM-Sprache verwendbar ist, setzte man bei Vert.x schon früh auf einen ganzheitlichen Ansatz (ohne Globulis und Nadeln). Für jede Sprache wurden eigene Varianten der Kern-APIs manuell erstellt. Dieses aufwändige Verfahren wurde nun durch einen generativen Ansatz ersetzt.

Die entsprechenden APIs werden mit speziellen Annotationen (siehe https://github.com/vertx3/vertxcodegen) versehen, mit deren Hilfe ein Maven-Plug-in passende Varianten für die Zielsprachen erzeugt. Aktuell werden Java, JavaScript, Groovy und Ruby unterstützt. Für Version 3.1 folgen dann Scala, Python und diverse Andere. Durch diesen vereinfachten Ansatz und die umfangreiche Dokumentation dürfte es deutlich einfacher sein, sprachspezifische APIs für neue Sprachen hinzu zu fügen.

Wie einfach es wirklich ist, werden die folgenden Monate zeigen.

Reactive Programming

Neben Microservices ist Reactive Programming eines der wichtigsten Themen der letzten Jahre. Mit dem Reaktiven Manifesto (http://www.reactivemanifesto.org/de) wurde eine neue Gattung von Frameworks definiert, welche die Zukunftssicherheit neuer Anwendung verbessern sollten. Vert.x erfüllte schon seit jeher die Anforderungen, die im Manifest formuliert wurden. Allerdings hat sich seit Vert.x 2 Einiges in dem Bereich getan.

Vor allem die Reactive Extensions (https://github.com/ReactiveX/RxJava) sind zu einem defakto-Standard für den Umgang mit Event Streams geworden. Konsequenterweise wurden diese nun in den Kern von Vert.x aufgenommen. Dank des neuen Frameworks zur Erzeugung sprachspezifischer Schnittstellen sind auch diese APIs für alle Sprachen verfügbar. Um sie zu nutzen muss nur die entsprechende Dependency hinzugefügt werden:

<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-rx-java</artifactId>
<version>3.0.0</version>
</dependency>

Jetzt können die aus RxJava bekannten Observables genutzt werden.

Hier ein kurzes Codebeispiel, in dem alle an die Adresse observeme gesendeten Nachrichten auf die Existenz einer somevalue-Property überprüft, über den Zeitraum von 1000 ms gesammelt und schließlich als ein Block an den Verarbeitungsschritt weitergeleitet werden:

Observable<Message<JsonObject>> observable = vertx.eventBus().<JsonObject>consumer("observerme").toObservable();
observable
.filter(msg -> msg.body().containsKey("somevalue"))
.buffer(1000, TimeUnit.MILLISECONDS).
.subscribe(msgList -> {
...
<do stuff>
...
});

Der Umgang mit Events wird somit deutlich eleganter und einfacher lesbar.

Neben den Rx-Extensions wurden aber auch Reactive Streams (http://www.reactive-streams.org/) implementiert. Diese kompakten Sets aus vier Klassen sind das Ergebnis der Kooperation verschiedener Big Player (Oracle, Twitter, Netflix, um nur ein paar zu nennen) und werden wohl demnächst auch in Form eines JSRs wieder zu finden sein.

Ziel war es, eine API für die Verarbeitung asynchroner Streams samt nicht blockierender Backpressure zu schaffen. Im Falle von Vert.x können Reactive Streams vor allem zur Interaktion mit anderen Frameworks wie z.B. Akka genutzt werden. Auf dem Event Bus finden die Reactive Streams keine Verwendung, da man hier auch weiterhin keine Vorgaben an den Verwender machen möchte.

Modularität und Buildsysteme

Kommen wir zum wohl gravierendsten Umbau im Framework.

Mit Vert.x 3 wurde das bisherige Modulsystem entfernt. Dieses hatte offensichtlich zu einiger Verwirrung bei verschiedenen Entwicklern geführt und stand dem “Baukasten”-Gedanken im Weg.

Vorbei sind die Zeiten, in denen sowohl Module als auch Verticles eigene Classloader hatten. Von nun an sind Module nichts weiter als simple Dependencies und nach dem Build findet sich alles im typisch flachen Classpath.

In den Vert.x-Examples (https://github.com/vert-x3/vertx-examples) finden sich die Beispiele gradle-simplest (https://github.com/vert-x3/vertx-examples/tree/master/gradle-simplest) und maven-simplest (https://github.com/vert-x3/vertx-examples/tree/master/maven-simplest), die gut als Schnelleinstieg in ein erstes Vert.x 3-Projekt geeignet sind.

 

So ganz ohne geht es dann aber doch nicht. Bestimmte Features wurden mit den neuen APIs reimplementiert. Mit dem vertx maven service factory (https://github.com/vertx3/vertxmavenservicefactory/blob/master/README.md) ist es auch weiterhin möglich, Module aus entfernten Repositories (Nexus, BitBucket, HTTP,…) zu laden und zur Laufzeit hinzuzufügen.

vertx.deployVerticle("maven:com.mycompany:main-services:1.2::my-service", ...)

Und so viel mehr

Dies waren nur eine kleine Auswahl an Neuerungen in Vert.x 3. Hinzu kommt eine gewaltige Liste neuer Features:

  • Fat-Jar-Deployments via Shadow/Shade-Plug-in
  • neues Unit Testing Framework
  • JCA-Integration
  • Neue APIs für Authentifizierung/Autorisierung via Apache Shiro / JWT /JDBC
  • Dropwizard Metrics
  • Docker- und OpenShift-Unterstützung
  • Hazelcast Module
  • Alternativer Cluster Manager via JBoss Groups

Aber irgendwann muss ein Artikel eben auch Enden.

Ende

Nachdem ich das Glück hatte, die letzten 1,5 Jahre fast ausschließlich mit Vert.x 2 zu arbeiten, war meine Vorfreude auf das dritte Major Release groß. Die Änderungen sind gewaltig. Erfahrenen Vert.x-Usern sollte der Wechsel dennoch leicht fallen. Und es lohnt sich. Zwar schmerzt mich der Verlust des Modulsystems und ich vermisse die Scala-Unterstützung (folgt in 3.1), aber das Arbeiten macht einen riesen Spaß. Ich freue mich schon auf die ersten Projekte mit Vert.x 3 und kann jedem empfehlen, zumindest mal einen Blick zu riskieren.Und wer es genauer wissen möchte, kann einfach bei meinem Talk auf der W-JAX 2015 vorbei schauen.

Aufmacherbild: Abstract background von Shutterstock / Urheberrecht: Nik Merkulov

 

 

Verwandte Themen:

Geschrieben von
Jochen Mader
Jochen Mader
Jochen Mader ist Lead IT Consultant bei der codecentric AG, Autor verschiedener Fachartikel und generell an allem interessiert, was Softwareentwicklung spannend macht. Auf Twitter findet man ihn unter dem Handle @codeptibull
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.