编写 Dev Service
了解如何在扩展中开发 Dev Service,以便在开发模式下替换外部服务。
创建 Dev Service
如果您的扩展提供用于连接到外部服务的 API,则最好提供 Dev Service 实现。
首先,您必须将以下依赖项添加到构建文件的 deployement 模块中
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-devservices-deployment</artifactId>
</dependency>
implementation("io.quarkus:quarkus-devservices-deployment")
然后,在扩展处理器类中添加一个新的构建步骤,该步骤返回 DevServicesResultBuildItem
。 在这里,使用了 hello-world
镜像,但您应该为您的服务设置正确的镜像。
@BuildStep(onlyIfNot = IsNormal.class, onlyIf = DevServicesConfig.Enabled.class)
public DevServicesResultBuildItem createContainer() {
DockerImageName dockerImageName = DockerImageName.parse("hello-world");
GenericContainer container = new GenericContainer<>(dockerImageName)
.withExposedPorts(SERVICE_PORT, OTHER_SERVICE_PORT)
.waitingFor(Wait.forLogMessage(".*Started.*", 1))
.withReuse(true);
container.start();
String newUrl = "http://%s:%d".formatted(container.getHost(),
container.getMappedPort(SERVICE_PORT));
Map<String, String> configOverrides = Map.of("some-service.base-url", newUrl);
return new DevServicesResultBuildItem.RunningDevService(FEATURE,
container.getContainerId(),
container::close,
configOverrides).toBuildItem();
}
使用此代码,如果将扩展添加到测试应用程序并运行 quarkus dev
,您应该能够看到您的容器启动。 但是,应用程序将无法连接到它,因为没有暴露端口。 要暴露端口,请将 withExposedPorts
添加到容器构造中。 例如,
GenericContainer container = new GenericContainer<>(dockerImageName)
.withExposedPorts(SERVICE_PORT, OTHER_SERVICE_PORT);
Testcontainers
会将这些端口映射到主机上的随机端口。 这避免了端口冲突,但也带来了一个新问题 – 应用程序如何连接到容器中的服务?
为了允许应用程序连接,扩展应该使用映射的端口覆盖服务的默认配置。 这必须在启动容器后完成。 例如,
container.start();
String serviceUrl = "http://%s:%d".formatted(container.getHost(),
container.getMappedPort(SERVICE_PORT));
Map<String, String> configOverrides = Map.of("some-service.base-url",
serviceUrl);
其他配置覆盖可以包含在同一映射中。
等待容器启动
您应该向容器构造添加一个 .waitingFor
调用,以等待容器启动。 例如
container.waitingFor(Wait.forLogMessage(".*Started.*", 1));
等待端口打开是另一种选择。 有关等待策略的完整讨论,请参阅 Testcontainers 文档。
配置 Dev Service
要配置 Dev Service 启动过程,您的构建步骤可以在其构造函数中接受 ConfigPhase.BUILD_TIME
配置类。 例如,
@BuildStep(onlyIfNot = IsNormal.class, onlyIf = GlobalDevServicesConfig.Enabled.class)
public DevServicesResultBuildItem createContainer(MyConfig config) {}
您可能希望使用此配置来设置固定端口或设置镜像名称,例如。
if (config.port.isPresent()) {
String portBinding = "%d:%d".formatted(config.port.get(), SERVICE_PORT);
container.setPortBindings(List.of(portBinding));
}