Start / Cheat Sheets

Cheat Sheet

Quarkus testen, betreiben und migrieren — Cheat Sheet

Stand: · Quarkus für Spring-Boot-Teams

QuarkusDev ServicesOIDCNative ImageMigration

Die Seite nach dem Code: Was der Test macht, was der Betrieb sieht und woran man merkt, dass eine Migration wirklich fertig ist. Maßgeblich bleibt die Doku auf quarkus.io; hier stehen die Werte und Pfade, die man im Alltag nachschlägt — und die Abnahmeliste, die Versionssprünge überlebt.

Annotationen, Konfigurationsschlüssel und Panache stehen auf dem Blatt Spring Boot nach Quarkus übertragen.

Welcher Test wofür

@QuarkusTest@QuarkusIntegrationTest
Gegenstandlaufende Anwendunggebautes Artefakt
Injektionmöglichnicht möglich
AusführungSurefireFailsafe
Nativeneinja, gegen das Native Image

Die Trennung über Surefire und Failsafe ist Pflicht — beide Arten gehören nicht in denselben Testlauf. JUnit 5 bleibt die Grundlage, REST Assured kennt den Port bereits, @TestHTTPResource und @TestHTTPEndpoint liefern URL und Pfad ohne Literale, und @TestTransaction rollt einen Test nach dem Lauf zurück.

@QuarkusTest
class RueckgabeTest {
  @InjectMock AbrechnungClient client;

  @Test void meldetRueckgabe() {
    given().body(dto).contentType(JSON)
      .when().post("/rueckgaben")
      .then().statusCode(201);
  }
}

Ein @Singleton-Bean wird nur mit @MockitoConfig(convertScopes = true) über @InjectMock ersetzt. Jedes zusätzliche Testprofil bedeutet einen weiteren Anwendungsstart — das ist der übliche Grund für eine langsame Suite.

Modul: Anwendungen mit Quarkus testen

Dev Services

Gesetzt wird nur, was wirklich abweicht — ohne Angabe wählt Quarkus ein passendes Image und verdrahtet es selbst.

quarkus.devservices.enabled=true
quarkus.devservices.timeout=60S
quarkus.datasource.devservices.image-name=postgres:17
quarkus.datasource.devservices.reuse=true
quarkus.kafka.devservices.shared=true

PostgreSQL liefert das Schema, das Flyway beim Start migriert; der Kafka-Dev-Service ersetzt den Broker; Keycloak stellt Realm und Tokens bereit. Mit shared und service-name teilen sich mehrere Anwendungen einen Container. Eine halb gesetzte Verbindungskonfiguration verhindert den Start des Dev Service — ohne Hinweis.

Modul: Dev Services statt manueller Testinfrastruktur

Absicherung: Spring Security zu Quarkus Security

Spring SecurityQuarkus Security
@PreAuthorize mit Ausdruck@RolesAllowed mit Rollenliste
@Secured@RolesAllowed
permitAll in der Chain@PermitAll
denyAll in der Chain@DenyAll
antMatchers in der Chainquarkus.http.auth.permission-Einträge

Rollenbasierte Prüfungen wirken an REST-Endpunkten und an CDI-Beans; die Zusicherung steht damit an der Methode und ist beim Lesen des Codes sichtbar. SecurityIdentity ist die eine Quelle für Benutzer, Rollen und Attribute.

quarkus.oidc.auth-server-url=https://idp/realms/pfand
quarkus.oidc.client-id=pfandkreis
quarkus.oidc.application-type=service
quarkus.oidc.token.audience=pfandkreis
quarkus.oidc.roles.role-claim-path=realm_access/roles

Getestet wird über @TestSecurity (Benutzer, Rollen, Berechtigungen ohne echten Provider), @OidcSecurity für Claims, den KeycloakTestClient für echte Tokens oder OidcWiremockTestResource aus quarkus-test-oidc-server.

Modul: Von Spring Security zu Quarkus Security

Messaging: vom Listener zum Kanal

