Quarkus 简介:为什么 Java 开发人员转向 Supersonic Java
近三十年来,Java 一直是企业软件开发的主导力量。其丰富的生态系统、强大的面向对象基础、通过 Java 虚拟机 (JVM) 实现的平台独立性以及像 Spring Boot 这样久经考验的框架,使其成为无可争议的后端基础设施之王。
然而,向云原生架构、Kubernetes 编排、容器化 (Docker) 和 无服务器计算(AWS Lambda、Knative) 的转变暴露了传统 Java 应用程序框架中的一个严重漏洞:内存开销高和启动时间慢。
当微服务需要从 0 到 100 个副本水平扩展以响应流量峰值时,或者当无服务器功能按需执行时,等待 3 到 10 秒等待 Java 进程启动是不可接受的。现代云基础设施需要即时启动和轻量的内存消耗——传统上为 Go、Rust 或 Node.js 等语言保留的特征。
输入 Quarkus:一个专为 GraalVM 和 OpenJDK HotSpot 设计的 Kubernetes 原生 Java 框架。 Quarkus 通常被称为“超音速亚原子 Java”*,它从根本上重新设计了 Java 应用程序的编译、启动和运行方式。
在本深入指南中,我们将探讨 Java 开发人员为何采用 Quarkus、Quarkus 如何实现亚秒级启动时间和微内存占用、构建时优化的架构机制,以及如何使用 Quarkus 在 Java 中构建可用于生产的反应式微服务。
1. 传统Java的云原生困境
要理解 Quarkus 存在的原因,我们必须研究 Spring Boot 或 Jakarta EE 等传统 Java 框架的底层运行方式。
A. 沉重的运行时初始化成本
传统的 Java 框架严重依赖运行时动态反射、类路径扫描和代理生成:
- 类路径扫描:在启动过程中,JVM 会扫描类路径中的每个 JAR 文件以发现注释,例如
@Component、@Service、@Controller或@Entity。 - 注释处理和反射:框架使用反射(
Class.forName()、getDeclaredFields())来构建 bean、配置属性和依赖项的内存中图。 - 动态代理创建:CGLIB 或 ByteBuddy 在运行时内存中生成动态字节码代理,以支持面向方面编程 (AOP)、数据库事务管理 (
@Transactional) 和安全边界。 - 元空间和 RSS 膨胀:所有元数据、反映的类描述符和生成的代理必须保留在 JVM 元空间和驻留集大小 (RSS) 内的内存中。
此运行时反射循环需要大量 CPU 周期并增加堆内存消耗。传统 Java 中的基本 CRUD REST 服务在空闲时很容易消耗 140MB 到 300MB RAM,并且需要 3 到 8 秒才能启动。
B. 云计算的经济处罚
在无服务器和容器化环境中,云提供商根据两个指标收费:分配的内存(GB)和执行持续时间(毫秒)。
- 冷启动:如果无服务器功能需要 5 秒才能启动,最终用户会遇到明显的延迟,并且您需要为 5 秒的空闲启动计算付费。
- 密度和 Pod 可扩展性:在具有 16GB RAM 的工作节点的 Kubernetes 集群中,在内存耗尽之前只能运行约 40 个传统 Spring Boot 微服务实例。如果每个实例仅消耗 15MB RAM,则同一节点可以托管超过 800 个实例。
2. Quarkus 架构:将工作从运行时转移到构建时
Quarkus 通过彻底的架构范式转变解决了云原生困境:将动态操作从运行时转移到构建时。
构建时处理(提前优化)
Quarkus 不是在每次应用程序启动时执行类路径扫描、注释解析和 bean 图连接,而是在构建阶段(mvn package 或 ./gradlew build)执行所有这些繁重操作一次。
- 扩展架构和构建步骤:Quarkus 使用可插拔的扩展框架。编译应用程序时,Quarkus 扩展会解析注释、生成优化的静态字节码并预先解析依赖项注入图。
- 预烘焙元数据:所有依赖注入元数据都是预先计算的。当应用程序启动时,Quarkus 直接实例化预编译的类,而不调用反射或扫描类路径。
- 死代码消除(Tree Shaking):在构建过程中,Quarkus 会识别应用程序未使用的类、方法和库,并将它们完全删除。
当您的应用程序 JAR 或本机二进制文件生成时,所有运行时开销都已消除。 JVM 只需加载预先连接的静态字节码并立即启动。
3. GraalVM Native Image 与 OpenJDK HotSpot
Quarkus 提供了双重执行模型:它在标准 OpenJDK HotSpot 上运行速度非常快,但在编译成 GraalVM Native Image 时,它达到了最大性能潜力。
+-----------------------------------------------------------------------+
| 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 |
+----------------------------------+ +----------------------------------+
提前 (AOT) 编译和 Substrate VM
GraalVM Native Image 采用 Java 字节码并将其直接编译为特定于操作系统的独立可执行二进制文件(Linux 上的 ELF 二进制文件、macOS 上的 Mach-O、Windows 上的 EXE)。
- 封闭世界假设:GraalVM 假设所有可访问的代码、类和资源在构建时都是已知的。
- Substrate VM:本机可执行文件嵌入了一个名为 Substrate VM 的微型运行时引擎,它可以处理内存管理、线程调度和垃圾收集,而无需启动完整的 JVM 实例。
- 零反射开销:由于 Quarkus 在构建期间准备反射配置和代理定义,因此 GraalVM 原生映像编译可以顺利成功,无需原生 GraalVM 构建历史上所需的手动配置文件。
4. 性能基准:经验证据
为了说明性能上的鲜明对比,让我们检查运行标准 REST + 数据库 CRUD 服务的三种 Java 运行时配置之间的标准行业基准比较:
- 传统云原生堆栈(传统JVM / Spring Boot)
- OpenJDK HotSpot 上的 Quarkus
- GraalVM 本机映像上的 Quarkus
性能汇总表
| 公制 | 传统堆栈 (JVM) | Quarkus(热点 JVM) | Quarkus(GraalVM 本机) |
|---|---|---|---|
| 剩余 RSS 内存 | 〜140MB | 〜74MB | ~13 MB |
| REST + CRUD RSS 内存 | 〜218MB | 〜112MB | ~35 MB |
| 休息启动时间 | 〜4.3秒 | ~0.98 秒 | ~0.014 秒 (14ms) |
| REST + CRUD 启动时间 | 〜9.5秒 | ~2.0 秒 | ~0.042 秒 (42ms) |
| 可执行工件 | 大胖 JAR (~50MB) | 优化的 JAR (~20MB) | 独立的本机二进制文件 (~30MB) |
请注意,Quarkus 编译为本机映像的启动时间为 14 毫秒,比眨眼还快,并且仅消耗 13 MB RAM。这使得 Java 在无服务器和云原生部署方面与 Go 和 Rust 完全竞争。
5. 反应式和命令式双核引擎
从历史上看,Java 开发人员必须在两种互斥的编程模型之间进行选择:
- 命令式(每个请求线程):使用标准 JDBC 驱动程序和同步 REST 端点的简单、可读的阻塞代码。
- 反应式(事件循环):异步、非阻塞代码(例如,RxJava、Project Reactor)具有高吞吐量,但因复杂的回调链和难以调试而臭名昭著。
Quarkus 将两个世界统一在一个由 Eclipse Vert.x 和 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 |
+-------------------+ +-------------------+
在 Quarkus 中,非阻塞 I/O 是基础。如果您编写传统的阻塞代码,Quarkus 会自动将执行分派到托管工作线程池。如果您使用 SmallRye Mutiny(Uni<T> 和 Multi<T>)等响应式类型,则执行将保留在高性能非阻塞事件循环线程上。
6. 开发人员的乐趣:实时编码和开发服务
除了运行时性能之外,Quarkus 还提供了革命性的开发人员体验,旨在消除繁琐的构建-测试-重启反馈循环。
A. 零重启实时编码 (quarkus:dev)
当运行 mvn quarkus:dev 时,Quarkus 启动实时编码模式。您可以编辑 Java 文件、更改属性、修改 HTML 模板或更新数据库架构。
下次您在浏览器或终端中触发 HTTP 请求时,Quarkus 会检测文件更改,重新应用构建步骤,并在 500 毫秒内热重新加载应用程序。在开发过程中,您永远不需要手动停止和重新启动应用程序服务器。
B. Quarkus 开发服务(零配置测试容器)
将微服务连接到 PostgreSQL 数据库、Kafka 代理或 Redis 缓存通常需要编写 docker-compose.yml 文件并配置本地数据库端口。
使用 Quarkus 开发服务:
- 如果 Quarkus 检测到数据库依赖项(例如
quarkus-reactive-pg-client),但application.properties中没有配置数据库 URL,Quarkus 会自动启动一个 Docker 容器,通过后台的 Testcontainers 运行 PostgreSQL。 - 它将连接凭据自动注入到您正在运行的应用程序中。
- 当您停止开发模式时,容器会自行清理干净。
7. 实践演练:构建可投入生产的反应式 Quarkus 服务
让我们用 Java 构建一个干净、高性能的 Quarkus 微服务,该服务公开使用 Hibernate Reactive with Panache 连接到 PostgreSQL 数据库的 REST API。
第 1 步:项目依赖项 (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>
步骤 2:定义反应实体 (UserEntity.java)
Quarkus 使用 Panache(Hibernate 之上的 Active-Record 模式实现)简化了数据访问。
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();
}
}
步骤 3:实施响应式 REST 资源 (UserResource.java)
使用 RESTEasy Reactive 和 SmallRye Mutiny,我们的 HTTP 端点在非阻塞线程上完全异步操作:
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());
}
}
步骤 4:应用程序配置 (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
请注意,我们没有配置数据库 URL、用户名或密码!当您运行 ./mvnw quarkus:dev 时,Quarkus 会自动检测 PostgreSQL,启动 Docker 容器,设置数据库架构表,并在 http://localhost:8080/swagger-ui 打开 Swagger UI。
步骤 5:构建并执行本机可执行文件
要在即时实时编码开发模式下运行:
./mvnw quarkus:dev
要在 Docker 容器内使用 GraalVM 构建本机 Linux 二进制文件(无需本地 GraalVM 安装):
./mvnw package -Dnative -Dquarkus.native.container-build=true
要直接在操作系统上启动生成的二进制文件:
./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秒启动!
8. 战略特性比较:Quarkus 与 Spring Boot
| 能力/特点 | 传统 Spring Boot 3.x | 夸库斯 3.x |
|---|---|---|
| 主要架构 | 运行时反射和动态扫描 | 构建时处理和 AOT 优化 |
| 本机编译 | Spring Native(需要复杂的提示) | 一流的 GraalVM 本机集成 |
| 启动速度(本机) | 〜0.1 - 0.5秒 | ~0.01 - 0.04s |
| 内存 RSS 占用空间 | 140MB - 300MB | 13MB - 40MB |
| 开发环境 | 通过 DevTools 热插拔(有限) | 零重启实时编码(quarkus:dev) |
| 第三方服务 | 手动 Docker / Testcontainers 配置 | 自动开发服务(零配置容器) |
| 标准支持 | Spring 生态系统特定 | Jakarta EE 和 MicroProfile 标准规格 |
| 反应范式 | Spring WebFlux(独立堆栈) | 统一引擎(Vert.x核心/反应式+命令式) |
9. 结论:是时候改用 Quarkus 了吗?
Quarkus 不仅仅是另一个 Web 框架;它还是一个 Web 框架。它代表了 Java 向云原生时代的演变。通过将构建时优化与 GraalVM 本机编译相结合,Quarkus 消除了 Java 对于现代微服务和无服务器功能来说太慢或太占内存的传统刻板印象。
什么时候应该选择 Quarkus?
- 无服务器和事件驱动应用程序:如果您将微服务部署到 AWS Lambda、GCP Cloud Run 或 Knative,Quarkus 本机二进制文件可以完全消除冷启动问题。
- 高密度 Kubernetes 集群:如果您的基础设施费用主要是集群 RAM 消耗,那么将服务迁移到 Quarkus 可以将内存成本降低高达 75%。
- 反应式微服务:如果您构建需要非阻塞流(Kafka、gRPC、WebSockets)的高吞吐量系统,Quarkus 可以提供开箱即用的顶级性能。
Java 不再受制于缓慢的启动或臃肿的运行时。借助 Quarkus,Java 开发人员可以构建具有超音速和亚原子足迹的云原生应用程序。
Tags
Empower Your Digital Presence & Workflows
Explore top-tier tools built by Ghaznix to streamline your links, surveys, and brand growth.