🔥 FREE PRO OFFER OnlyLink.click Pro Version is 100% Free of Cost till 31 December, 2026! Claim Free Pro

Introducción a Quarkus: por qué los desarrolladores de Java se están trasladando a Java supersónico

Introducción a Quarkus: por qué los desarrolladores de Java se están trasladando a Java supersónico

Durante casi tres décadas, Java ha sido la fuerza dominante en el desarrollo de software empresarial. Su rico ecosistema, su sólida base orientada a objetos, su independencia de plataforma a través de la máquina virtual Java (JVM) y sus marcos probados en batalla como Spring Boot lo convirtieron en el rey indiscutible de la infraestructura backend.

Sin embargo, el cambio hacia arquitecturas nativas de la nube, orquestación de Kubernetes, containerización (Docker) y computación sin servidor (AWS Lambda, Knative) expuso una vulnerabilidad grave en los marcos de aplicaciones Java tradicionales: alta sobrecarga de memoria y tiempos de inicio lentos.

Cuando un microservicio necesita escalar horizontalmente de cero a 100 réplicas en respuesta a un aumento en el tráfico, o cuando una función sin servidor se ejecuta bajo demanda, esperar de 3 a 10 segundos para que se inicie un proceso Java es inaceptable. La infraestructura de nube moderna exige un inicio instantáneo y un consumo ligero de memoria, rasgos tradicionalmente reservados para lenguajes como Go, Rust o Node.js.

Ingrese a Quarkus: un marco Java nativo de Kubernetes diseñado específicamente para GraalVM y OpenJDK HotSpot. A menudo denominado “Java subatómico supersónico”, Quarkus rediseña fundamentalmente cómo se compilan, inician y ejecutan las aplicaciones Java.

En esta guía detallada, exploraremos por qué los desarrolladores de Java están adoptando Quarkus, cómo Quarkus logra tiempos de inicio inferiores a un segundo y huellas de micromemoria, la mecánica arquitectónica de Optimización del tiempo de compilación y cómo construir un microservicio reactivo listo para producción en Java con Quarkus.


1. El dilema nativo de la nube del Java tradicional

Para comprender por qué existe Quarkus, debemos examinar cómo funcionan internamente los marcos tradicionales de Java como Spring Boot o Jakarta EE.

A. El alto costo de inicialización del tiempo de ejecución

Los marcos tradicionales de Java dependen en gran medida de la reflexión dinámica en tiempo de ejecución, el escaneo de classpath y la generación de proxy:

  1. Escaneo de Classpath: durante el inicio, la JVM escanea cada archivo JAR en el classpath para descubrir anotaciones como @Component, @Service, @Controller o @Entity.
  2. Procesamiento de anotaciones y reflexión: el marco utiliza la reflexión (Class.forName(), getDeclaredFields()) para crear un gráfico en memoria de beans, propiedades de configuración y dependencias.
  3. Creación dinámica de proxy: CGLIB o ByteBuddy genera proxies dinámicos de código de bytes en la memoria de ejecución para admitir la programación orientada a aspectos (AOP), la gestión de transacciones de bases de datos (@Transactional) y los límites de seguridad.
  4. Inflación de metaespacio y RSS: todos los metadatos, descriptores de clase reflejados y proxies generados deben retenerse en la memoria dentro del metaespacio y el tamaño del conjunto residente (RSS) de la JVM.

Este bucle de reflexión en tiempo de ejecución requiere ciclos de CPU considerables e infla el consumo de memoria dinámica. Un servicio CRUD REST básico en Java tradicional puede consumir fácilmente 140 MB a 300 MB de RAM en estado inactivo y tardar de 3 a 8 segundos en iniciarse.

B. La sanción financiera en la computación en la nube

