Quarkus Topic

Getting Started with Quarkus

What is Quarkus?

Quarkus is a Kubernetes-native Java framework tailored for GraalVM and HotSpot, designed to create supersonic, subatomic Java applications. It's built for cloud-native, containerized environments with extremely fast startup times and low memory footprint.

Key Features:

  • Fast Startup Time: 10-100x faster than traditional Java frameworks

  • Low Memory Usage: Optimized for container environments

  • Developer Joy: Live coding, unified configuration, and great tooling

  • Kubernetes Native: Built with cloud-native principles in mind

  • Standards-Based: Uses JPA, JAX-RS, CDI, Eclipse MicroProfile


1. Setting Up Quarkus

Prerequisites

  • Java 11 or 17

  • Maven 3.8+ or Gradle 7+

  • IDE (VS Code, IntelliJ, or Eclipse)

Installation Methods

Method 1: Using Quarkus CLI

bash

# Install Quarkus CLI
curl -Ls https://sh.jbang.dev | bash -s - app install --fresh --force quarkus@quarkusio

# Create a new project
quarkus create app com.example:quarkus-demo:1.0.0
cd quarkus-demo

Method 2: Using Maven

bash

mvn io.quarkus.platform:quarkus-maven-plugin:3.2.0.Final:create \
    -DprojectGroupId=com.example \
    -DprojectArtifactId=quarkus-demo \
    -DclassName="com.example.GreetingResource" \
    -Dpath="/hello"
cd quarkus-demo

Method 3: Using start.quarkus.io

Visit start.quarkus.io and select your extensions, then download the project.


2. Project Structure

text

quarkus-demo/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/example/
│   │   │       ├── GreetingResource.java
│   │   │       ├── entities/
│   │   │       ├── services/
│   │   │       └── repositories/
│   │   └── resources/
│   │       ├── META-INF/resources/
│   │       ├── application.properties
│   │       └── import.sql
│   └── test/
│       └── java/
├── .dockerignore
├── .gitignore
├── README.md
└── pom.xml

3. Basic REST API with Quarkus

Simple REST Endpoint

java

package com.example;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

@Path("/hello")
public class GreetingResource {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
        return "Hello from Quarkus REST!";
    }
    
    @GET
    @Path("/{name}")
    @Produces(MediaType.TEXT_PLAIN)
    public String helloName(String name) {
        return "Hello " + name + "!";
    }
    
    @GET
    @Path("/json")
    @Produces(MediaType.APPLICATION_JSON)
    public Greeting jsonHello() {
        return new Greeting("Hello JSON!", "Quarkus");
    }
    
    public static class Greeting {
        public String message;
        public String from;
        
        public Greeting(String message, String from) {
            this.message = message;
            this.from = from;
        }
        
        // Getters and setters
        public String getMessage() { return message; }
        public void setMessage(String message) { this.message = message; }
        public String getFrom() { return from; }
        public void setFrom(String from) { this.from = from; }
    }
}

Running the Application

bash

# Development mode (with live reload)
./mvnw quarkus:dev

# The application will be available at:
# http://localhost:8080/hello

4. Configuration Management

application.properties

properties

# Server configuration
quarkus.http.port=8080
quarkus.http.host=0.0.0.0

# Logging
quarkus.log.level=INFO
quarkus.log.console.format=%d{HH:mm:ss} %-5p [%c{2.}] (%t) %s%e%n

# Database configuration (if using H2 for development)
quarkus.datasource.db-kind=h2
quarkus.datasource.username=quarkus
quarkus.datasource.password=quarkus
quarkus.datasource.jdbc.url=jdbc:h2:mem:quarkusdb

# Hibernate ORM
quarkus.hibernate-orm.database.generation=drop-and-create
quarkus.hibernate-orm.log.sql=true

# Custom application properties
app.name=Quarkus Demo Application
app.version=1.0.0
app.feature.enabled=true
app.max.connections=10

# External API configuration
external.api.url=https://api.example.com
external.api.timeout=5000
external.api.retry.attempts=3

Configuration with @ConfigMapping (Type-safe)

java

package com.example.config;

