Quarkus VS Spring Boot
Quarkus 是 Red Hat 推出的云原生 Java 框架,定位为「Supersonic Subatomic Java」。本文从 Spring Boot 开发者的视角出发,对比两者的设计理念、依赖注入机制、响应式编程支持和启动性能表现。Quarkus 通过构建时元数据处理和 GraalVM 原生镜像实现毫秒级启动和极低内存消耗,适合 Kubernetes 和 Serverless 场景;Spring Boot 则以生态丰富和社区成熟见长。两者并非替代关系,而是针对不同场景的互补选择。
TL;DR
- Quarkus:编译时 IoC + GraalVM 原生镜像 = 毫秒启动 + 超低内存
- Spring Boot:运行时反射 + 动态代理 = 灵活 + 启动慢(硬伤)
- 👉 如果你的服务要跑在 K8s 里、或者做 Serverless,Quarkus 值得尝试
- 👉 如果你追求生态丰富、文档完善、社区成熟,Spring Boot 依旧稳如老狗
Intro
Quarkus:Supersonic Subatomic Java,「超音速亚原子 Java」🚀 Cool!
👉 来自官方的介绍:专为快速启动、高吞吐量和低资源消耗而设计。
- Container First:轻量级 Java 应用程序,最适合在容器中运行。
- Cloud Native:Quarkus是为Kubernetes建立的,使其能够轻松部署应用程序,而无需了解该平台的所有复杂性。
- Versatile:从小型微服务到大型单体应用。
- Fast startup:在构建时完成更多工作,启动速度快。
- Unify imperative and reactive:统一命令式和响应式:将非阻塞和命令式开发风格统一在一个编程模型下。
- Standards-based:基于你常用和喜爱的标准与框架(RESTEasy and JAX-RS, Hibernate ORM and JPA, Netty, Eclipse Vert.x, Eclipse MicroProfile, Apache Camel...)
📦 All under ONE framework.
🔍 从自己熟悉的视角出发,理解 Quarkus 在解决什么问题 ?
我们知道 Spring Boot 通过自动配置,内嵌容器等方式已经非常进步的做到了开箱即用,是 Spring 生态顺应云原生趋势的进步。
Quarkus 不是 Spring Boot 的替代品,而是一个针对特定场景的补充 --> 让你的服务在云上跑得更舒服。
它解决的核心问题是:传统 Java 框架在云原生场景下太重了。
- Spring Boot:灵活、成熟、生态好,适合大多数场景
- Quarkus:快、轻、省,适合 K8s / Serverless / 容器优先的场景
一、设计理念:两条完全不同的路
先来看个表格:
| 对比维度 | Spring Boot | Quarkus |
|---|---|---|
| 核心理念 | 「约定大于配置」,简化 Spring 开发 | 「容器优先」,为云原生而生 |
| 设计哲学 | 运行时灵活,依赖注入、反射、AOP 全上 | 编译时搞定一切,运行时要快要轻 |
| 启动时间 | 慢(秒级) | 极快(毫秒级,GraalVM 原生更是变态) |
| 内存占用 | 高(至少几百 MB) | 低(原生镜像可以 <100MB) |
| 生态 | 极其丰富 | 相对年轻但覆盖核心场景 |
Spring Boot 的思路是:我给你铺好路,你随便玩。启动慢点怎么了?服务器扛得住。
Quarkus 的思路是:别废话,上来就要快。你要跑在容器里?要 K8s 调度?要 Serverless 冷启动?那就别搞那些运行时反射的老套路了。
本质区别就一句话:
Spring Boot 把能做的都留到运行时做,Quarkus 把能做的都提前到编译时做。
二、依赖注入:ArC vs Spring
这部分我之前在分析 Spring Boot @ConfigurationProperties 源码时详细聊过,有兴趣可以翻一下。
Spring 的依赖注入是运行时反射:
- 启动时扫 classpath,找到所有
@Component/@Service - 通过反射创建 bean 实例
- 根据
@Autowired找到依赖关系,注入
这套流程熟悉吧?但问题在于:反射是要成本的。
Quarkus 搞了个 ArC(Arc = Annotation + CDI),基于 CDI Lite 标准。核心区别在于:
- 编译时:Quarkus 的构建工具会扫描你的代码,生成直接的依赖注入代码
- 运行时:不再需要反射,直接调用生成好的代码
简单理解就是:Spring Boot 是「边跑边组装」,Quarkus 是「跑之前就组装好了」。
代码对比
Spring Boot:
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
}Quarkus(其实一样写,但底层原理不同):
@Service
public class UserService {
@Inject
private UserRepository userRepository;
}写法上几乎没区别,但 ArC 在编译时就把 @Inject 的目标解析好了,不再是运行时反射。
三、响应式编程:WebFlux vs Mutiny
Spring Boot 有 WebFlux,用的是 Project Reactor(Mono / Flux)。
Quarkus 也有响应式编程,用的是 Mutiny。
先说个人感受:Mutiny 比 Reactor 好上手。
为什么?
Reactor 的概念有点绕:Flux 可以是 0..N 也可以是 1..N,不读几遍文档总觉得差点意思。
Mutiny 就直观多了:
Uni<T>:异步结果,类似于 RxJava 的Maybe或Single,有且只有一个结果Multi<T>:多个异步结果,类似于Flux,可以有零个或多个
代码对比
Spring WebFlux:
@Service
public class UserService {
public Flux<User> findAll() {
return userRepository.findAll();
}
}Quarkus Mutiny:
@Service
public class UserService {
public Multi<User> findAll() {
return userRepository.findAll();
}
}基本一样的思路,但 Mutiny 的命名更符合直觉。
再来看一个更有意思的对比 —— 阻塞 vs 非阻塞:
Spring WebFlux:
@GetMapping("/{id}")
public Mono<User> getUser(@PathVariable Long id) {
return userRepository.findById(id); // 看起来像同步,但底层是非阻塞
}Quarkus RESTEasy Reactive + Mutiny:
@GetMapping("/{id}")
public Uni<User> getUser(@PathVariable Long id) {
return userRepository.findById(id);
}两者都是非阻塞的,但 Quarkus 的区别在于:如果你不加 Uni,直接返回 User,它默认就是阻塞的。
简单说:Quarkus 对响应式的支持更「一是一二是二」,你用 Uni 就是非阻塞,用普通类型就是阻塞,没有魔法。
四、启动性能:这才是 Quarkus 的主场
说了这么多理念和写法,实际跑起来差多少?
先看一下官方给出的参考数据(不同硬件环境有差异):
| 指标 | Spring Boot (JVM) | Quarkus (JVM) | Quarkus (Native) |
|---|---|---|---|
| 启动时间 | 秒级 | 亚秒级 ~1s | 毫秒级 <0.1s |
| 内存占用 | 几百 MB | 约 100-200MB | < 50MB |
| JIT 预热 | 需要 | 需要 | 不需要 |
这些数字在不同机器上会有差异,但趋势是确定的:
- Quarkus 在 JVM 模式下已经比 Spring Boot 快很多
- Quarkus + GraalVM 原生镜像 = 开挂级别的性能
为什么快?
核心就三点:
- 构建时元数据处理:不需要在启动时扫 classpath、解析注解、创建反射代理
- 静态代码生成:把原本运行时做的事,提前到编译时做好
- GraalVM 原生镜像:直接编译成机器码,不需要 JVM,进一步减少内存和启动时间
五、生态对比:Spring Boot 依旧是王者
说完 Quarkus 的好,也得说点实在的。
Spring Boot 的优势:
- 生态极其成熟:Spring Cloud、Spring Security、Spring Batch... 要啥有啥
- 文档完善:踩的坑前人都踩过,Stack Overflow 一搜一堆
- 社区庞大:出了问题不慌,总有人遇到过
Quarkus 的挑战:
- 生态相对年轻:有些场景的扩展还不如 Spring 全
- 学习曲线:虽然写法和 Spring Boot 很像,但底层原理不同,排查问题时要心里有数
- 工具链:本地开发体验还在不断完善