En entornos sin servidor y en contenedores, los proveedores de nube cobran según dos métricas: memoria asignada (GB) y duración de ejecución (milisegundos).

  • Arranques en frío: si una función sin servidor tarda 5 segundos en iniciarse, los usuarios finales experimentan una latencia notable y usted paga por 5 segundos de cálculo de inicio inactivo.
  • Densidad y escalabilidad de pod: en un clúster de Kubernetes con un nodo trabajador que posee 16 GB de RAM, solo puede ejecutar ~40 instancias de microservicio Spring Boot tradicionales antes de quedarse sin memoria. Si cada instancia consumiera solo 15 MB de RAM, el mismo nodo podría albergar más de 800 instancias.

2. Arquitectura Quarkus: pasar el trabajo del tiempo de ejecución al tiempo de construcción

Quarkus resuelve el dilema nativo de la nube a través de un cambio radical de paradigma arquitectónico: trasladar operaciones dinámicas del tiempo de ejecución al tiempo de construcción.

Diagrama de arquitectura de optimización del tiempo de compilación de Java en tiempo de ejecución tradicional frente a Quarkus

Procesamiento en tiempo de compilación (optimización anticipada)

En lugar de ejecutar escaneo de classpath, análisis de anotaciones y cableado de gráficos de beans cada vez que se inicia la aplicación, Quarkus realiza todas estas operaciones pesadas una vez durante la fase de compilación (mvn package o ./gradlew build).

  1. Arquitectura de extensión y pasos de construcción: Quarkus utiliza un marco de extensión conectable. Al compilar su aplicación, las extensiones de Quarkus analizan anotaciones, generan código de bytes estático optimizado y resuelven gráficos de inyección de dependencias por adelantado.
  2. Metadatos predefinidos: todos los metadatos de inyección de dependencia se calculan previamente. Cuando se inicia la aplicación, Quarkus crea instancias directamente de clases precompiladas sin invocar reflexión ni escanear classpaths.
  3. Eliminación de código muerto (sacudida de árbol): durante el proceso de compilación, Quarkus identifica clases, métodos y bibliotecas que su aplicación no utiliza y los elimina por completo.

Para cuando se produce el JAR o el binario nativo de su aplicación, se habrá eliminado toda la sobrecarga del tiempo de ejecución. La JVM simplemente carga códigos de bytes estáticos precableados y se inicia instantáneamente.


3. Imagen nativa de GraalVM frente a OpenJDK HotSpot

Quarkus proporciona un modelo de ejecución dual: se ejecuta excepcionalmente rápido en OpenJDK HotSpot estándar, pero alcanza su máximo potencial de rendimiento cuando se compila en una Imagen nativa de GraalVM.

+-----------------------------------------------------------------------+
|                         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    |
   +----------------------------------+   +----------------------------------+

Compilación anticipada (AOT) y máquina virtual de sustrato

GraalVM Native Image toma el código de bytes de Java y lo compila directamente en un binario ejecutable independiente específico del sistema operativo (binario ELF en Linux, Mach-O en macOS, EXE en Windows).

  • Supuesto de mundo cerrado: GraalVM supone que todo el código, las clases y los recursos accesibles se conocen en el momento de la compilación.
  • Substrate VM: el ejecutable nativo incorpora un motor de ejecución en miniatura llamado Substrate VM, que maneja la administración de memoria, la programación de subprocesos y la recolección de basura sin iniciar una instancia JVM completa.
  • Sobrecarga de reflexión cero: debido a que Quarkus prepara configuraciones de reflexión y definiciones de proxy durante el tiempo de compilación, la compilación de imágenes nativas de GraalVM se realiza correctamente sin los archivos de configuración manual que históricamente requieren las compilaciones nativas de GraalVM.

4. Puntos de referencia de desempeño: la evidencia empírica

Para ilustrar el marcado contraste en el rendimiento, examinemos comparaciones estándar de la industria en tres configuraciones de tiempo de ejecución de Java que ejecutan un servicio CRUD de base de datos REST + estándar:

  1. Pila tradicional nativa de la nube (JVM tradicional/arranque de primavera)
  2. Quarkus en OpenJDK HotSpot
  3. Quarkus en imagen nativa de GraalVM
Comparación de rendimiento del marco Java: consumo de memoria y tiempo de inicio

Tabla de resumen de rendimiento