import io.smallrye.config.ConfigMapping;
import io.smallrye.config.WithName;

import java.util.Optional;

@ConfigMapping(prefix = "app")
public interface AppConfig {
    
    String name();
    String version();
    
    @WithName("feature.enabled")
    boolean featureEnabled();
    
    @WithName("max.connections")
    int maxConnections();
    
    ExternalApiConfig external();
    
    interface ExternalApiConfig {
        String url();
        int timeout();
        @WithName("retry.attempts")
        int retryAttempts();
    }
}

Using Configuration in Services

java

package com.example.services;

import com.example.config.AppConfig;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.eclipse.microprofile.config.inject.ConfigProperty;

@ApplicationScoped
public class ConfigurationService {
    
    // Method 1: Direct injection
    @ConfigProperty(name = "app.name")
    String appName;
    
    @ConfigProperty(name = "app.version", defaultValue = "1.0.0")
    String appVersion;
    
    @ConfigProperty(name = "external.api.url")
    String externalApiUrl;
    
    // Method 2: Type-safe configuration
    @Inject
    AppConfig appConfig;
    
    public void printConfig() {
        System.out.println("App Name: " + appName);
        System.out.println("App Version: " + appVersion);
        System.out.println("External API: " + externalApiUrl);
        
        // Using type-safe config
        System.out.println("Feature Enabled: " + appConfig.featureEnabled());
        System.out.println("Max Connections: " + appConfig.maxConnections());
        System.out.println("External API URL: " + appConfig.external().url());
    }
}

5. Dependency Injection with CDI

Service Classes

java

package com.example.services;

import jakarta.enterprise.context.ApplicationScoped;
import java.time.LocalDateTime;
import java.util.concurrent.atomic.AtomicLong;

// @ApplicationScoped - single instance for the application
@ApplicationScoped
public class GreetingService {
    
    private final AtomicLong counter = new AtomicLong();
    
    public String generateGreeting(String name) {
        long count = counter.incrementAndGet();
        return String.format("Hello %s! (Request #%d at %s)", 
                           name, count, LocalDateTime.now());
    }
    
    public String formalGreeting(String title, String name) {
        return String.format("Good day, %s %s!", title, name);
    }
}

// @RequestScoped - new instance for each request
package com.example.services;

import jakarta.enterprise.context.RequestScoped;

@RequestScoped
public class RequestScopedService {
    private final String requestId = java.util.UUID.randomUUID().toString();
    
    public String getRequestInfo() {
        return "Request ID: " + requestId;
    }
}

Using CDI in REST Resources

java

package com.example;

import com.example.services.GreetingService;
import com.example.services.RequestScopedService;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

@Path("/greeting")
public class GreetingResource {
    
    @Inject
    GreetingService greetingService;
    
    @Inject
    RequestScopedService requestScopedService;
    
    @GET
    @Path("/{name}")
    @Produces(MediaType.TEXT_PLAIN)
    public String greeting(@PathParam("name") String name) {
        String requestInfo = requestScopedService.getRequestInfo();
        String greeting = greetingService.generateGreeting(name);
        return greeting + " - " + requestInfo;
    }
    
    @GET
    @Path("/formal/{title}/{name}")
    @Produces(MediaType.TEXT_PLAIN)
    public String formalGreeting(@PathParam("title") String title,
                                @PathParam("name") String name) {
        return greetingService.formalGreeting(title, name);
    }
}

Event-Driven with CDI

java

package com.example.events;

// Event classes
public class UserRegisteredEvent {
    private final String username;
    private final String email;
    
    public UserRegisteredEvent(String username, String email) {
        this.username = username;
        this.email = email;
    }
    
    // getters
    public String getUsername() { return username; }
    public String getEmail() { return email; }
}

public class EmailSentEvent {
    private final String recipient;
    private final String subject;
    
    public EmailSentEvent(String recipient, String subject) {
        this.recipient = recipient;
        this.subject = subject;
    }
    
    // getters
    public String getRecipient() { return recipient; }
    public String getSubject() { return subject; }
}

// Event producers
package com.example.services;

