Introduction
En 2026, Quarkus domine le paysage des frameworks Java pour microservices grâce à sa compilation native GraalVM, réduisant les temps de démarrage à moins de 10 ms et la consommation mémoire de 80 % par rapport à Spring Boot. Idéal pour Kubernetes et serverless, il intègre supersonic subatomic Java : build rapide, hot reload en dev, et extensions modulaires pour Kafka, gRPC ou OpenTelemetry.
Ce tutoriel expert vous guide pas à pas pour bâtir un microservice complet : API REST réactive, persistence avec Hibernate Reactive, tests unitaires, build native et déploiement K8s. Chaque ligne de code est fonctionnelle, copier-collable. Imaginez un framework qui compile votre app en binaire autonome comme Go ou Rust, mais en Java pur – c'est Quarkus. À la fin, vous maîtriserez les configs avancées pour scaler en prod. (142 mots)
Prérequis
- JDK 17+ (GraalVM 22+ recommandé pour native)
- Maven 3.9+ ou Gradle 8+
- Docker et Kubernetes (minikube pour tests)
- Connaissances avancées : Java 21 records/sealed classes, réactivité (Mutiny), Hibernate ORM
- IDE : IntelliJ avec Quarkus Tools ou VS Code
Créer le projet Quarkus
mkdir quarkus-microservice && cd quarkus-microservice
quarkus create app --extensions=resteasy-reactive,hibernate-reactive-panache,quarkus-smallrye-health,quarkus-container-image-docker,quarkus-kubernetes \
com.example:quarkus-microservice:1.0.0-SNAPSHOT
# Alternative Maven CLI si quarkus CLI non installé
mvn io.quarkus.platform:quarkus-maven-plugin:3.15.1:create \
-DprojectGroupId=com.example -DprojectArtifactId=quarkus-microservice \
-Dextensions="resteasy-reactive,hibernate-reactive-panache,quarkus-smallrye-health,quarkus-container-image-docker,quarkus-kubernetes" \
-DnoCodeCette commande initialise un projet avec REST réactif, persistence réactive PostgreSQL (Dev Services auto), health checks, build Docker natif et manifests K8s. Le flag --noCode évite le boilerplate ; on customise tout. Attention : installez quarkus CLI via brew ou SDKMAN pour simplicité.
Structure du projet généré
Le squelette inclut src/main/java pour resources JAX-RS, entités Panache, application.properties pour configs, et pom.xml avec extensions. Dev Services auto-démarre Postgres en dev sans config manuelle – magie Quarkus. Hot reload via ./mvnw quarkus:dev : modifiez code, refresh auto en <1s, comme un Vite pour Java.
Définir l'entité et repository
package com.example;
import io.quarkus.hibernate.reactive.panache.PanacheEntityBase;
import io.smallrye.mutiny.Uni;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
@Entity
public class Product extends PanacheEntityBase {
@Id @GeneratedValue
public Long id;
public String name;
public Double price;
public static Uni<Product> findByName(String name) {
return find("name", name).firstResult();
}
public static Uni<Long> deleteByName(String name) {
return delete("name", name);
}
}Héritage de PanacheEntityBase pour CRUD réactif avec Mutiny (Uni/Multi). Repository statique intégré évite boilerplate DAO. Piège : toujours wrap en Uni pour non-bloquant ; @GeneratedValue auto-incrémente ID.
Implémenter la resource REST
package com.example;
import io.smallrye.mutiny.Uni;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import java.util.List;
@Path("/products")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class ProductResource {
@GET
public Uni<List<Product>> getAll() {
return Product.listAll();
}
@GET
@Path("{id}")
public Uni<Response> getById(@PathParam("id") Long id) {
return Product.findById(id)
.onItem().transform(product -> product != null ? Response.ok(product) : Response.status(404, "Not found"))
.onFailure().transform(e -> Response.status(500, e.getMessage()));
}
@POST
public Uni<Response> create(Product product) {
return product.persist().map(ignore -> Response.created(null).build());
}
@DELETE
@Path("{id}")
public Uni<Response> delete(@PathParam("id") Long id) {
return Product.deleteById(id).map(deleted -> Response.noContent().build());
}
}Resource JAX-RS réactive : Uni pour async. Chaines Mutiny fluides gèrent 404/500. @PathParam pour routes dynamiques. Avantage expert : zero XML, injection CDI auto, scale horizontal sans blocage.
Configuration base de données
Dev Services provisionne Postgres en mémoire. En prod, override via env vars. Health checks exposés sur /q/health pour K8s readiness probes.
Fichier de configuration avancée
quarkus.datasource.db-kind=postgresql
quarkus.datasource.reactive.url=postgresql://localhost:5432/microservice
quarkus.datasource.username=quarkus
quarkus.datasource.password=quarkus
quarkus.hibernate-reactive.database.generation=drop-and-create
quarkus.log.level=INFO
%prod.quarkus.container-image.build=true
%prod.quarkus.container-image.group=learni
%prod.quarkus.kubernetes.deploy=true
quarkus.smallrye-health.root-path=/q/health
# Native hints pour GraalVM
quarkus.native.additional-build-args=--report-unsupported-elements-at-runtimeConfigs profilées %prod pour build/deploy. drop-and-create en dev, validate en prod. Native args évitent warnings GraalVM. Piège : oubliez quarkus.container-image.build=true pour Docker auto.
Tests unitaires réactifs
package com.example;
import io.quarkus.test.junit.QuarkusTest;
import io.restassured.http.ContentType;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.is;
@QuarkusTest
public class ProductResourceTest {
@Test
public void testCreateAndGet() {
Product product = new Product();
product.name = "Laptop";
product.price = 999.99;
given()
.body(product)
.contentType(ContentType.JSON)
.when().post("/products")
.then()
.statusCode(201);
given()
.when().get("/products")
.then()
.statusCode(200)
.body("[0].name", is("Laptop"));
}
}@QuarkusTest mocke DB en H2, injecte CDI. RestAssured pour assertions HTTP. Couvre create/list ; ajoutez @TestHTTPEndpoint pour integration. Expert : tests parallèles x10 plus rapides qu'en JVM.
Build native et Docker
./mvnw clean package -Pnative -Dquarkus.native.container-build=true
# Image auto-générée : quay.io/learni/quarkus-microservice:1.0.0-SNAPSHOT-native
# Test local
docker run -i --rm -p 8080:8080 quay.io/learni/quarkus-microservice:1.0.0-SNAPSHOT-native
# Push et deploy K8s
./mvnw deploy -Dquarkus.kubernetes.deploy-mode=openshift # ou kubernetesProfile native compile en binaire <50MB, startup 0.01s. Container build in-Docker pour M1/ARM. deploy génère Deployment/Service YAML. Piège : 20-30min premier build GraalVM, cachez layers.
Bonnes pratiques
- Profilage strict :
%dev,%test,%prodpour secrets/env vars ; jamais hardcoded. - Mutiny everywhere : évitez
await()bloquants, chainonFailure().recoverWith(). - Extensions lazy :
quarkus-arcpour DI,smallrye-opentracingpour traces auto. - Native-ready :
@RegisterForReflectionsur classes dynamiques, testez native unitaires. - Observability : activez
/q/metrics, Prometheus scrape pour K8s HPA.
Erreurs courantes à éviter
- Blocage IO : utiliser
Uni.createFrom().emitter()au lieu deThread.sleep(). - GraalVM reflection : oublie
@NativeImageHintcrash runtime ; analyseznative-image-agent. - Dev Services leak : toujours
./mvnw cleanaprès dev, ouquarkus.devservices.enabled=false. - K8s scaling : readiness
/q/health/readymanquante = pods pending forever.
Pour aller plus loin
Plongez dans Quarkus Kafka Reactive ou gRPC. Maîtrisez GraalVM avec notre formation experte : Formations Learni Java Cloud-Native. Docs officielles : guide.quarkus.io.