Quarkus verspricht sagenhafte Performancegewinne. Der Einstieg ist einfach, da Quarkus wie eine Sammlung bereits bekannter Frameworks erscheint. Doch Quarkus wurde speziell für den Einsatz im Container und in der Cloud entwickelt. Hohe Performance und geringer Ressourcenverbrauch stehen im Focus.
Quarkus bietet einen ähnlichen Funktionsumfang wie die Platzhirsche Spring-Boot und Java-EE (jetzt Jakarta-EE). Es ist jedoch nicht das Ziel von Quarkus, die etablierten Frameworks verdrängen. Es gibt keinen vorgezeichneten Migrationspfad von Java-EE oder Spring nach Quarkus. In den meisten Fällen dürfte eine Migration so teuer sein, dass sie den Nutzen bei weitem überschreitet. Quarkus ist vielmehr angetreten, um neue Nischen zu besetzen.
Die Welt der Java-Entwickler hat sich geändert. Als Spring Boot, und erst recht Java-EE, entworfen wurden, sah die typische Laufzeitumgebung noch ganz anders aus als heute. Es gab keine Cloud. Dafür war es populär die UI mit Java zu entwickeln. Bis vor einigen Jahren galten JavaScript, HTML und CSS als schwierig. Ein sehr großer Teil der Java-Entwickler fühlte sich in diesen Bereichen nicht sattelfest. Das machte Java-zentrierte UIs wie Java-Server-Faces (JSF), Spring MVC oder GWT (ehem. Google Web-Toolkit) populär. Spring und Java-EE mussten den gesamten Bereich vom Frontend bis hin zur Datenbank abdecken.
The Brave New World für Java-Entwickler
Heute sieht die Situation ganz anders aus. Die Branche hat sich differenziert. In vielen Firmen hat sich eine Arbeitsteilung etabliert: Java-Entwickler kümmern sich um die Business-Aufgaben im Backend, während das Frontend die Domäne der JavaScript-Entwickler ist. In der Backend-Entwicklung wiederum findet gerade eine Revolution statt. Der Megatrend Cloud-Computing wirbelt die Welt der Java-Entwickler gründlich durcheinander, zum Beispiel:
- Docker gehört nun zum Entwickleralltag.
- Mit Docker laufen Java-Programme typischerweise unter Linux.
- Application-Server, auf denen mehrere Anwendungen gleichzeitig laufen, wurden durch leichtgewichtigere Spring-Boot-Services abgelöst.
- Neue Serverless-Ansätze wie AWS-Lamda und Azure- sind noch leichtgewichtiger.
- Microservices führ zu einer zunehmenden Arbeitsteilung.
Das alles ist sehr spannend und aufregend, bringt jedoch ganz neue Ebenen an Komplexität mit sich. Der Wunsch nach Vereinfachungen wird laut.
Der Aufstieg der Micro-Frameworks
Eine ganze Reihe neuer Frameworks springt in die Bresche. Sie bezeichnen sich als Micro-Frameworks, weil sie sich auf bestimmte Aspekte der Softwareentwicklung konzentrieren. Während Spring-Boot noch ein Full-Stack-Framework war, liefern Micro-Frameworks nur noch einen Teil dieser Funktionalität. Bei den Micro-Frameworks sind das die Funktionen, die für Microservices ohne UI benötigt werden. MicroProfile, Helidon, Micronaut, Spark, Javalin und Ktor sind einige Micro-Frameworks, die auf dem Radar auftauchen. Und natürlich Quarkus.
Altbekannte Frameworks neu kombiniert
Eine für die Einarbeitung sehr angenehme Eigenschaft von Quarkus ist, dass es auf den ersten Blick wenig Neuerungen bringt. Im Werkzeugkasten1 auf der Quarkus-Homepage finden wir unter anderem Hibernate, JAX-RS, CDI, Bean-Validation, Flyway und Liquibase sowie Apache-Kafka. Viele Java-Enwickler haben mit diesen oder ähnlichen Bibliotheken schon gearbeitet. Das sorgt für einen stressfreien Start. Es gibt auch Support für Spring. Konkret werden Spring-Core, Spring-Data, Spring-Web, Spring-Security und ein Teil von Spring-Boot unterstützt. Es handelt sich um einen Kompatibilitäts-Layer; in der Praxis sind daher Einschränkungen zu erwarten. Die Botschaft ist aber auch hier klar: Wer Spring kennt, sollte sich schnell mit Quarkus wohlfühlen. Weniger bekannt sind die reaktiven Frameworks von Quarkus: Vert.x und Smallrye. Darauf wird später nochmal eingegangen. Beide sind schon seit einigen Jahren auf dem Markt. Mit anderen Worten: Quarkus bringt viele bekannte Frameworks zusammen. Auf der Homepage von Quarkus lässt sich ein Beispielprojekt generieren. Es ist ein klassisches Maven- oder Gradle-Projekt ohne große Überraschungen (Abb. 1). Die APIs sind also nicht das Alleinstellungsmerkmal von Quarkus. Was ist es stattdessen?
Typischer Aufbau einer Quarkus-Anwendung (Abb. 1)
Container-First Ansatz
Einige Neuerungen fallen im Screenshot doch auf: der Ordner Docker, zwei Dateien mit der Bezeichnung native im Namen und das Maven-Plugin von Quarkus. Auf den zweiten Blick fällt noch auf, dass anstelle der Standardbibliotheken Quarkus-Versionen von RESTEasy, JUnit, Hibernate usw. verwendet werden. Quarkus wurde für den Einsatz im Container und in der Cloud entwickelt. Daraus leiten sich verschiedene Optimierungsziele ab. Es sind die Dauerbrenner Performance, Speicherverbrauch und Kosten – jetzt aber mit anderen Schwerpunkten:
- Im Bereich Performance gewinnt die Dauer eines Kaltstarts an Bedeutung. Die Peak-Performance ist relevant bei Anwendungen, die mehrere Minuten oder Stunden laufen. Beim Einsatz in der Cloud ist das aber gar nicht mehr die Regel. Um Kosten zu sparen, werden Container schnell herunter- und nur bei Lastspitzen wieder hochgefahren. Besonders augenfällig wird das bei AWS-Lambdas und Azure-Functions. Wird die Funktion einige Minuten nicht aufgerufen, bedeutet der nächste Aufruf einen Kaltstart.
- Mit Speicherverbrauch ist nicht mehr der Heap-Memory gemeint, sondern der gesamte Speicher, den der Container braucht. Die JVM und das Betriebssystem gehören dazu.
- In der Cloud bestimmen sowohl die Rechenleistung als auch der Speicherbedarf die Kosten. Die Rechenleistung ist bei typischen Enterprise-Anwendungen sekundär: Es können jederzeit weitere Container hochgefahren werden. Damit wird, abhängig vom Preismodell des Cloudproviders, oft der Hauptspeicher zum primären Kostentreiber.
Native Anwendungen mit GraalVM
Quarkus verschiebt einen Teil der Aufgaben vom Anwendungsstart in die Kompilierphase. Das ist nicht zuletzt der GraalVM geschuldet. GraalVM bietet einen Ahead-of-Time-Compiler (AOT-Compiler). Dieser Compiler erzeugt Maschinencode, der von der CPU direkt ausgeführt werden kann. Das hat Vor- und Nachteile. Zu den Vorteilen gehört ein dramatisch beschleunigter Anwendungsstart. Zu den Nachteilen zählen eine langfristig schlechtere Performance und der Verzicht auf Reflection, was jedoch den Verzicht auf fast alle populären Java-Frameworks bedeute würde. Daher kann die GraalVM zur Compile-Zeit Metadaten erzeugen, mit deren Hilfe die Funktionalität der Reflection-API gerettet werden kann. Der Preis dafür sind erheblich längere Kompilierzeiten.
Ein weiterer Preis ist, dass sich die fertig kompilierte Anwendung zur Laufzeit nicht mehr ändern darf (Closed-World-Principle). In der Praxis ist das keine Einschränkung. Wenn eine Anwendung verändert werden soll, wird sie ohnehin neu kompiliert. Etwas anders sieht es bei einem traditionellen Application-Server aus. Dort konnten die WAR-Dateien zur Laufzeit installiert werden. Mit einem AOT-Compiler ist so etwas nicht möglich. Die Unterstützung des AOT-Compilers hat auch ein paar Nachteile.
Die Aufgaben der Quarkus-Extensions
Quarkus macht aus der Not eine Tugend. Wie bereits erwähnt, werden nicht direkt die gewohnten Frameworks verwendet, sondern speziell für Quarkus angepasste Versionen, wie Quarkus-Extensions. Die Erweiterung besteht darin, zur Kompilierzeit Metadaten zu sammeln und möglichst viele Aufgaben vom Anwendungsstart in die Kompilierzeit zu verschieben. Peter Palaga skizziert in seinem Vortrag2, wie das aussieht: Statt alle Beans bei jedem Anwendungsstart per Classpath-Scan zu suchen und per Reflection zu erzeugen, werden sie gleich beim Kompilieren in eine statische Hash-Table geschrieben. Damit sind sie sofort verfügbar und können schnell erzeugt werden. Je nach Scope können die Instanzen dieser Beans auch gleich erzeugt werden. Er beschreibt auch noch weitere Tricks, mit denen Quarkus den Start der Anwendung optimiert. Die statische Codeanalyse während der Kompilierzeit ermöglicht eine Art Tree-Shaking. Klassen, welche die Anwendung nicht benötigt, werden eliminiert. Das spart den Aufwand sie zu laden und zu initialisieren. Bei Spring-Boot und erst recht bei einem Application-Server macht das einen erheblichen Teil der Startzeit aus.
Enorme Performance mit GraalVM
Ein besonders raffinierter Trick wird nicht von Quarkus, sondern von der GraalVM implementiert. Sie führt statische Initializer bereits zur Kompilierzeit aus, nimmt einen Snapshot des so entstandenen Heap und kopiert ihn in das Executable3. Wenn die Anwendung später gestartet wird, brauchen die statischen Initializer damit nicht mehr ausgeführt werden. Das Ergebnis liegt ja bereits vor.
In praktisch allen Präsentationen zur GraalVM wird gezeigt, dass der Speicherverbrauch einer nativen, mit dem AOT-Compiler erzeugten Anwendung 80% bis 90% niedriger ist als der Speicherverbrauch einer traditionellen Anwendung mit JIT-Compiler. Das ist grundsätzlich korrekt, gilt in diesem Ausmaß aber nur für relativ kleine Anwendungen. Bytecode ist erheblich kompakter als Assembler-Code. Je größer eine Anwendung ist, desto geringer wird der Vorteil des AOT-Compilers, und irgendwann drehen sich die Verhältnisse auch um. Ähnlich wird es bei den Startzeiten sein. Bei den meisten Benchmarks startet die Anwendung dank des AOT-Compilers rund tausendmal schneller als mit dem JIT-Compiler4. Führt man aber eigene Programmlogik bei Programmstart aus, wird das Ergebnis weniger überzeugend sein. Der Grundsatz des AOT-Compilers lautet, dass man ein wenig Peak-Performance gegen schnelle Verfügbarkeit eintauscht. Das sollten man beim Anwendungsdesign berücksichtigen. Für die meisten Microservices, wenn sie denn wirklich micro sind, ist das Resumée aber tatsächlich: deutlich weniger Memory-Footprint, stark reduzierte Startzeiten, aber dafür wird das Programm niemals die Performance des JIT-Compilers erreichen. Konkrete Zahlen zu nennen ist sehr schwierig, da es erheblich von der jeweilige Aufgabe abhängt. In den meisten Fällen dürfte der JIT-Compiler jedoch rund zwei bis dreimal schneller sein.
Quarkus macht die Arbeit mit GraalVM einfacher. Wie in (Abb. 1) zu sehen, werden die Dateien zum Generieren eines nativen Executables von Quarkus standardmäßig erzeugt. Das manuelle Erstellen dieser Datei artet laut Peter Palaga5 dagegen schnell in eine endlose Liste von Parametern aus.
Performance im Vergleich
Bei dem auf GitHub6 verfügbaren Demoprojekt zu diesem Artikel handelt es sich um einen besonders kleinen Lambda-Service, der aber gerade deshalb die Unterschiede zwischen dem AOT-Compiler und dem JIT-Compiler besonders deutlich macht. Mit Java 8 und der traditionellen JVM dauert der erste Start spürbar lang.
> ./invoke-java-function.sh
Duration: 367.99 ms Billed Duration: 400 ms Memory Size: 128 MB Max Memory Used: 97 MB Init Duration: 1112.91 ms
Dafür ist der zweite und alle folgenden Funktionsaufrufe rund 1000 Mal schneller – so lange, bis der Lambda-Service nach einer Pause wieder herunterfährt.
> ./invoke-java-function.sh
Duration: 0.60 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 97 MB
Wenn der Lambda-Service dagegen nativ kompiliert wird, dauert der Aufruf immer rund eine Millisekunde.
./invoke-native-function.sh
Duration: 1.04 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 52 MB
Das ist auch in diesem einfachen Beispiel, in dem es kaum etwas zu optimieren gibt, nur halb so schnell wie die Peak-Performance des JIT-Compilers. Die Messung ist jedoch zuverlässig. Bei jedem Versuch lag die Performance im Bereich zwischen 0,9 bis 1,1 Millisekunden.
Wann lohnen sich langsamere Microservices?
Traditionell ist die CPU-Performance das Maß der Dinge. Speicher galt lange Zeit als billige Ressource. In der Cloud sieht das oft anders aus. Hier ist der Speicherverbrauch ein wesentlicher Kostentreiber. Der geringere Memory-Footprint einer nativen Anwendung erlaubt eine höhere Packungsdichte. Der Speicher, der vorher für einen einzigen Application-Server nötig war hat, reicht jetzt für eine ganze Schar von Containern. Wenn alle Container gleichzeitig gestartet werden, also bei horizontaler Skalierung, ist der Durchsatz größer als der Durchsatz des einen Application-Servers. Die gute Performance des JIT-Compilers kann das nicht ausgleichen.
Wann braucht man vorhersehbare Performance?
Manchmal kommt es auch gar nicht so sehr auf die Spitzengeschwindigkeit an. In Echtzeitsystemen ist das entscheidende Kriterium, dass das System garantiert in einer bestimmten Zeitspanne reagiert. Ein Beispiel dafür wäre eine in Java programmierte Motorsteuerung eines Autos. Der JIT-Compiler sorgt dafür, dass die CPU reichlich Leistungsreserven hat – mit Ausnahme des Kaltstarts. Java nimmt erst im Laufe der Zeit Fahrt auf. Für den Motor bedeutet das jede Menge Fehlzündungen. Womöglich sogar jedes Mal, wenn die Start-Stopp-Automatik an der Ampel den Motor ausschaltet. Der AOT-Compiler sorgt dagegen für eine vorhersagbare Performance. Sie mag etwas geringer sein, aber vor allem ist sie konstant. Die Motorsteuerung hat nicht mehr so viel Leistungsreserven, aber darauf kommt es in diesem Fall gar nicht an. Entscheidend ist, dass sie keine Fehlzündungen erzeugt.
Quarkus ohne GraalVM
Auch ohne GraalVM profitiert man beim Kompilieren von den Features von Quarkus. Anwendungen starten auch mit dem klassischen JIT-Compiler i.d.R. deutlich schneller, in unseren Beispielen um den Faktor zwei bis drei. Ein weiteres hilfreiches Feature von Quarkus ist das Hot-Module-Reloading. Dazu startet man Quarkus im Entwicklungsmodus, indem man ein Terminal öffnet und auf der Kommandozeile den Befehl ./mvnw compile quarkus:dev eingibt. Anschließend geht man genauso vor wie zum Beispiel bei Angular: Quellcode editieren, beim Speichern wird automatisch kompiliert und beim Aktualisieren des Browsers wird der neue Code ausgeführt. Kurioserweise handelt es sich um ein sehr altes Feature, das bereits in Java 1.4 enthalten war. Seinerzeit hatte IBM einen Application-Server entwickelt, der ca. fünf bis zehn Minuten zum Starten brauchte. An ein flüssiges Entwickeln war damit nicht zu denken. Als Ausweg wurde das Hot-Code-Replacement erfunden. Das ermöglicht es der IDE, geänderte Quelltexte in das laufende Programm einzufügen. Der Zustand der Anwendung bleibt dabei erhalten. Dank Hot-Code-Replacement ist das Einloggen nach jeder Programmänderung bei einer komplexen Anwendung mit UI nicht notwendig. Leider funktioniert Hot-Code-Replacement nicht besonders gut mit Frameworks wie beispielsweise Spring. Spätestens mit dem Siegeszug der testgetriebenen Entwicklung und der Fokussierung auf Backend-Entwicklung geriet das Feature in Vergessenheit. Spring Boot startet so schnell, dass das Hot-Code-Replacement nicht mehr so wichtig ist. Quarkus startet noch etwas schneller. Bei umfangreichen Test-Suiten spielt das eine große Rolle. Vor allem Integrationstests laufen mit Quarkus rund doppelt so schnell.
Die richtige IDE für Quarkus
Der developer mode von Quarkus besteht aktuell aus einem Maven-Skript. Das Kommando ./mvnw compile quarkus:dev startet einen Prozess, der die Dateien im Quelltextverzeichnis überwacht und bei jeder Änderung neu kompiliert. Traditionell arbeiten IDEs wie zum Beispiel Eclipse anders. Im traditionellen Modell kümmert sich die IDE darum, dass die Anwendung kompiliert wird. Die geänderte Arbeitsweise hat einige Auswirkungen. Eine davon ist relativ überraschend, zumindest aus der Sicht eines Java-Entwicklers: Visual-Studio-Code ist ein hervorragender Editor für Quarkus. In der JavaScript-Welt, aus der Visual-Studio-Code kommt, hat es sich ohnehin weitgehend etabliert, den Compiler in einem Terminal-Fenster zu starten. Quarkus überträgt das gleiche Modell in die Java-Welt. Eclipse kann ebenfalls verwendet werden, es ist aber ein wenig mühsamer, weil Eclipse standardmäßig kein Terminalfenster mitbringt. IntelliJ dagegen bietet ein integriertes Terminal. Trotzdem lohnt es sich, Visual-Studio-Code in die engere Wahl zu nehmen: Sowohl Quarkus als auch das Java-Plugin von Visual-Studio-Code werden primär von Red Hat vorangetrieben. Beide sind gut aufeinander abgestimmt. Zum Debugging müssen in allen IDEs das remote Debugging verwendet werden. Das ist ein wenig lästig, funktioniert aber tadellos.
Reactive Programming mit Quarkus
In der JavaScript-Welt sind in den letzten Jahren die reaktive Programmierung und Non-Blocking-IO populär geworden. Quarkus überträgt diese Ideen in die Java-Welt und unterstützt sowohl imperative Programmteile als auch reaktive. Hinter der reaktiven Programmierung steckt die Idee, dass das Programm nicht blockiert, wenn auf das Ergebnis einer Datenbankabfrage oder einer REST-Calls gewartet wird. In der Zwischenzeit kann das Programm weiterlaufen und sich um andere Aufgaben kümmern. Sobald das Ergebnis da ist, wird eine Call-Back-Funktion aufgerufen. In Java sind das Lambda-Expressions. Der Unterschied wird in (Listing 1) gezeigt. Es handelt sich hierbei nicht um Quellcode, sondern um stark reduzierten Pseudocode. Das erste Beispiel ist JDBC-Code, welcher schon seit Java 5 bekannt ist:
(Listing 1)
Das Programm hält so lange an, bis die Datenbankabfrage ein Ergebnis zurückliefert. Viel schöner wäre es, wenn mehrere Datenbankabfragen parallel abgeschickt werden könnten. Reactive-Programming macht das möglich:
(Listing 2)
In diesem Fall ist der Code, der die Daten verarbeitet, nicht mehr direkt in der nächsten Zeile. Hinter dem Aufruf der Methode query() folgt ein Lambda, das asynchron aufgerufen wird, wenn die Daten da sind. In der Zwischenzeit läuft die Anwendung weiter und könnte weitere Abfragen starten. Deswegen liefert die Methode auch keine Liste. Das Uni<List> ist lediglich ein Versprechen, demnächst eine List zu bekommen.
Die reaktive Programmierung erfordert ein Umdenken. Was passiert zum Beispiel, wenn in der Callback-Methode wiederum eine Datenbankabfrage passiert? Dann würde ein Versprechen auf ein Versprechen zurückgeliefert. Das erfordert etwas Übung. Quarkus erleichtert den Einstieg, indem es beide Programmierstile zulässt.
Reactive Programming weitergedacht
Im Prinzip könnte der Datenbanktreiber auch einen Datenstrom schicken. Anders ausgedrückt: Er könnte bereits anfangen, das Ergebnis der Abfrage zu schicken, wenn er erst einen Teil der Daten gelesen hat. Der Rest der Daten kommt später und wird ebenfalls über das Lambda verarbeitet. Datenbankbetreiber, die dieses Feature bereits beherrschen, sind dem Autor nicht bekannt.
Bei vielen anderen Systemen, wie zum Beispiel Kafka ist das bereits heute Standard. Ein Anwendungsfall ist ein Chat-Programm, das den ganzen Tag im Hintergrund läuft und sofort reagiert, wenn eine Nachricht ankommt. Wenn die Architektur so konzipiert ist, dass die Daten als kontinuierlicher Strom von Ereignissen kommen, ist die asynchrone Verarbeitung in einer Callback-Methode die einfachste Lösung.
Reaktive Programmierung hat noch weitere Vorteile. Wenn die Datenbank sehr groß ist und der Datenbanktreiber mitspielt, kann die Callback-Methode bereits aufgerufen werden, wenn erst ein Teil der Daten verfügbar ist. Die Callback-Methode wird mehrfach aufgerufen. Immer dann, wenn weitere Daten ankommen.
Java-Programme mit Quarkus als AWS-Lambda deployen
Auf Quarkus.io7 findet sich ein Tutorial das zeigt, wie die Unterstützung von Quarkus aussehen kann. Das Beispielprojekt wird im wesentlichem durch ein Maven-Archetype erzeugt und enthält einige Skripte, um einen Amazon Lambda-Service mit wenigen Handgriffen zu deployen – oder auch lokal zu testen. Das erleichtert den Einstieg in die Technik deutlich. Vor allem ist es mit den Skripten sehr einfach, ein native kompiliertes Java-Programm als Lambda zu deployen. Die gleiche Anwendung mit Shell-Skripten, welche die Arbeit noch etwas weiter vereinfachen, kann man auf GitHub-Repository8 ansehen. Der erste Eindruck ist positiv. Der Maven-Archetype liefert die Konfiguration von SAM mit, so dass die Lambda-Funktion lokal getestet werden kann. Die Shell-Skripte erlauben sowohl das Deployment einer traditionellen JAR-Datei als auch das Deployment einer nativen Binärdatei. Dafür wird GraalVM als Docker-Image heruntergeladen. Der AOT-Compiler braucht also nicht lokal installiert zu werden. Das ist praktisch, bedeutet aber auch, dass es etwas länger dauert.
Die native Kompilierung zeigt am deutlichsten, dass der AWS Lambda-Support noch im Preview-Stadium ist. Neben den unangenehm langen Kompilierzeiten fielen in der Version 1.3.2 teilweise kryptische Fehlermeldungen unangenehm auf. Die langen Laufzeiten liegen allerdings in der Natur der Sache. Die statische Code-Analyse des AOT-Compilers und die Analyse der Reflection dauern einige Zeit. Die Erzeugung der nativen Images wird am besten in einen Jenkins-Job ausgelagert, der asynchron nach dem Einchecken der Quelltexte läuft.
Fazit:
Auf den ersten Blick ist es gar nicht so einfach zu sagen, was Quarkus ausmacht. Fast alles, was einem in den Tutorials begegnet, ist vertraut. Allenfalls das reaktive Programmieren mit Vert.x und Smallrye mag ungewohnt sein. Das eigentlich Neue an Quarkus ist, dass es all diese vertrauten Frameworks auf eine neue Weise zusammenbringt. Die Magie liegt in der Build-Pipeline. Quarkus hat den Build-Prozess für viele Frameworks so optimiert, dass sie besonders gut mit dem AOT-Compiler von GraalVM harmonieren. Und das wiederum ist ein großer Vorteil in der Cloud, wo Container häufig hoch- und runtergefahren werden.
Auch jenseits der Cloud hat Quarkus ein paar Vorteile. Der Anwendungsstart ist deutlich schneller, und das fällt in vielen Situationen auf. Unit-Tests laufen schneller, und das gilt insbesondere für Integrationstests. Natürlich hat auch Quarkus ein paar Eigenheiten und Nachteile. Die IDE wird auf die Rolle eines Editors reduziert. Der Compiler läuft in einem separaten Fenster und Debugging ist nur über Remote-Debugging möglich. Für Softwareentwicklers ist aber noch etwas wichtig: Der Entwicklermodus von Quarkus bringt das Hot-Module-Reloading in die Java-Welt. Dies ist bereits seit Java 1.4 mit dem Hot-Code-Replacement bekannt, also bereits seit 18 Jahren. Allerdings ist dieses Feature meistens nicht mehr zugänglich. Es spricht einiges dafür, dass Quarkus im Bereich Cloud-Computing seine Nische finden und uns noch viele Jahre begleiten wird.
[1] https://bit.ly/quarkus-c1
[2] Peter Palaga, „Quarkus from Inside“: https://bit.ly/palaga-p2
[3] Peter Palaga, „Quarkus from Inside“: https://bit.ly/palaga-p3
[4] Unterschied JIT- und AOT-Compiler: https://bit.ly/graalvm-u4
[5] Peter Palaga, „Quarkus from Inside“: https://bit.ly/palaga-p5
[6] Demoproject auf GitHub: https://bit.ly/github-g
[7[ Tutorial Quarkus: https://bit.ly/tutorial-t7
[8] GitHub-Repository: https://bit.ly/github-g
Stephan Rauh ist Architekt, Entwickler und Trainer mit viel Freude an Presales und Marketing. Er pendelt regelmäßig zwischen der Java-Welt und dem Java-Script-Universum. In der Open-Source-Scene hat er sich einen Namen durch Projekte wie BootsFaces und ngx-extended-pdf-viewer gemacht. Außerdem betreibt er den Blog BeyondJava.net, wo er aktuell eine große Serie über die GraalVM und Quarkus schreibt.
Blog | Twitter | GitHub | E-Mail