Spring for Apache KafkaQuarkus Messaging
@KafkaListener@Incoming auf der Methode
KafkaTemplate.send@Outgoing oder Emitter
Topic in der AnnotationTopic in der Konfiguration
ConsumerRecordMessage mit Metadaten
Container-FactoryConnector smallrye-kafka

Der Kanalname im Schlüssel ist derselbe, der in @Incoming und @Outgoing steht — weicht er ab, bleibt der Consumer stumm.

kafka.bootstrap.servers=broker:9092
mp.messaging.incoming.rueckgaben.topic=pfand.rueckgabe
mp.messaging.incoming.rueckgaben.group.id=pfandkreis
mp.messaging.outgoing.buchungen.topic=pfand.buchung

Datenbankzugriffe in der Verarbeitung gehören mit @Blocking auf einen Worker-Thread.

Modul: Messaging und externe Systeme

Fehlertoleranz: Vorgabewerte, die man kennen sollte

AnnotationVorgabeBedeutung
@RetrymaxRetries 3drei Wiederholungen
@Timeout1 Sekundeharte Zeitgrenze
@Bulkheadvalue 10zehn gleichzeitige Aufrufe
@CircuitBreakerfailureRatio 0.5Hälfte der Aufrufe fehlerhaft
@CircuitBreakerrequestVolumeThreshold 20Beobachtungsfenster
@CircuitBreakerdelay 5sWartezeit bis zum Probelauf

Je Methode überschreibbar über quarkus.fault-tolerance."Klasse/methode".retry.max-retries.

@Retry(maxRetries = 2)
@Timeout(2000)
@CircuitBreaker(requestVolumeThreshold = 10)
@Fallback(fallbackMethod = "ausCache")
public Konto laden(String id) { ... }

Konto ausCache(String id) { ... }   // gleiche Signatur, sonst greift es nicht

Reaktiv und imperativ dürfen im selben Projekt stehen: Reaktive Endpunkte laufen auf wenigen I/O-Threads, blockierende auf Worker-Threads. await oder toIterable auf einem I/O-Thread schlagen bewusst fehl.

Modul: Resiliente und reaktive Anwendungen

Observability: vom Actuator zu Quarkus

Spring Boot ActuatorQuarkus
/actuator/health/q/health
/actuator/health/liveness/q/health/live
/actuator/health/readiness/q/health/ready
HealthIndicatorHealthCheck mit @Liveness oder @Readiness
Micrometer-RegistryMicrometer-Extension

Verschiebbar über quarkus.smallrye-health.root-path. Die drei Prüfungen bleiben getrennt, weil sie verschiedene Fragen beantworten: Liveness entscheidet über den Neustart des Pods, Readiness über die Zuleitung von Anfragen, Startup verschiebt den Beginn der Liveness-Prüfung beim langsamen Hochlauf. Eine Prüfung, die eine Fremddatenbank abfragt, gehört nicht in Liveness.

Modul: Observability übertragen

Container und Kubernetes

quarkus.kubernetes.namespace=pfand
quarkus.kubernetes.replicas=3
quarkus.kubernetes.image-pull-policy=always
quarkus.kubernetes.env.vars.db-host=postgres
quarkus.kubernetes.liveness-probe.period=10S
quarkus.kubernetes.readiness-probe.period=5S

quarkus.kubernetes.deploy=true rollt beim Build direkt in den Cluster aus — ein Schalter, der nicht versehentlich stehenbleiben sollte. Konfiguration und Secrets kommen aus ConfigMaps und Secrets, nie aus dem Image; Graceful Shutdown lässt laufende Anfragen zu Ende kommen.

Modul: Container und Kubernetes

JVM-Build gegen Native Build

JVM-BuildNative Build
DauerSekundenmehrere Minuten
Speicherbedarfgeringmehrere Gigabyte
Dynamik zur Laufzeitvollständignur was registriert ist
Test des ArtefaktsJVM-TestsIntegrationstests gegen das Image
./mvnw install -Dnative
quarkus build --native
./mvnw install -Dnative -Dquarkus.native.container-build=true