Métrico Pila tradicional (JVM) Quarkus (Punto de acceso JVM) Quarkus (nativo de GraalVM)
Memoria RSS RESTO ~140MB ~74MB ~13MB
REST + Memoria RSS CRUD ~218MB ~112MB ~35MB
Tiempo de inicio DESCANSO ~4,3 segundos ~0,98 segundos ~0,014 segundos (14 ms)
REST + Tiempo de inicio CRUD ~9,5 segundos ~2,0 segundos ~0,042 segundos (42 ms)
Artefacto ejecutable JAR grande y gordo (~50 MB) JAR optimizado (~20 MB) Binario nativo independiente (~30 MB)

Tenga en cuenta que Quarkus compilado en una imagen nativa arranca en 14 milisegundos (más rápido que un abrir y cerrar de ojos) y consume apenas 13 MB de RAM. Esto hace que Java sea completamente competitivo con Go y Rust para implementaciones nativas de la nube y sin servidor.


5. Motor de doble núcleo reactivo e imperativo

Históricamente, los desarrolladores de Java tenían que elegir entre dos modelos de programación mutuamente excluyentes:

  1. Imperativo (subproceso por solicitud): código de bloqueo simple y legible que utiliza controladores JDBC estándar y puntos finales REST sincrónicos.
  2. Reactivo (bucle de eventos): código asincrónico sin bloqueo (por ejemplo, RxJava, Project Reactor) capaz de un alto rendimiento, pero conocido por cadenas de devolución de llamadas complejas y depuración difícil.

Quarkus unifica ambos mundos bajo un único motor cohesivo impulsado por Eclipse Vert.x y Netty.

                      +---------------------------------+
                      |     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 |
                 +-------------------+   +-------------------+

En Quarkus, la E/S sin bloqueo es la base. Si escribe código de bloqueo tradicional, Quarkus envía automáticamente la ejecución a un grupo de subprocesos de trabajo administrado. Si utiliza tipos reactivos como SmallRye Mutiny (Uni<T> y Multi<T>), la ejecución permanece en el subproceso de bucle de eventos sin bloqueo de alto rendimiento.


6. Alegría del desarrollador: servicios de desarrollo y codificación en vivo

Más allá del rendimiento en tiempo de ejecución, Quarkus ofrece una experiencia de desarrollador revolucionaria diseñada para eliminar el tedioso ciclo de retroalimentación de compilación, prueba y reinicio.

A. Codificación en vivo con reinicio cero (quarkus:dev)

Al ejecutar mvn quarkus:dev, Quarkus inicia el modo de codificación en vivo. Puede editar archivos Java, cambiar propiedades, modificar plantillas HTML o actualizar esquemas de bases de datos.

La próxima vez que active una solicitud HTTP en su navegador o terminal, Quarkus detecta los cambios en el archivo, vuelve a aplicar los pasos de compilación y recarga en caliente la aplicación en menos de 500 milisegundos. Nunca necesitará detener y reiniciar manualmente su servidor de aplicaciones durante el desarrollo.

B. Quarkus Dev Services (contenedores de prueba de configuración cero)

Para conectar un microservicio a una base de datos PostgreSQL, un agente Kafka o un caché de Redis, generalmente es necesario escribir un archivo docker-compose.yml y configurar los puertos de la base de datos local.

Con los servicios de desarrollo de Quarkus:

  • Si Quarkus detecta una dependencia de la base de datos (por ejemplo, quarkus-reactive-pg-client) pero no hay ninguna URL de base de datos configurada en application.properties, Quarkus activa automáticamente un contenedor Docker que ejecuta PostgreSQL a través de Testcontainers en segundo plano.
  • Inyecta automáticamente las credenciales de conexión en la aplicación en ejecución.
  • Cuando detienes el modo de desarrollo, el contenedor se limpia solo.

7. Tutorial práctico: creación de un servicio Quarkus reactivo listo para producción

Creemos un microservicio Quarkus limpio y de alto rendimiento en Java que exponga una API REST conectada a una base de datos PostgreSQL usando Hibernate Reactive con Panache.