import com.example.events.UserRegisteredEvent;
import com.example.events.EmailSentEvent;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.event.Event;
import jakarta.inject.Inject;

@ApplicationScoped
public class UserRegistrationService {
    
    @Inject
    Event<UserRegisteredEvent> userRegisteredEvent;
    
    @Inject
    Event<EmailSentEvent> emailSentEvent;
    
    public void registerUser(String username, String email) {
        // Save user to database
        System.out.println("Registering user: " + username);
        
        // Fire event
        userRegisteredEvent.fire(new UserRegisteredEvent(username, email));
        
        // Fire async event
        userRegisteredEvent.fireAsync(new UserRegisteredEvent(username, email));
    }
}

// Event observers
package com.example.listeners;

import com.example.events.UserRegisteredEvent;
import com.example.events.EmailSentEvent;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.event.Observes;
import jakarta.enterprise.event.ObservesAsync;

@ApplicationScoped
public class EventListeners {
    
    // Synchronous observer
    public void onUserRegistered(@Observes UserRegisteredEvent event) {
        System.out.println("Sending welcome email to: " + event.getEmail());
        // Send welcome email
    }
    
    // Asynchronous observer
    public void onUserRegisteredAsync(@ObservesAsync UserRegisteredEvent event) {
        System.out.println("Async: Creating user profile for: " + event.getUsername());
        // Time-consuming operations
    }
    
    // Conditional observer
    public void onGmailUserRegistered(@Observes @Gmail UserRegisteredEvent event) {
        System.out.println("Special handling for Gmail user: " + event.getEmail());
    }
}

// Qualifier for conditional events
package com.example.listeners;

import jakarta.inject.Qualifier;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
public @interface Gmail {
}

6. Database Integration with Panache

Entity Classes

java

package com.example.entities;

import io.quarkus.hibernate.orm.panache.PanacheEntity;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import java.time.LocalDateTime;

@Entity
@Table(name = "users")
public class User extends PanacheEntity {
    
    @NotBlank
    @Size(min = 3, max = 50)
    public String username;
    
    @NotBlank
    @Email
    public String email;
    
    public String firstName;
    public String lastName;
    
    public LocalDateTime createdAt;
    public LocalDateTime updatedAt;
    
    // Lifecycle callbacks
    public void prePersist() {
        createdAt = LocalDateTime.now();
        updatedAt = LocalDateTime.now();
    }
    
    public void preUpdate() {
        updatedAt = LocalDateTime.now();
    }
    
    // Static query methods
    public static User findByEmail(String email) {
        return find("email", email).firstResult();
    }
    
    public static long countByUsername(String username) {
        return count("username", username);
    }
}

// Another entity
package com.example.entities;

import io.quarkus.hibernate.orm.panache.PanacheEntity;
import jakarta.persistence.Entity;
import jakarta.persistence.ManyToOne;
import java.math.BigDecimal;
import java.time.LocalDateTime;

@Entity
public class Product extends PanacheEntity {
    
    public String name;
    public String description;
    public BigDecimal price;
    public Integer stockQuantity;
    public LocalDateTime createdAt;
    
    // Getters and setters
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    // ... other getters/setters
}

Repository Pattern with Panache

java

package com.example.repositories;

import com.example.entities.User;
import io.quarkus.hibernate.orm.panache.PanacheRepository;
import jakarta.enterprise.context.ApplicationScoped;
import java.util.List;
import java.util.Optional;

@ApplicationScoped
public class UserRepository implements PanacheRepository<User> {
    
    public Optional<User> findByEmailOptional(String email) {
        return find("email", email).firstResultOptional();
    }
    
    public List<User> findActiveUsers() {
        return list("createdAt is not null order by createdAt desc");
    }
    
    public long updateUserEmail(Long userId, String newEmail) {
        return update("email = ?1 where id = ?2", newEmail, userId);
    }
    
    public List<User> findUsersWithNameLike(String namePattern) {
        return find("username like ?1", "%" + namePattern + "%").list();
    }
}

package com.example.repositories;

import com.example.entities.Product;
import io.quarkus.hibernate.orm.panache.PanacheRepository;
import jakarta.enterprise.context.ApplicationScoped;
import java.math.BigDecimal;
import java.util.List;

