Einführung in Quarkus: Warum Java-Entwickler auf Supersonic Java umsteigen
Seit fast drei Jahrzehnten ist Java die dominierende Kraft in der Entwicklung von Unternehmenssoftware. Sein reichhaltiges Ökosystem, die robuste objektorientierte Grundlage, die Plattformunabhängigkeit über die Java Virtual Machine (JVM) und kampferprobte Frameworks wie Spring Boot machten es zum unbestrittenen König der Backend-Infrastruktur.
Allerdings hat die Umstellung auf Cloud-Native-Architekturen, Kubernetes-Orchestrierung, Containerisierung (Docker) und Serverless Computing (AWS Lambda, Knative) eine schwerwiegende Schwachstelle in traditionellen Java-Anwendungsframeworks aufgedeckt: hoher Speicheraufwand und langsame Startzeiten.
Wenn ein Mikroservice als Reaktion auf einen Datenverkehrsanstieg horizontal von null auf 100 Replikate skaliert werden muss oder wenn eine serverlose Funktion bei Bedarf ausgeführt wird, ist es inakzeptabel, 3 bis 10 Sekunden auf den Start eines Java-Prozesses zu warten. Moderne Cloud-Infrastrukturen erfordern einen sofortigen Start und einen geringen Speicherverbrauch – Eigenschaften, die traditionell Sprachen wie Go, Rust oder Node.js vorbehalten sind.
Hier kommt Quarkus ins Spiel: ein Kubernetes-natives Java-Framework, das speziell für GraalVM und OpenJDK HotSpot entwickelt wurde. Quarkus wird oft als „Supersonic Subatomic Java“* bezeichnet und entwickelt die Art und Weise, wie Java-Anwendungen kompiliert, gestartet und ausgeführt werden, grundlegend neu.
In diesem ausführlichen Leitfaden werden wir untersuchen, warum Java-Entwickler sich für Quarkus entscheiden, wie Quarkus Startzeiten von weniger als einer Sekunde und einen Mikrospeicherbedarf erreicht, die architektonischen Mechanismen der Build-Time-Optimierung und wie man mit Quarkus einen produktionsbereiten reaktiven Mikroservice in Java erstellt.
1. Das Cloud-Native-Dilemma des traditionellen Java
Um zu verstehen, warum Quarkus existiert, müssen wir untersuchen, wie traditionelle Java-Frameworks wie Spring Boot oder Jakarta EE unter der Haube funktionieren.
A. Die hohen Kosten für die Laufzeitinitialisierung
Herkömmliche Java-Frameworks basieren stark auf dynamischer Laufzeitreflexion, Klassenpfad-Scanning und Proxy-Generierung:
- Klassenpfad-Scannen: Während des Startvorgangs scannt die JVM jede JAR-Datei im Klassenpfad, um Annotationen wie
@Component,@Service,@Controlleroder@Entityzu erkennen. - Annotationsverarbeitung und Reflexion: Das Framework verwendet Reflexion (
Class.forName(),getDeclaredFields()), um ein speicherinternes Diagramm von Beans, Konfigurationseigenschaften und Abhängigkeiten zu erstellen. - Dynamische Proxy-Erstellung: CGLIB oder ByteBuddy generiert dynamische Bytecode-Proxys im Laufzeitspeicher, um aspektorientierte Programmierung (AOP), Datenbanktransaktionsverwaltung (
@Transactional) und Sicherheitsgrenzen zu unterstützen. - Metaspace- und RSS-Inflation: Alle Metadaten, reflektierten Klassendeskriptoren und generierten Proxys müssen im Speicher innerhalb des Metaspace und der Resident Set Size (RSS) der JVM aufbewahrt werden.
Diese Laufzeitreflexionsschleife erfordert erhebliche CPU-Zyklen und erhöht den Heap-Speicherverbrauch. Ein einfacher CRUD-REST-Dienst in herkömmlichem Java kann im Leerlauf leicht 140 MB bis 300 MB RAM verbrauchen und 3 bis 8 Sekunden zum Starten benötigen.
B. Die finanzielle Strafe im Cloud Computing
In serverlosen und Container-Umgebungen berechnen Cloud-Anbieter ihre Gebühren auf der Grundlage von zwei Metriken: zugewiesener Speicher (GB) und Ausführungsdauer (Millisekunden).
- Kaltstarts: Wenn der Start einer serverlosen Funktion 5 Sekunden dauert, erleben Endbenutzer eine spürbare Latenz und Sie zahlen für 5 Sekunden Startberechnung im Leerlauf.
- Dichte und Pod-Skalierbarkeit: In einem Kubernetes-Cluster mit einem Worker-Knoten mit 16 GB RAM können Sie nur ca. 40 herkömmliche Spring Boot-Mikroservice-Instanzen ausführen, bevor Ihnen der Arbeitsspeicher ausgeht. Wenn jede Instanz nur 15 MB RAM verbrauchen würde, könnte derselbe Knoten über 800 Instanzen hosten.
2. Quarkus-Architektur: Verlagerung der Arbeit von der Laufzeit zur Build-Zeit
Quarkus löst das Cloud-Native-Dilemma durch einen radikalen architektonischen Paradigmenwechsel: Verlagerung dynamischer Vorgänge von der Laufzeit zur Build-Zeit.
Build-Time-Verarbeitung (Ahead-Of-Time-Optimierung)
Anstatt jedes Mal, wenn die Anwendung startet, Klassenpfad-Scanning, Annotations-Parsing und Bean-Graph-Verknüpfung auszuführen, führt Quarkus alle diese umfangreichen Vorgänge einmal während der Build-Phase (mvn package oder ./gradlew build) aus.
- Erweiterungsarchitektur und Erstellungsschritte: Quarkus verwendet ein steckbares Erweiterungsframework. Beim Kompilieren Ihrer Anwendung analysieren Quarkus-Erweiterungen Anmerkungen, generieren optimierten statischen Bytecode und lösen Abhängigkeitsinjektionsdiagramme im Voraus auf.
- Vorgefertigte Metadaten: Alle Dependency-Injection-Metadaten werden vorberechnet. Wenn die Anwendung gestartet wird, instanziiert Quarkus direkt vorkompilierte Klassen, ohne Reflektion aufzurufen oder Klassenpfade zu scannen.
- Beseitigung von totem Code (Tree Shaking): Während des Erstellungsprozesses identifiziert Quarkus Klassen, Methoden und Bibliotheken, die von Ihrer Anwendung nicht verwendet werden, und entfernt sie vollständig.
Bis die JAR- oder native Binärdatei Ihrer Anwendung erstellt ist, ist der gesamte Laufzeitaufwand beseitigt. Die JVM lädt einfach vorverdrahtete statische Bytecodes und startet sofort.
3. GraalVM Native Image vs. OpenJDK HotSpot
Quarkus bietet ein duales Ausführungsmodell: Es läuft außergewöhnlich schnell auf dem standardmäßigen OpenJDK HotSpot, erreicht aber sein maximales Leistungspotenzial, wenn es in ein GraalVM Native Image kompiliert wird.
+-----------------------------------------------------------------------+
| Java Source Code (.java) |
+-----------------------------------------------------------------------+
|
v (Standard javac)
+-----------------------------------------------------------------------+
| Bytecode (.class) |
+-----------------------------------------------------------------------+
/ \
/ \
v v
+----------------------------------+ +----------------------------------+
| OpenJDK HotSpot JVM | | GraalVM Native Image (AOT) |
| - JIT Compilation (C1/C2) | | - Substrate VM |
| - Dynamic Class Loading | | - No Classpath Scanning |
| - Fast throughput, longer boot | | - Millisecond boot, tiny RAM |
+----------------------------------+ +----------------------------------+
Ahead-of-Time (AOT)-Kompilierung und Substrat-VM
GraalVM Native Image nimmt Java-Bytecode und kompiliert ihn direkt in eine betriebssystemspezifische, eigenständige ausführbare Binärdatei (ELF-Binärdatei unter Linux, Mach-O unter macOS, EXE unter Windows).
- Annahme einer geschlossenen Welt: GraalVM geht davon aus, dass alle erreichbaren Codes, Klassen und Ressourcen zum Zeitpunkt der Erstellung bekannt sind.
- Substrate VM: Die native ausführbare Datei bettet eine Miniatur-Laufzeit-Engine namens Substrate VM ein, die die Speicherverwaltung, Thread-Planung und Garbage Collection übernimmt, ohne eine vollständige JVM-Instanz zu starten.
- Kein Reflexions-Overhead: Da Quarkus Reflexionskonfigurationen und Proxy-Definitionen während der Build-Zeit vorbereitet, gelingt die Kompilierung nativer GraalVM-Images reibungslos ohne die manuellen Konfigurationsdateien, die früher für native GraalVM-Builds erforderlich waren.
4. Leistungsbenchmarks: Die empirische Evidenz
Um den starken Leistungsunterschied zu veranschaulichen, untersuchen wir branchenübliche Benchmark-Vergleiche für drei Java-Laufzeitkonfigurationen, auf denen ein standardmäßiger REST- und Datenbank-CRUD-Dienst ausgeführt wird:
- Traditioneller Cloud-Native-Stack (Traditionelle JVM/Spring Boot)
- Quarkus auf OpenJDK HotSpot
- Quarkus auf GraalVM Native Image
Leistungsübersichtstabelle
| Metrisch | Traditioneller Stack (JVM) | Quarkus (HotSpot-JVM) | Quarkus (GraalVM Native) |
|---|---|---|---|
| REST-RSS-Speicher | ~140 MB | ~74 MB | ~13 MB |
| REST + CRUD RSS-Speicher | ~218 MB | ~112 MB | ~35 MB |
| REST-Startzeit | ~4,3 Sekunden | ~0,98 Sekunden | ~0,014 Sekunden (14 ms) |
| REST + CRUD-Startzeit | ~9,5 Sekunden | ~2,0 Sekunden | ~0,042 Sekunden (42 ms) |
| Ausführbares Artefakt | Großes Fat JAR (~50 MB) | Optimiertes JAR (~20 MB) | Eigenständige native Binärdatei (~30 MB) |
Beachten Sie, dass Quarkus, das zu einem nativen Image kompiliert wurde, in 14 Millisekunden startet – schneller als ein einziger Wimpernschlag – und lediglich 13 MB RAM verbraucht. Dadurch ist Java für serverlose und Cloud-native Bereitstellungen voll konkurrenzfähig zu Go und Rust.
5. Reaktive und imperative Dual-Core-Engine
Historisch gesehen mussten Java-Entwickler zwischen zwei sich gegenseitig ausschließenden Programmiermodellen wählen:
- Imperativ (Thread-pro-Anfrage): Einfacher, lesbarer Blockierungscode mit Standard-JDBC-Treibern und synchronen REST-Endpunkten.
- Reaktiv (Ereignisschleife): Asynchroner, nicht blockierender Code (z. B. RxJava, Project Reactor), der einen hohen Durchsatz ermöglicht, aber für komplexe Rückrufketten und schwieriges Debuggen bekannt ist.
Quarkus vereint beide Welten unter einer einzigen, zusammenhängenden Engine, die von Eclipse Vert.x und Netty angetrieben wird.
+---------------------------------+
| Client HTTP Request |
+---------------------------------+
|
v
+---------------------------------+
| Eclipse Vert.x I/O |
| (Event Loop) |
+---------------------------------+
/ \
/ \
v v
+-------------------+ +-------------------+
| Reactive Endpoint | |Blocking Endpoint |
| (Event Loop) | | (Worker Thread) |
| - Mutiny (Uni/Multi)| | - Standard JDBC |
| - Non-blocking | | - Imperative Code |
+-------------------+ +-------------------+
In Quarkus ist nicht blockierender I/O die Grundlage. Wenn Sie herkömmlichen Blockierungscode schreiben, leitet Quarkus die Ausführung automatisch an einen verwalteten Worker-Thread-Pool weiter. Wenn Sie reaktive Typen wie SmallRye Mutiny (Uni<T> und Multi<T>) verwenden, bleibt die Ausführung im leistungsstarken, nicht blockierenden Ereignisschleifen-Thread.
6. Entwicklerfreude: Live-Codierung und Entwicklungsdienste
Über die Laufzeitleistung hinaus bietet Quarkus ein revolutionäres Entwicklererlebnis, das darauf ausgelegt ist, die mühsame Feedbackschleife beim Erstellen, Testen und Neustarten zu eliminieren.
A. Live-Codierung ohne Neustart (quarkus:dev)
Beim Ausführen von mvn quarkus:dev startet Quarkus den Live-Coding-Modus. Sie können Java-Dateien bearbeiten, Eigenschaften ändern, HTML-Vorlagen ändern oder Datenbankschemata aktualisieren.
Wenn Sie das nächste Mal eine HTTP-Anfrage in Ihrem Browser oder Terminal auslösen, erkennt Quarkus die Dateiänderungen, wendet die Build-Schritte erneut an und lädt die Anwendung in weniger als 500 Millisekunden im laufenden Betrieb neu. Sie müssen Ihren Anwendungsserver während der Entwicklung nie manuell stoppen und neu starten.
B. Quarkus Dev Services (Testcontainer ohne Konfiguration)
Um einen Microservice mit einer PostgreSQL-Datenbank, einem Kafka-Broker oder einem Redis-Cache zu verbinden, müssen in der Regel eine docker-compose.yml-Datei geschrieben und lokale Datenbankports konfiguriert werden.
Mit Quarkus Dev Services:
- Wenn Quarkus eine Datenbankabhängigkeit erkennt (z. B.
quarkus-reactive-pg-client), aber inapplication.propertieskeine Datenbank-URL konfiguriert ist, startet Quarkus automatisch einen Docker-Container, auf dem PostgreSQL über Testcontainer im Hintergrund ausgeführt wird. - Es fügt Verbindungsanmeldeinformationen automatisch in Ihre laufende Anwendung ein.
- Wenn Sie den Entwicklungsmodus beenden, bereinigt sich der Container selbst sauber.
7. Praktische Komplettlösung: Aufbau eines produktionsbereiten reaktiven Quarkus-Dienstes
Erstellen wir einen sauberen, leistungsstarken Quarkus-Mikroservice in Java, der mithilfe von Hibernate Reactive with Panache eine REST-API bereitstellt, die mit einer PostgreSQL-Datenbank verbunden ist.
Schritt 1: Projektabhängigkeiten (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>com.ghaznix.quarkus</groupId>
<artifactId>user-service</artifactId>
<version>1.0.0-SNAPSHOT</version>
<properties>
<compiler-plugin.version>3.13.0</compiler-plugin.version>
<maven.compiler.release>21</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
<quarkus.platform.version>3.15.1</quarkus.platform.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>${quarkus.platform.artifact-id}</artifactId>
<version>${quarkus.platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- RESTEasy Reactive for high-performance HTTP endpoints -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive-jackson</artifactId>
</dependency>
<!-- Hibernate Reactive with Panache for active-record data access -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-reactive-panache</artifactId>
</dependency>
<!-- Reactive PostgreSQL Driver -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-reactive-pg-client</artifactId>
</dependency>
<!-- Quarkus SmallRye OpenAPI / Swagger UI -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-openapi</artifactId>
</dependency>
<!-- Testing -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>${quarkus.platform.version}</version>
<executions>
<execution>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Schritt 2: Definieren Sie die reaktive Entität (UserEntity.java)
Quarkus vereinfachte den Datenzugriff mit Panache, einer Active-Record-Musterimplementierung zusätzlich zu Hibernate.
package com.ghaznix.quarkus.entity;
import io.quarkus.hibernate.reactive.panache.PanacheEntity;
import io.smallrye.mutiny.Uni;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import java.time.Instant;
@Entity
@Table(name = "users")
public class UserEntity extends PanacheEntity {
@NotBlank(message = "Username cannot be blank")
@Column(unique = true, nullable = false)
public String username;
@Email(message = "Email must be valid")
@Column(unique = true, nullable = false)
public String email;
@Column(nullable = false)
public String role;
@Column(name = "created_at", nullable = false, updatable = false)
public Instant createdAt = Instant.now();
/**
* Helper method to find a user reactively by email.
*/
public static Uni<UserEntity> findByEmail(String email) {
return find("email", email).firstResult();
}
}
Schritt 3: Implementieren Sie die reaktive REST-Ressource (UserResource.java)
Mit RESTEasy Reactive und SmallRye Mutiny arbeiten unsere HTTP-Endpunkte vollständig asynchron auf nicht blockierenden Threads:
package com.ghaznix.quarkus.resource;
import com.ghaznix.quarkus.entity.UserEntity;
import io.quarkus.hibernate.reactive.panache.Panache;
import io.smallrye.mutiny.Uni;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.validation.Valid;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import java.net.URI;
import java.util.List;
@Path("/api/v1/users")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@ApplicationScoped
public class UserResource {
@GET
public Uni<List<UserEntity>> getAllUsers() {
return UserEntity.listAll();
}
@GET
@Path("/{id}")
public Uni<Response> getUserById(@PathParam("id") Long id) {
return UserEntity.<UserEntity>findById(id)
.onItem().ifNotNull().transform(user -> Response.ok(user).build())
.onItem().ifNull().continueWith(() -> Response.status(Response.Status.NOT_FOUND).build());
}
@POST
public Uni<Response> createUser(@Valid UserEntity user) {
return Panache.withTransaction(user::persist)
.replaceWith(() -> Response.created(URI.create("/api/v1/users/" + user.id))
.entity(user)
.build());
}
@DELETE
@Path("/{id}")
public Uni<Response> deleteUser(@PathParam("id") Long id) {
return Panache.withTransaction(() -> UserEntity.deleteById(id))
.map(deleted -> deleted
? Response.noContent().build()
: Response.status(Response.Status.NOT_FOUND).build());
}
}
Schritt 4: Anwendungskonfiguration (application.properties)
# Quarkus Application Configuration
quarkus.application.name=user-service
quarkus.http.port=8080
# Database Schema Management (Automatically managed by Dev Services in dev mode)
quarkus.hibernate-orm.database.generation=drop-and-create
quarkus.hibernate-orm.log.sql=true
# SmallRye OpenAPI & Swagger UI Configuration
quarkus.smallrye-openapi.path=/swagger-ui
quarkus.swagger-ui.always-include=true
Beachten Sie, dass wir keine Datenbank-URLs, Benutzernamen oder Passwörter konfiguriert haben! Wenn Sie ./mvnw quarkus:dev ausführen, erkennt Quarkus automatisch PostgreSQL, startet einen Docker-Container, richtet Datenbankschematabellen ein und öffnet die Swagger-Benutzeroberfläche bei http://localhost:8080/swagger-ui.
Schritt 5: Erstellen und Ausführen nativer ausführbarer Dateien
So führen Sie den sofortigen Live-Coding-Entwicklungsmodus aus:
./mvnw quarkus:dev
So erstellen Sie eine native Linux-Binärdatei mit GraalVM in einem Docker-Container (keine lokale GraalVM-Installation erforderlich):
./mvnw package -Dnative -Dquarkus.native.container-build=true
So starten Sie die resultierende Binärdatei direkt auf Ihrem Betriebssystem:
./target/user-service-1.0.0-SNAPSHOT-runner
__ ____ __ _____ ___ __ ____ ______
--/ __ \/ / / / _ | / _ \/ //_/ / / / __/
-/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/
2026-08-26 01:37:15,102 INFO [io.quarkus] (main) user-service 1.0.0-SNAPSHOT native (powered by Quarkus 3.15.1) started in 0.016s. Listening on: http://0.0.0.0:8080
2026-08-26 01:37:15,103 INFO [io.quarkus] (main) Profile prod activated.
2026-08-26 01:37:15,103 INFO [io.quarkus] (main) Installed features: [cdi, hibernate-reactive, panache, reactive-pg-client, resteasy-reactive, resteasy-reactive-jackson, smallrye-openapi]
0,016 Sekunden Start!
8. Strategischer Funktionsvergleich: Quarkus vs. Spring Boot
| Fähigkeit/Funktion | Traditioneller Spring Boot 3.x | Quarkus 3.x |
|---|---|---|
| Primäre Architektur | Laufzeitreflexion und dynamisches Scannen | Build-Time-Verarbeitung und AOT-Optimierung |
| Native Zusammenstellung | Spring Native (erfordert komplexe Hinweise) | Erstklassige native GraalVM-Integration |
| Startgeschwindigkeit (nativ) | ~0,1 - 0,5 s | ~0,01 - 0,04 s |
| Speicher-RSS-Footprint | 140 MB – 300 MB | 13 MB - 40 MB |
| Entwicklungsumgebung | Hot-Swapping über DevTools (begrenzt) | Live-Codierung ohne Neustart (quarkus:dev) |
| Dienste von Drittanbietern | Manuelle Docker-/Testcontainer-Konfiguration | Automatische Entwicklungsdienste (Zero-Config-Container) |
| Standardunterstützung | Spezifisch für das Frühlingsökosystem | Jakarta EE- und MicroProfile-Standardspezifikationen |
| Reaktives Paradigma | Spring WebFlux (separater Stapel) | Einheitliche Engine (Vert.x Core / Reactive + Imperative) |
9. Fazit: Ist es Zeit, zu Quarkus zu wechseln?
Quarkus ist nicht nur ein weiteres Web-Framework; es stellt die Entwicklung von Java für das Cloud-native-Zeitalter dar. Durch die Kombination der Build-Time-Optimierung mit der nativen GraalVM-Kompilierung widerlegt Quarkus das alte Klischee, dass Java zu langsam oder zu speicherintensiv für moderne Microservices und serverlose Funktionen sei.
Wann sollten Sie sich für Quarkus entscheiden?
- Serverlose und ereignisgesteuerte Anwendungen: Wenn Sie Microservices auf AWS Lambda, GCP Cloud Run oder Knative bereitstellen, beseitigen die nativen Binärdateien von Quarkus Kaltstartprobleme vollständig.
- Hochdichte Kubernetes-Cluster: Wenn Ihre Infrastrukturrechnung vom Cluster-RAM-Verbrauch dominiert wird, können Sie durch die Migration von Diensten zu Quarkus die Speicherkosten um bis zu 75 % senken.
- Reaktive Microservices: Wenn Sie Systeme mit hohem Durchsatz erstellen, die nicht blockierendes Streaming erfordern (Kafka, gRPC, WebSockets), liefert Quarkus sofort erstklassige Leistung.
Java wird nicht länger durch langsame Startvorgänge oder überlange Laufzeiten blockiert. Mit Quarkus können Java-Entwickler Cloud-native Anwendungen mit Überschallgeschwindigkeit und subatomarem Fußabdruck erstellen.
Tags
Empower Your Digital Presence & Workflows
Explore top-tier tools built by Ghaznix to streamline your links, surveys, and brand growth.