Paso 1: Dependencias del proyecto (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>

Paso 2: Definir la entidad reactiva (UserEntity.java)

Quarkus simplificó el acceso a los datos con Panache, una implementación del patrón Active-Record además de 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();
    }
}

Paso 3: Implementar el recurso REST reactivo (UserResource.java)

Utilizando RESTEasy Reactive y SmallRye Mutiny, nuestros puntos finales HTTP operan de forma totalmente asincrónica en subprocesos sin bloqueo:

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());
    }
}

Paso 4: Configuración de la aplicación (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

Tenga en cuenta que no configuramos URL de bases de datos, nombres de usuario ni contraseñas. Cuando ejecuta ./mvnw quarkus:dev, Quarkus detecta automáticamente PostgreSQL, inicia un contenedor Docker, configura tablas de esquema de base de datos y abre la interfaz de usuario de Swagger en http://localhost:8080/swagger-ui.


Paso 5: Creación y ejecución de ejecutables nativos

Para ejecutar en modo de desarrollo de codificación en vivo instantáneo:

./mvnw quarkus:dev

Para crear un binario nativo de Linux usando GraalVM dentro de un contenedor Docker (no se requiere instalación local de GraalVM):

./mvnw package -Dnative -Dquarkus.native.container-build=true

Para iniciar el binario resultante directamente en su sistema operativo:

./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 segundos de inicio!


8. Comparación de funciones estratégicas: Quarkus frente a Spring Boot

Capacidad / Característica Bota de primavera tradicional 3.x Cuarcus 3.x
Arquitectura primaria Reflexión en tiempo de ejecución y escaneo dinámico Procesamiento en tiempo de construcción y optimización de AOT
Compilación nativa Spring Native (requiere sugerencias complejas) Integración nativa de GraalVM de primera clase
Velocidad de inicio (Nativo) ~0,1 - 0,5 s ~0,01 - 0,04s
Huella RSS de memoria 140 MB - 300 MB 13MB - 40MB
Entorno de desarrollo Intercambio en caliente a través de DevTools (limitado) Codificación en vivo con reinicio cero (quarkus:dev)
Servicios de terceros Configuración manual de Docker/Testcontainers Servicios de desarrollo automático (contenedores de configuración cero)
Soporte de estándares Específico del ecosistema de primavera Especificaciones estándar de Yakarta EE y MicroProfile
Paradigma reactivo Spring WebFlux (pila separada) Motor unificado (Vert.x Core / Reactivo + Imperativo)

9. Conclusión: ¿Es hora de cambiar a Quarkus?

Quarkus no es simplemente otro marco web; representa la evolución de Java para la era nativa de la nube. Al combinar la optimización del tiempo de compilación con la compilación nativa de GraalVM, Quarkus invalida el estereotipo heredado de que Java es demasiado lento o tiene demasiada memoria para los microservicios modernos y las funciones sin servidor.

¿Cuándo debería elegir Quarkus?

  • Aplicaciones sin servidor y controladas por eventos: si está implementando microservicios en AWS Lambda, GCP Cloud Run o Knative, los archivos binarios nativos de Quarkus eliminan por completo los problemas de arranque en frío.
  • Clústeres de Kubernetes de alta densidad: si su factura de infraestructura está dominada por el consumo de RAM del clúster, la migración de servicios a Quarkus puede reducir los costos de memoria hasta en un 75 %.
  • Microservicios reactivos: si crea sistemas de alto rendimiento que requieren transmisión sin bloqueo (Kafka, gRPC, WebSockets), Quarkus ofrece un rendimiento de primer nivel listo para usar.

Java ya no está limitado por inicios lentos o tiempos de ejecución inflados. Con Quarkus, los desarrolladores de Java pueden crear aplicaciones nativas de la nube con velocidad supersónica y huella subatómica.

Ghaznix Ecosystem Products

Empower Your Digital Presence & Workflows

Explore top-tier tools built by Ghaznix to streamline your links, surveys, and brand growth.