@ApplicationScoped
public class ProductRepository implements PanacheRepository<Product> {
    
    public List<Product> findExpensiveProducts(BigDecimal minPrice) {
        return find("price > ?1 order by price desc", minPrice).list();
    }
    
    public List<Product> findProductsInStock() {
        return find("stockQuantity > 0").list();
    }
    
    public long updateProductPrice(Long productId, BigDecimal newPrice) {
        return update("price = ?1 where id = ?2", newPrice, productId);
    }
}

Service Layer

java

package com.example.services;

import com.example.entities.User;
import com.example.entities.Product;
import com.example.repositories.UserRepository;
import com.example.repositories.ProductRepository;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import java.util.List;
import java.util.Optional;

@ApplicationScoped
public class UserService {
    
    @Inject
    UserRepository userRepository;
    
    @Inject
    ProductRepository productRepository;
    
    @Transactional
    public User createUser(String username, String email, String firstName, String lastName) {
        User user = new User();
        user.username = username;
        user.email = email;
        user.firstName = firstName;
        user.lastName = lastName;
        
        userRepository.persist(user);
        return user;
    }
    
    public Optional<User> getUserById(Long id) {
        return userRepository.findByIdOptional(id);
    }
    
    public Optional<User> getUserByEmail(String email) {
        return userRepository.findByEmailOptional(email);
    }
    
    public List<User> getAllUsers() {
        return userRepository.listAll();
    }
    
    @Transactional
    public boolean deleteUser(Long id) {
        return userRepository.deleteById(id);
    }
    
    @Transactional
    public User updateUserEmail(Long userId, String newEmail) {
        Optional<User> userOpt = userRepository.findByIdOptional(userId);
        if (userOpt.isPresent()) {
            User user = userOpt.get();
            user.email = newEmail;
            return user;
        }
        return null;
    }
}

// Product Service
package com.example.services;

import com.example.entities.Product;
import com.example.repositories.ProductRepository;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import java.math.BigDecimal;
import java.util.List;

@ApplicationScoped
public class ProductService {
    
    @Inject
    ProductRepository productRepository;
    
    @Transactional
    public Product createProduct(String name, String description, BigDecimal price, Integer stock) {
        Product product = new Product();
        product.name = name;
        product.description = description;
        product.price = price;
        product.stockQuantity = stock;
        product.createdAt = java.time.LocalDateTime.now();
        
        productRepository.persist(product);
        return product;
    }
    
    public List<Product> getAllProducts() {
        return productRepository.listAll();
    }
    
    public List<Product> getProductsInStock() {
        return productRepository.findProductsInStock();
    }
    
    public List<Product> getExpensiveProducts(BigDecimal minPrice) {
        return productRepository.findExpensiveProducts(minPrice);
    }
    
    @Transactional
    public boolean updateProductStock(Long productId, Integer newStock) {
        Optional<Product> productOpt = productRepository.findByIdOptional(productId);
        if (productOpt.isPresent()) {
            Product product = productOpt.get();
            product.stockQuantity = newStock;
            return true;
        }
        return false;
    }
}

REST Controllers for CRUD Operations

java

package com.example.resources;

import com.example.entities.User;
import com.example.services.UserService;
import jakarta.inject.Inject;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import java.net.URI;
import java.util.List;
import java.util.Optional;

