Quarkus 核心

共 18 题
📑 题目列表 18 题
#
★★★

1. Quarkus 的编译时优先(Build-Time Boot)理念与 Spring 的差异

Quarkus 的"编译时优先(Build-Time Boot)"理念是什么?它和 Spring 的运行时引导(Runtime Boot)在启动机制上有哪些本质差异?

  • 构建期(Build Time)与运行期(Runtime)的职责划分
  • 编译时元数据生成与字节码增强
  • 启动时间与内存优化的根源

Quarkus 的理念是把尽可能多的处理和校验放到构建期完成,而不是运行期。在构建阶段,Quarkus 通过扩展(Extension)的 Build Step 收集所有 Bean 元数据、解析配置、做配置校验、生成字节码增强,并把这些"判定结果"固化下来;到运行期,应用只需加载已经生成好的元数据和字节码,启动时不再重复扫描、解析和反射发现。而 Spring 传统上是运行时引导(Runtime Boot):ClassPath 扫描、Bean 定义解析、配置绑定、依赖注入大多在启动时通过反射和代理完成。因此 Quarkus 在同类场景下启动更快、内存占用更低,且天然更适合 GraalVM Native Image(因为运行期不需要大量反射)。代价是开发期需要"构建一次才能看到效果",对动态改动(如配置文件热更新)的灵活性不如 Spring 运行时反射。

核心差异是"把工作前移"。Spring 把认知负担放在运行期,换取开发期的便利与动态性;Quarkus 把负担放在构建期,换取启动与内存的极致优化。理解这一点就能理解为什么 Quarkus 的构建步骤、Dev Services、Native 编译都围绕"构建期闭环"设计。

#
★★

2. QuarkusTest 的测试机制(启动隔离、@TestHTTPResource)与持续测试(Continuous Testing)

QuarkusTest 的测试机制是怎样的?它如何处理启动隔离、如何用 @TestHTTPResource 访问运行中的服务,以及什么是持续测试(Continuous Testing)?

  • QuarkusTest 的启动与隔离模型
  • @TestHTTPResource 注入 HTTP 端点
  • Continuous Testing 的增量测试机制

