
本文详解如何为任意第三方 web 服务(如自建 api、mock 服务或外部依赖)编写 quarkus 自定义 dev service 扩展,实现本地开发时自动拉起容器、动态注入配置,并在 dev ui 中统一管理。
本文详解如何为任意第三方 web 服务(如自建 api、mock 服务或外部依赖)编写 quarkus 自定义 dev service 扩展,实现本地开发时自动拉起容器、动态注入配置,并在 dev ui 中统一管理。
Quarkus 的 Dev Services 是其开发者体验的核心优势之一:它能在 quarkus:dev 模式下,自动检测未显式配置的依赖(如 PostgreSQL、Redis、RabbitMQ),并基于 Testcontainers 启动轻量级容器化服务实例,同时将连接参数(URL、端口、凭据等)无缝注入运行时配置。但该机制默认仅覆盖官方支持的扩展(如 quarkus-jdbc-postgresql)。当你需要为非标准依赖服务(例如内部微服务、契约测试 Mock Server 或私有 SaaS 接口代理)启用同等自动化能力时,就必须通过编写自定义 Quarkus 扩展来扩展 Dev Services 生态。
✅ 正确路径:编写专用 Quarkus 扩展
不同于测试阶段使用 QuarkusTestResourceLifecycleManager(仅作用于 @QuarkusTest),Dev Service 必须在构建期注册,由 Quarkus 构建流程识别并调度。因此,唯一合规且可被 Dev UI 发现的方式是创建一个 Quarkus 扩展(Extension),并在其中声明 DevServicesResultBuildItem。
1. 初始化扩展骨架
使用 Quarkus CLI 快速生成基础结构(推荐 Quarkus 3.2+):
mvn io.quarkus.platform:quarkus-maven-plugin:3.16.0:create-extension -N \ -DgroupId=org.acme \ -DextensionId=quarkus-devservice-myapi \ -DclassNamePrefix=MyApi
该命令将生成标准 Maven 模块,含 runtime/ 和 deployment/ 子模块,核心逻辑位于 deployment/src/main/java/.../MyApiProcessor.java。
客服回复模板。售前咨询、售后处理、退换货、投诉回复、好评引导、升级处理、行业FAQ、满意度挽回。Customer service reply templates for pre-sale, after-sale, returns, complaints, escalation, FAQ generation, s...
2. 实现 Dev Service 构建步骤
在 Processor 类中添加带条件约束的 @BuildStep 方法,确保仅在开发模式(LaunchMode.DEVELOPMENT)且全局 Dev Services 启用时执行:
@BuildStep(onlyIfNot = IsNormal.class, onlyIf = GlobalDevServicesConfig.Enabled.class)
public DevServicesResultBuildItem createMyApiDevService(
LaunchModeBuildItem launchMode,
Config config) {
// 1. 定义镜像与容器(复用 Testcontainers)
DockerImageName image = DockerImageName.parse("acme/my-api-mock:1.2");
MyApiContainer container = new MyApiContainer(image)
.withEnv("API_TIMEOUT_MS", "5000")
.withEnv("MOCK_MODE", "strict");
// 2. 启动容器(Quarkus 会自动处理生命周期)
container.start();
// 3. 构造运行时配置映射(供应用代码读取)
Map<string string> devProps = Map.of(
"myapi.base-url",
"http://" + container.getHost() + ":" + container.getMappedPort(8080),
"myapi.health-check-path", "/actuator/health"
);
// 4. 返回可被 Dev UI 识别的构建项
return new DevServicesResultBuildItem.RunningDevService(
"my-api-mock", // Feature 名称(显示在 Dev UI)
container.getContainerId(), // 容器 ID(用于状态追踪)
container::stop, // 停止回调(Quarkus 自动调用)
devProps // 动态注入的配置
).toBuildItem();
}
// 自定义容器类(继承 GenericContainer,专注就绪判断与端口映射)
private static class MyApiContainer extends GenericContainer<myapicontainer> {
private static final int HTTP_PORT = 8080;
public MyApiContainer(DockerImageName image) {
super(image);
}
@Override
protected void configure() {
withNetwork(Network.SHARED); // 共享网络,便于服务发现
addExposedPorts(HTTP_PORT);
waitingFor(Wait.forLogMessage(".*Started MyApiMockApplication.*", 1)); // 关键:就绪探针
}
public Integer getMappedPort() {
return getMappedPort(HTTP_PORT);
}
}</myapicontainer></string>
✅ 关键要点:
waitingFor(...)是强制要求 —— Quarkus 依赖此判断容器是否真正就绪,避免应用启动时连接失败;- 使用
Network.SHARED确保容器与 Quarkus 应用在同一 Docker 网络,支持host.docker.internal或容器别名解析;- 返回的
DevServicesResultBuildItem将自动触发 Dev UI 的服务卡片渲染,并支持一键启停。
3. 在应用中启用与消费
- 在目标 Quarkus 应用的
pom.xml中添加扩展依赖:<dependency><groupid>org.acme</groupid><artifactid>quarkus-devservice-myapi</artifactid><version>1.0.0-SNAPSHOT</version></dependency>
- 配置优先级:Dev Service 提供的属性会自动覆盖
application.properties中同名配置(如myapi.base-url),无需额外代码。 - 启动开发模式:
quarkus dev→ 访问http://localhost:8080/q/dev即可见 “My API Mock” 服务卡片,含状态、日志、重启按钮。
⚠️ 注意事项与最佳实践
-
不要在
@PostConstruct或@Startup中手动启动容器:这绕过 Quarkus 生命周期管理,导致 Dev UI 无法感知、热重载失效、进程退出时残留容器; -
避免硬编码镜像标签:通过
@ConfigItem注入Config,支持quarkus.myapi-devservice.image-name=acme/my-api-mock:latest等灵活配置; -
健康检查必须可靠:若
waitingFor超时(默认 60s),Quarkus 将终止启动并报错 —— 建议在 Mock 服务中输出明确就绪日志; -
调试技巧:添加
-Dquarkus.log.category."io.quarkus.devservices".level=DEBUG查看 Dev Services 启动细节; -
生产隔离:Dev Service 仅在
dev/test模式生效,prod模式下自动忽略,无需额外开关。
通过以上方式,你不仅复用了 Quarkus 原生的 Dev Services 体验,更将团队内部服务的本地联调标准化、可视化、自动化 —— 这正是云原生 Java 开发效率跃迁的关键一环。