@Path("/api/users")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class UserResource {
    
    @Inject
    UserService userService;
    
    @GET
    public List<User> getAllUsers() {
        return userService.getAllUsers();
    }
    
    @GET
    @Path("/{id}")
    public Response getUserById(@PathParam("id") Long id) {
        Optional<User> user = userService.getUserById(id);
        if (user.isPresent()) {
            return Response.ok(user.get()).build();
        } else {
            return Response.status(Response.Status.NOT_FOUND)
                         .entity("User not found with id: " + id)
                         .build();
        }
    }
    
    @POST
    public Response createUser(User user) {
        try {
            User createdUser = userService.createUser(
                user.username, 
                user.email, 
                user.firstName, 
                user.lastName
            );
            return Response.created(URI.create("/api/users/" + createdUser.id))
                         .entity(createdUser)
                         .build();
        } catch (Exception e) {
            return Response.status(Response.Status.BAD_REQUEST)
                         .entity("Error creating user: " + e.getMessage())
                         .build();
        }
    }
    
    @PUT
    @Path("/{id}")
    public Response updateUser(@PathParam("id") Long id, User user) {
        User updatedUser = userService.updateUserEmail(id, user.email);
        if (updatedUser != null) {
            return Response.ok(updatedUser).build();
        } else {
            return Response.status(Response.Status.NOT_FOUND)
                         .entity("User not found with id: " + id)
                         .build();
        }
    }
    
    @DELETE
    @Path("/{id}")
    public Response deleteUser(@PathParam("id") Long id) {
        boolean deleted = userService.deleteUser(id);
        if (deleted) {
            return Response.noContent().build();
        } else {
            return Response.status(Response.Status.NOT_FOUND)
                         .entity("User not found with id: " + id)
                         .build();
        }
    }
    
    @GET
    @Path("/email/{email}")
    public Response getUserByEmail(@PathParam("email") String email) {
        Optional<User> user = userService.getUserByEmail(email);
        if (user.isPresent()) {
            return Response.ok(user.get()).build();
        } else {
            return Response.status(Response.Status.NOT_FOUND)
                         .entity("User not found with email: " + email)
                         .build();
        }
    }
}

7. Testing in Quarkus

Unit Tests

java

package com.example.services;

import io.quarkus.test.junit.QuarkusTest;
import jakarta.inject.Inject;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

@QuarkusTest
class GreetingServiceTest {
    
    @Inject
    GreetingService greetingService;
    
    @Test
    void testGenerateGreeting() {
        String result = greetingService.generateGreeting("John");
        assertTrue(result.contains("Hello John!"));
        assertTrue(result.contains("Request #1"));
    }
    
    @Test
    void testFormalGreeting() {
        String result = greetingService.formalGreeting("Mr", "Smith");
        assertEquals("Good day, Mr Smith!", result);
    }
}

Integration Tests

java

package com.example.resources;

import io.quarkus.test.junit.QuarkusTest;
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.containsString;

@QuarkusTest
class GreetingResourceTest {
    
    @Test
    void testHelloEndpoint() {
        given()
          .when().get("/hello")
          .then()
             .statusCode(200)
             .body(is("Hello from Quarkus REST!"));
    }
    
    @Test
    void testHelloNameEndpoint() {
        given()
          .when().get("/hello/Quarkus")
          .then()
             .statusCode(200)
             .body(containsString("Hello Quarkus!"));
    }
    
    @Test
    void testJsonEndpoint() {
        given()
          .when().get("/hello/json")
          .then()
             .statusCode(200)
             .contentType(ContentType.JSON)
             .body("message", is("Hello JSON!"))
             .body("from", is("Quarkus"));
    }
}

Database Tests

java

package com.example.repositories;

import com.example.entities.User;
import io.quarkus.test.TestTransaction;
import io.quarkus.test.junit.QuarkusTest;
import jakarta.inject.Inject;
import org.junit.jupiter.api.Test;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.*;

@QuarkusTest
@TestTransaction
class UserRepositoryTest {
    
    @Inject
    UserRepository userRepository;
    
    @Test
    void testCreateAndFindUser() {
        // Create user
        User user = new User();
        user.username = "testuser";
        user.email = "[email protected]";
        user.firstName = "Test";
        user.lastName = "User";
        
        userRepository.persist(user);
        assertNotNull(user.id);
        
        // Find user
        Optional<User> found = userRepository.findByEmailOptional("[email protected]");
        assertTrue(found.isPresent());
        assertEquals("testuser", found.get().username);
    }
    
    @Test
    void testUpdateUser() {
        User user = new User();
        user.username = "updateuser";
        user.email = "[email protected]";
        userRepository.persist(user);
        
        long updated = userRepository.updateUserEmail(user.id, "[email protected]");
        assertEquals(1, updated);
        
        Optional<User> found = userRepository.findByEmailOptional("[email protected]");
        assertTrue(found.isPresent());
    }
}