@QuarkusTest 通过 Quarkus 的 Test 扩展启动一个完整的 Quarkus 应用(真实 HTTP 端口或随机端口),测试与运行中的应用共享同一进程,因此测试可以访问真实依赖注入、配置和外部服务。@TestHTTPResource 用于把测试中需要访问的 HTTP 端点(如 http://localhost:8080/api)直接注入到测试字段,配合 @TestHTTPEndpoint 可以指定路径,避免手写 URL 与端口。启动隔离方面,测试类可以配置 @QuarkusTestResource 去启动或管理外部资源(如数据库、消息队列),并支持按测试类隔离或共享。持续测试(Continuous Testing)是 Quarkus 在 Dev Mode 下的能力:当源码或测试改动时,只需重新编译并运行受影响的测试,无需重启应用,实现增量验证,大大提升开发反馈速度。

QuarkusTest 的核心价值在于"测试与真实运行环境一致",避免 Mock 过多带来的失真。@TestHTTPResource 简化了端到端测试的 URL 管理;Continuous Testing 则把测试融入开发循环,配合 Dev Mode 提供快速反馈。

#
★★

3. Quarkus Dev Mode 热重载与 Build Step 的协同工作原理?

Quarkus Dev Mode 的热重载是如何工作的?它与 Build Step 是如何协同实现源码改动后快速生效的?

  • Dev Mode 的监听与重编译机制
  • Build Step 在重载过程中的作用
  • 热重载与冷启动的差异

Quarkus Dev Mode 启动后,会监听源码与资源文件的变化。当检测到改动时,它不会重启整个 JVM,而是重新执行部分 Build Step 来构建一个"增量版本"的应用,并替换已加载的类。由于绝大多数元数据在构建期已经生成,Dev Mode 的重载只需重新执行受影响的 Build Step 并热替换相关类,无需重新扫描整个类路径,因此比全量重启快得多。Build Step 是热重载的最小单元:框架把应用构建拆成一个个声明式的 Build Step,每个 Step 有输入输出,Quarkus 能够根据依赖关系判断哪些 Step 需要重跑,从而精确生成本次变更所需的产物。Dev Mode 还内置了持续测试,改动后自动运行受影响测试,形成"改代码 → 热重载 → 跑测试"的闭环。

Dev Mode 的热重载正是"编译时优先"理念的开发期体现——因为构建被拆成可重放的 Build Step,才能做到只重跑受影响部分。理解 Build Step 的依赖图,就理解了热重载为何能精准、快速。

#
★★

4. Quarkus 与 Spring API 兼容性(quarkus-spring-di、quarkus-spring-web)

Quarkus 通过 quarkus-spring-di、quarkus-spring-web 等扩展对 Spring API 提供兼容支持,这种兼容的性能如何?它是否意味着可以无缝迁移 Spring 应用?

  • Spring 兼容扩展的覆盖范围
  • 兼容层的实现机制(编译期映射)
  • 迁移的边界与限制

Quarkus 提供了一组 Spring 兼容扩展,让开发者可以用 Spring 风格的注解(如 @Autowired、@Service、@RestController、@RequestMapping 等)来写代码。这些扩展的核心机制是:在构建期把 Spring 注解翻译成 Quarkus 的 CDI 和 RESTEasy 模型并生成元数据,而不是在运行期引入完整的 Spring 容器。因此性能上仍然保留 Quarkus 编译时优先的优势,不因为用了 Spring 注解而变慢。但要注意,这种兼容并不覆盖整个 Spring 生态:它只实现常用子集(如 DI、Web MVC 基础注解、properties 部分),像 Spring Security 的复杂功能、Spring Data 的复杂查询、AOP 的完整语义等并不完全支持,需要改用 Quarkus 原生机制。所以它适合"快速上手、渐进迁移",而不是大型 Spring 应用的零成本一键迁移。

兼容层的本质是"注解翻译"。它降低了 Spring 开发者迁移门槛,但信任边界是"覆盖子集",超出子集的功能仍要回到 Quarkus 原生 API。迁移前应评估所用 Spring 特性是否在兼容范围内。

#
★★

5. Quarkus 的 Dev Mode 与热加载(Live Coding)

Quarkus 的 Dev Mode 和热加载(Live Coding)是什么?它比传统编辑-编译-重启的流程好在哪?

  • Dev Mode 的启动与运行方式
  • Live Coding 的自动重载机制
  • 与传统开发流程的对比

Quarkus Dev Mode 通过 mvn quarkus:dev./mvnw quarkus:dev 启动,它会在本地运行应用并持续监听源码、资源、配置的变化。当发生改动时,Quarkus 利用热重载机制(重新执行受影响的 Build Step、热替换类)自动更新运行中的应用,无需手动重启。Live Coding 把这一过程集成到浏览器或 IDE 中,开发者改完代码保存后,页面请求即可命中新逻辑,提供类似"即时生效"的开发体验。相比传统"编辑→编译→重启→等待启动"的流程,Dev Mode 显著缩短了迭代反馈周期,特别是配合持续测试,可以在保存后自动运行受影响的测试,第一时间发现回归。这对需要频繁调整 API、配置或业务逻辑的开发非常高效。

Dev Mode 的价值在于把"构建期重跑"与"热替换"结合,让每次改动的反馈时间从"分钟级"降到"秒级"。它依赖 Quarkus 构建产物可重放、可增量生成的特性,是编译时优先理念在开发体验上的直接收益。

#
★★

6. Quarkus 的反应式引擎(Vert.x/Mutiny)

Quarkus 的反应式引擎基于 Vert.x 与 Mutiny,它们各自扮演什么角色?如何协同支撑非阻塞编程?

  • Vert.x 作为底层网络/IO 引擎
  • Mutiny 作为响应式编程 API
  • 反应式调用链与背压

Quarkus 的反应式能力建立在 Vert.x 之上,Vert.x 提供事件循环、非阻塞网络 IO、异步 HTTP 服务器等底层基础设施,其单线程事件循环模型保证了高并发下非阻塞请求处理的确定性。Mutiny 则是 Quarkus 采用的响应式编程 API(Uni/Multi),它提供统一、可组合的异步操作符,让开发者用声明式方式编排异步任务、处理错误与背压。两者协同:Vert.x 负责真正的非阻塞 IO 与调度,Mutiny 负责把异步结果以 Uni/Multi 流的形式暴露给业务代码,并与 RESTEasy Reactive、Panache、MicroProfile Reactive Messaging 等集成。Quarkus 通过把 Mutiny 的类型与组件在构建期做类型化处理,避免了传统响应式框架的部分运行期开销。

Vert.x 是"引擎",Mutiny 是"API"。理解这一分工,就能理解为什么 Quarkus 反应式栈既能保持非阻塞能力,又能通过类型化简化开发。选型时,需要团队掌握响应的编程思维(背压、错误传播、异步编排)。

#
★★

7. Quarkus 的构建期处理,为什么能在构建期完成配置验证与字节码增强?

Quarkus 为什么能在构建期完成配置验证与字节码增强?这背后的机制是什么?

  • Build Step 与构建产物(Generated Bytecode)
  • 配置模型的构建期绑定
  • 字节码增强的时机与方法

Quarkus 把应用的"固化"交给构建期:它通过扩展定义的 Build Step 在构建期扫描、解析并生成最终需要的元数据与字节码。配置验证方面,Quarkus 在构建期读取配置并绑定到类型化的配置模型,如果配置缺失或类型错误,在构建阶段就会报错,而不是等到运行期才暴露,从而把配置错误前置。字节码增强方面,Quarkus 在构建期使用字节码操作(如 Jandex 索引、ASM)对类进行改写,例如为 Panache 实体生成访问器、为 CDI 方法生成拦截器字节码、为 REST 端点生成路由信息,运行期直接加载这些增强后的字节码。因为构建期已经把"该做什么"决定好了,运行期就不需要再通过反射去发现与拦截,这既保证了正确性(错误提前暴露),又降低了启动开销。

关键机制是"构建产物封闭":构建期把所有决策固化为字节码与元数据,运行期只是执行。配置验证前置和字节码增强都是同一思想的不同体现,也是它与 Spring 运行时反射式处理的最大分水岭。

#
★★

8. Quarkus 的响应式与非阻塞栈,Vert.x 与 RESTEasy Reactive 的集成如何?

Quarkus 的响应式、非阻塞栈中,Vert.x 与 RESTEasy Reactive 是如何集成的?它们如何支撑高并发 JAX-RS 端点?

  • RESTEasy Reactive 的构建期路由生成
  • 与 Vert.x 事件循环的绑定
  • 非阻塞端点的处理模型

RESTEasy Reactive 是 Quarkus 响应式 JAX-RS 实现,它在构建期检查端点方法签名(是否返回 Uni/Multi、是否声明阻塞),据此生成优化的路由与序列化代码,并在运行期把 HTTP 请求交给 Vert.x 事件循环处理。与阻塞式实现不同,RESTEasy Reactive 的处理器默认在事件循环线程上执行,只有显式标记为阻塞的方法才会被调度到 worker 线程,从而避免阻塞事件循环。它通过构建期生成针对每个方法的、类型化的无缝序列化器(如 JSON-B/Jackson 的生成代码),避免运行期反射与动态分派,显著降低请求处理开销。Vert.x 提供 HTTP 服务器与事件循环,RESTEasy Reactive 作为其上层的路由引擎,两者在构建期就完成了绑定,因此既能保持非阻塞高并发,又能减少抽象层开销。

集成点在于"构建期把端点路由与事件循环绑定"。非阻塞的达成依赖两个前提:方法签名能在构建期判定(阻塞/非阻塞),以及运行期把请求留在事件循环线程。理解这一点就能理解 RESTEasy Reactive 的性能来源。

#
★★

9. Quarkus 的 Panache(active record vs repository)数据访问模式

Quarkus 的 Panache 提供哪两种数据访问模式?Active Record 与 Repository 有什么差异,应如何选择?

  • Active Record 模式(实体操作)
  • Repository 模式(仓储操作)
  • 两种模式的适用场景

Panache 提供两种 JPA 数据访问模式:Active Record 与 Repository。Active Record 模式让实体类直接继承 PanacheEntity,数据访问方法(如 findBy、list、persist、delete)直接放在实体上,实体既是数据又是数据操作对象,代码简洁、适合领域逻辑简单、实体自带行为的场景。Repository 模式则让实体继承 PanacheRepository 或实现 PanacheRepository 接口,把数据访问封装在独立的仓储类中,实体只承载数据,更符合"仓储模式"的分层思想,适合复杂业务、需要复用查询逻辑、以及测试时便于 Mock 的场景。Panache 在构建期通过字节码增强为实体和仓储生成静态查询方法,避免运行期反射,同时基于 JPA 提供流式查询(PanacheQuery)。选择时,简单 CRUD 倾向 Active Record,复杂聚合与解耦倾向 Repository。

两种模式本质是"数据访问职责放哪"的取舍。Active Record 快但耦合,Repository 清晰但样板多。Panache 的构建期增强让两者都有较好的性能,选型主要依据业务复杂度与团队风格。

#
★★

10. Quarkus 的安全体系(Quarkus Security、OIDC/JWT)与 Spring Security 的差异

Quarkus 的安全体系(Quarkus Security、OIDC/JWT)与 Spring Security 在架构和实现上有哪些差异?

  • Quarkus Security 的构建期处理
  • OIDC/JWT 的集成方式
  • 与 Spring Security 的过滤器链对比

Quarkus Security 采用构建期优先的方法:安全配置、角色映射、权限注解(@RolesAllowed、@PermitAll 等)在构建期被解析并固化,认证/授权逻辑尽量在构建期确定,避免运行期反射;而 Spring Security 的过滤器链是运行期动态装配的,安全规则在请求时通过过滤器链与拦截器动态计算。Quarkus 通过 quarkus-oidc 扩展集成 OIDC 与 JWT,支持授权码流程、令牌验证(JWT 签名校验)、角色映射,并可在 Native 下工作;Spring Security 则通过 OAuth2 Resource Server、JWT Decoder 等实现类似能力,但依托更庞大的运行时 Bean 体系。Quarkus 的权限校验更依赖构建期生成的元数据与注解,运行时开销小;Spring Security 灵活强大、社区资源丰富,但运行时反射与代理更多。因此 Quarkus 适合需要极致性能与 Native 的场景,Spring Security 适合需要高度定制与复杂安全策略的场景。

差异根源仍是"构建期 vs 运行期"。Quarkus 把安全规则前移换取性能,Spring Security 用运行期动态灵活性换取可定制性。实际选型要考虑安全策略的复杂度与对 Native 的需求。

#

11. Quarkus 的分布式配置与 Kubernetes 集成

Quarkus 如何支持分布式配置以及与 Kubernetes 的集成?它如何管理外部化配置?

  • 配置源的优先级与组合
  • Kubernetes ConfigMap/Secret 集成
  • 运行期的配置刷新

Quarkus 采用统一的配置模型,支持属性文件、环境变量、系统属性、命令行参数等多级配置源,并定义了明确的优先级,同时支持通过 ConfigSource 自定义新的配置源。与 Kubernetes 集成时,Quarkus 提供 quarkus-kubernetes-client 与相关扩展,可以把 Kubernetes ConfigMap 和 Secret 作为配置源读取,实现配置与秘密的集中管理;配置变更可由 ConfigMap 更新触发,配合 Quarkus 的配置刷新(@ConfigProperty 与运行时配置)在应用内生效。Quarkus 的配置在构建期和运行期有区分:构建期配置在构建时固化,运行期配置才可在运行期读取,这样既保证 Native 兼容,也支持动态调整。整体上,Quarkus 面向 Kubernetes 做了深度适配,让配置管理与部署环境无缝衔接。

分布式配置的关键是"配置源可组合 + 外部化"。Kubernetes 集成让配置中心与部署平台统一,而构建期/运行期配置的区分则保证了 Native 与动态性的平衡。

#

12. Quarkus 的 GraalVM Native Image 原生支持

Quarkus 如何支持 GraalVM Native Image?它如何帮助我们生成原生可执行文件?

  • Native Image 的编译原理
  • 扩展的反射/序列化元数据收集
  • 构建与启动优势

GraalVM Native Image 把 JVM 应用提前编译(AOT)为原生可执行文件,运行时不依赖 JVM 解释执行,因而启动极快、内存占用低。Quarkus 对 Native Image 做了深度支持:每个扩展都会在构建期声明并生成 Native 所需的反射、资源、序列化、代理等元数据(通过 GraalVM 的 reflection/build-time 配置),避免原生编译时因反射找不到类而失败。Quarkus 的构建工具(如 mvn package -Pnative)会自动调用 GraalVM 编译并注入这些元数据。由于 Quarkus 本身是构建期优先,很多反射在构建期已被消除,使得原生编译更顺畅、产物更小。原生可执行文件启动通常在毫秒级、内存占用大幅下降,非常适合微服务、Serverless 与冷启动敏感场景。代价是编译时间长、需要额外工具链,且部分动态能力受限。

Quarkus 与 Native Image 的契合源于"构建期优先"——动态反射少,元数据易收集。理解这点就能理解为什么 Quarkus 是 Native 友好的首选之一,以及为什么原生编译需要扩展提供元数据。

#

13. Quarkus 与 Spring Boot DevTools 体验对比的真实差异?

Quarkus Dev Mode 与 Spring Boot DevTools 在开发体验上的真实差异是什么?

  • 热重载机制对比
  • 重启与类加载策略
  • 持续测试与反馈速度

Spring Boot DevTools 的核心是"自动重启":当 ClassPath 变化时,它会用两个类加载器把类加载到新的 JVM 上下文(restart),让静态资源变化即时生效,而类变更则触发重启。其本质仍是"重启应用",只是比手动重启快、且不会丢失状态(如已有连接)。Quarkus Dev Mode 则是热重载:只重跑受影响的 Build Step 并热替换类,无需重启整个应用,配合持续测试能自动运行受影响测试。因此 Quarkus 的反馈速度更快、更接近"即时生效",但机制上更复杂(依赖构建期产物);Spring Boot DevTools 简单直观、生态成熟,但类变更仍要重启。对大型应用,Spring Boot 重启可能仍需数秒,而 Quarkus 增量重载通常更快。此外 Quarkus Dev Mode 还集成 Dev UI、Dev Services 等,开发体验更一体化。

核心差异是"重启 vs 热替换"。DevTools 是聪明的重启(restart),Quarkus 是构建期驱动的实时热替换。选择取决于团队对反馈速度与配置复杂度的取舍。

#

14. Quarkus 的扩展机制(Extension)与 CDI 注入

Quarkus 的扩展机制(Extension)是什么?它如何与 CDI 注入协作?

  • Extension 的构建期角色
  • 与 CDI 容器集成
  • 第三方库如何适配

Quarkus 扩展(Extension)是框架扩展点的核心机制,它在构建期运行,通过 Build Step 扫描、验证并生成元数据与字节码,把第三方库的能力"固化"进 Quarkus 应用。扩展由两部分组成:构建期处理器(Build Step,运行在构建期)和运行期组件(Runtime,运行期加载)。扩展与 CDI 注入协作的方式是:扩展会把第三方库的 CDI Bean 注册进 Quarkus 的 CDI 容器(基于 ArC),让开发者在业务代码中通过 @Inject 正常注入这些库提供的组件。扩展还可以定义 CDI 相关的 Build Item,让其他扩展或应用引用。由于 Bean 元数据在构建期生成,CDI 注入在运行期无需反射,既快又对 Native 友好。开发者若要为第三方库编写扩展,主要是实现构建期 Build Step 来注册 Bean 与生成元数据。

扩展是 Quarkus 生态的"插件化"机制,CDI 注入则是其暴露给业务的统一入口。扩展在构建期把库组件注册进 CDI,运行期直接注入,实现了"第三方库无缝接入 Quarkus"。

#

15. Quarkus 与 GraalVM,扩展(extension)如何驱动原生编译的元数据生成?

在 Quarkus 与 GraalVM 的协作中,扩展是如何驱动原生编译所需元数据的生成的?

  • 扩展与 GraalVM 元数据的关系
  • 反射/序列化/资源元数据的收集
  • 构建期 vs 运行期

在 Native Image 编译中,GraalVM 需要知道哪些类要被反射、序列化、加载资源,这些信息以元数据(reflection-config、resource-config、serialization-config 等)形式提供,否则程序可能在运行期抛 ClassNotFoundException。Quarkus 扩展在构建期就通过 Build Step 收集并生成这些元数据:扩展了解自己依赖库的类结构,能确定哪些类需要反射、哪些需要序列化、哪些资源需要打包,从而生成对应的 GraalVM 配置。Quarkus 还会读取库声明的元数据(如 reflection 注解)并纳入。由于 Quarkus 本身构建期优先、反射少,这份元数据相对精简,原生编译更顺畅。所以扩展是"第三方库 ↔ Native 编译"之间的桥梁,它把库的运行时需求翻译成 GraalVM 能理解的配置。

扩展驱动元数据生成的本质是"把库的运行时反射需求提前告知编译器"。没有扩展,GraalVM 无法凭空知道库需要哪些反射;有了扩展生成的元数据,才可能 Native 化。这是 Quarkus 生态原生编译的基石。

#

16. Quarkus 的 Dev Services,开发期容器化依赖的自动启动如何?

Quarkus 的 Dev Services 是什么?它如何自动启动开发期的容器化依赖(如数据库、消息队列)?

  • Dev Services 的自动启动能力
  • 与 Docker 的集成
  • 开发体验提升

Dev Services 是 Quarkus 在 Dev Mode 和测试环境下自动启动外部依赖(如 PostgreSQL、MySQL、Kafka、Redis 等)的机制。当应用配置了某类数据源或消息系统时,Dev Services 会自动创建一个对应的 Docker 容器,并自动配置连接信息(端口、用户名、密码、连接串),开发者无需手动准备和管理这些服务。它还能在测试期间用相同容器提供隔离的测试环境,测试结束自动清理。Dev Services 通过检测本机 Docker 或容器运行时来工作,并支持按需关闭(quarkus.devservices.enabled=false)或自定义容器镜像。它极大简化了本地开发与测试的基础设施搭建,让"开箱即用"的体验贯穿整个开发周期。

Dev Services 的价值是把"外部依赖的管理"从人工操作自动化。它把容器编排能力下沉到开发期,开发者专注业务代码,基础设施由 Quarkus 按需拉起,显著提升开发效率与一致性。

#

17. Quarkus 扩展机制,如何为第三方库编写 Quarkus extension?

如何为第三方库编写一个 Quarkus extension?编写扩展需要哪些步骤与关键组件?

  • Extension 的构建期处理器(Build Step)
  • 运行期组件与配置
  • 注册流程与元数据生成

为第三方库编写 Quarkus 扩展,通常分两部分:构建期处理器(deployment)与运行期组件(runtime)。开发步骤大致为:1) 创建 extension 模块结构,包含 runtime 与 deployment 两个子模块;2) 在 runtime 模块声明库的依赖与运行期配置;3) 在 deployment 模块实现 Build Step,用 @BuildStep 注解方法,在构建期扫描库的类、注册 CDI Bean、生成元数据(如通过 AdditionalBeanBuildItem 注册 Bean)、校验配置;4) 生成 Build Item 供其他扩展消费,或消费框架提供的 Build Item;5) 通过 META-INF/services 或 Quarkus 的扩展描述文件(quarkus-extension.yaml)声明扩展。扩展需要处理构建期与运行期的分离,构建期只做生成与校验,运行期提供实际组件。完成后,应用只需在 pom 中加入该扩展依赖即可获得对应能力。