Seit Quarkus 3.36 ist GraalVM beziehungsweise Mandrel 25.0 die minimal offiziell unterstützte Version. Reflektiver Zugriff, dynamische Proxys und Ressourcen brauchen ausdrückliche Registrierung — was in der JVM funktioniert, kann nativ fehlen; umgekehrt nie.

Modul: JVM, AOT und Native Image vergleichen

Die Abnahmeliste

Erst wenn jede Zeile abgehakt ist, wird der alte Dienst abgeschaltet.

PrüfpunktNachweis
Fachliches VerhaltenCharacterization Tests bestehen beidseitig
API-Vertraggleiche Statuscodes und Antwortformate
Fehlerfällegleiche Formate, gleiche Codes
Securityerlaubte und verbotene Zugriffe identisch
Messaginggleiche Nachrichten, keine Doppelverarbeitung
RessourcenStartzeit, Speicher und Antwortzeit gemessen

Modul: Eine Spring-Boot-Anwendung migrieren

Werkzeuge für die Umstellung

WerkzeugAufgabe
Migration Toolkit for Applicationsregelbasierte Analyse des Bestands
OpenRewritedeterministische Codeänderungen nach Rezept
Quarkus Update ToolQuarkus-Projekt auf einen neueren Stream heben
Konveyor AIAnalyse mit Vorschlägen in der Entwicklungsumgebung

Für Quarkus-nach-Quarkus-Updates genügt quarkus update, wahlweise mit --stream. Es stützt sich auf OpenRewrite-Rezepte, und die Dokumentation sagt ausdrücklich, dass damit nur ein Teil der Migration automatisiert wird: vor dem Lauf ein eigener Zweig, nach dem Lauf Ausgabe und Diff prüfen, dann Build und Tests.

Modul: Migrationstools, KI-Unterstützung und Roadmap

Typische Fallen

  • Integrationstests landen in Surefire und starten damit die falsche Variante; Injektion in @QuarkusIntegrationTest schlägt fehl, weil der Prozess ein anderer ist.
  • reuse ist eingeschaltet und Tests beeinflussen sich über alte Daten.
  • Ohne festes Image-Tag ändert ein Testlauf unbemerkt die Datenbankversion.
  • Die CI läuft ohne Container-Laufzeit und die Suite bricht erst dort ab.
  • Die Audience wird nicht geprüft — fremde Tokens desselben Providers gelten damit.
  • Der Rollen-Claim heißt beim Provider anders als erwartet und alle Rollen fehlen.
  • Pfadregeln und Annotationen widersprechen sich, die restriktivere gewinnt unbemerkt; CORS und CSRF werden vergessen, weil sie in Spring woanders standen.
  • Beide Varianten laufen mit derselben Gruppen-Kennung und teilen sich die Nachrichten.
  • Eine Dead Letter Queue wird eingerichtet, aber niemandem zugewiesen.
  • @Retry ohne @Timeout verlängert den Ausfall, statt ihn abzufangen — und Timeout mal Wiederholungen sprengt die Zeitgrenze des Aufrufers.
  • Liveness prüft eine externe Abhängigkeit, und ein fremder Ausfall startet den Pod neu.
  • Readiness meldet bereit, bevor Flyway die Migration beendet hat.
  • Die Probes zeigen weiter auf die Actuator-Pfade und schlagen nach der Migration fehl.
  • Requests und Limits bleiben aus der Spring-Boot-Zeit stehen — der Speichervorteil bleibt damit ungenutzt.
  • Gemessen wird der Kaltstart, obwohl der Dienst wochenlang läuft.

Dieses Thema als Schulung für Ihr Team

Dieser Beitrag erklärt das Thema. Damit Ihr Team es danach auch anwendet, gibt es Quarkus für Spring-Boot-Teams als Schulung — an Ihrem eigenen Code, mit den Fragen, die ein Text nicht beantwortet. Sie wählen die Module, wir bauen daraus ein Programm.

3 Tage·ab 900 EUR netto pro Tag (bis 3 Teilnehmende) ·Termin nach Vereinbarung

Als Team-Schulung anfragenZum Seminar Quarkus für Spring-Boot-Teams →