8. Building and Deployment

Building for Production

bash

# Build native executable (requires GraalVM)
./mvnw package -Pnative

# Build JVM mode
./mvnw package

# Build container image
./mvnw package -Dquarkus.container-image.build=true

Docker Configuration

dockerfile

# Dockerfile.jvm
FROM registry.access.redhat.com/ubi8/openjdk-17-runtime:1.14
ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en'
COPY target/quarkus-app/lib/ /deployments/lib/
COPY target/quarkus-app/*.jar /deployments/
COPY target/quarkus-app/app/ /deployments/app/
COPY target/quarkus-app/quarkus/ /deployments/quarkus/
EXPOSE 8080
USER 185
ENTRYPOINT [ "java", "-jar", "/deployments/quarkus-run.jar" ]

Kubernetes Deployment

yaml

# src/main/kubernetes.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: quarkus-demo
spec:
  replicas: 3
  selector:
    matchLabels:
      app: quarkus-demo
  template:
    metadata:
      labels:
        app: quarkus-demo
    spec:
      containers:
      - name: quarkus-demo
        image: quarkus-demo:1.0.0
        ports:
        - containerPort: 8080
        env:
        - name: QUARKUS_HTTP_PORT
          value: "8080"
        resources:
          requests:
            memory: "64Mi"
            cpu: "100m"
          limits:
            memory: "256Mi"
            cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:
  name: quarkus-demo
spec:
  ports:
  - port: 80
    targetPort: 8080
  selector:
    app: quarkus-demo

9. Key Quarkus Extensions

Popular Extensions to Add

bash

# RESTEasy JAX-RS
./mvnw quarkus:add-extension -Dextensions="resteasy,resteasy-jsonb"

# Hibernate ORM with Panache
./mvnw quarkus:add-extension -Dextensions="hibernate-orm-panache,jdbc-h2"

# Security
./mvnw quarkus:add-extension -Dextensions="oidc,smallrye-jwt"

# Messaging
./mvnw quarkus:add-extension -Dextensions="smallrye-reactive-messaging-kafka"

# Monitoring
./mvnw quarkus:add-extension -Dextensions="smallrye-health,smallrye-metrics"

# Database
./mvnw quarkus:add-extension -Dextensions="jdbc-postgresql"

# Testing
./mvnw quarkus:add-extension -Dextensions="rest-assured"

pom.xml Extensions Section

xml

<dependencies>
    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-resteasy</artifactId>
    </dependency>
    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-resteasy-jsonb</artifactId>
    </dependency>
    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-hibernate-orm-panache</artifactId>
    </dependency>
    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-jdbc-h2</artifactId>
    </dependency>
    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-arc</artifactId>
    </dependency>
    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-smallrye-health</artifactId>
    </dependency>
</dependencies>

10. Development Workflow

Development Mode

bash

# Start in dev mode with live reload
./mvnw quarkus:dev

# Access dev UI
# http://localhost:8080/q/dev/

# Continuous testing mode
./mvnw quarkus:dev -Dquarkus.test.continuous-testing=enabled

Useful Development Endpoints

  • Dev UI: http://localhost:8080/q/dev/

  • Health Checks: http://localhost:8080/q/health/

  • Metrics: http://localhost:8080/q/metrics/

  • OpenAPI: http://localhost:8080/q/openapi/

Performance Comparison

java

// Traditional Spring Boot vs Quarkus
/*
Startup Time:
- Spring Boot: 2-5 seconds
- Quarkus JVM: 0.5-1 second  
- Quarkus Native: 0.01-0.05 seconds

Memory Usage:
- Spring Boot: 100-200MB
- Quarkus JVM: 30-50MB
- Quarkus Native: 10-20MB
*/

This extensive Quarkus guide covers everything from basic setup to advanced features like CDI events, Panache ORM, testing, and deployment. Quarkus is ideal for cloud-native applications where fast startup times and low memory footprint are critical.

 

Comments (0)

No comments yet. Be the first to comment!

LecturreAI Assistant

Hello! I'm LecturreAI

What would you like to learn today?