编写扩展的核心是"用 Build Step 在构建期把库翻译成 Quarkus 可用的元数据与 Bean"。理解 Build Item 的输入输出与构建期/运行期隔离,是编写正确扩展的关键。

#

18. Quarkus 的 CDI 实现,编译期 Bean 元数据与运行期启动优化如何?

Quarkus 的 CDI 实现(ArC)是如何通过编译期 Bean 元数据实现运行期启动优化的?

  • ArC 的构建期 Bean 发现
  • 编译期元数据与字节码生成
  • 运行期启动开销的降低

Quarkus 的 CDI 实现是 ArC,它采用构建期优先:在构建期对应用的 Bean 进行发现、分析、类型校验,并生成 Bean 元数据与字节码(如 Bean 描述符、注入点、拦截器)。运行期启动时,ArC 直接加载这些已生成的元数据,无需再扫描类路径、解析注解、做反射实例化,因此启动更快、内存占用更低。ArC 还支持在构建期生成无反射的注入代码,Bean 的创建与注入尽可能用直接方法调用而非反射,进一步降低运行期开销。同时 ArC 保持 CDI 规范兼容,支持 @Inject、@ApplicationScoped、@Qualifier、拦截器等标准语义。这种"编译期 Bean 元数据 + 运行期直接加载"的机制,正是 Quarkus 快速启动与 Native 友好的核心支撑之一。

ArC 把"发现与装配 Bean"的昂贵工作前移到构建期,运行期只做加载。理解这一点,就能理解 Quarkus 启动快与内存省的来源,以及与 Spring 运行时反射注入的本质差异。