You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何结合@ServiceConnection与GenericContainer实现自定义ConnectionDetails

问题描述

我在测试中用新的@ServiceConnection注解管理KafkaContainer,效果符合预期——自动配置时会用KafkaContainerConnectionDetails覆盖bootstrap servers属性。

现在我想对自己实现的GenericContainer子类SchemaRegistryContainer也用@ServiceConnection注解管理,但运行时抛出ConnectionDetailsNotFoundException: No ConnectionDetails found for source '@ServiceConnection source for Bean 'schemaRegistryContainer''异常。

我想为这个@ServiceConnection配置自定义的ConnectionDetails(或其他替代方案),这样SchemaRegistryContainer启动时能修改所需的应用属性,具体是要把spring.kafka.consumer.properties.schema-registry-url替换成容器的URL。

能不能通过@ServiceDefinition实现?我不想退回到用静态字段和@DynamicPropertySource的方式。

测试配置

@TestConfiguration(proxyBeanMethods = false)
public class ContainerConfig {
    public static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("confluentinc/cp-kafka");
    public static final String CONFLUENT_PLATFORM_VERSION = "7.4.1";

    @Bean
    @ServiceConnection
    KafkaContainer kafkaContainer() {
        return new KafkaContainer(DEFAULT_IMAGE_NAME.withTag(CONFLUENT_PLATFORM_VERSION));
    }

    @Bean
    @ServiceConnection
    SchemaRegistryContainer schemaRegistryContainer(KafkaContainer kafkaContainer) {
        return new SchemaRegistryContainer(CONFLUENT_PLATFORM_VERSION, kafkaContainer);
    }
}

SchemaRegistryContainer 代码

public class SchemaRegistryContainer extends GenericContainer<SchemaRegistryContainer> {

    private static final int PORT = 8081;

    public SchemaRegistryContainer(String confluentVersion, KafkaContainer kafka) {
        super("confluentinc/cp-schema-registry:" + confluentVersion);

        withExposedPorts(PORT);
        dependsOn(kafka);
        withEnv("SCHEMA_REGISTRY_KAFKASTORE_BOOTSTRAP_SERVERS", kafka.getBootstrapServers());
    }

    public String getSchemaRegistryUrl() {
        return "http://" + getHost() + ":" + getMappedPort(PORT);
    }
}
解决方案

要让自定义的SchemaRegistryContainer支持@ServiceConnection,无需使用@ServiceDefinition,只需实现自定义ConnectionDetails和对应的工厂类即可,步骤如下:

1. 定义自定义ConnectionDetails

创建实现ConnectionDetails的类,封装Schema Registry的连接信息,通过注解指定要覆盖的配置属性:

public class SchemaRegistryConnectionDetails implements ConnectionDetails {

    private final String schemaRegistryUrl;

    public SchemaRegistryConnectionDetails(String schemaRegistryUrl) {
        this.schemaRegistryUrl = schemaRegistryUrl;
    }

    @ConnectionDetailsKey("spring.kafka.consumer.properties.schema-registry-url")
    public String getSchemaRegistryUrl() {
        return schemaRegistryUrl;
    }
}

@ConnectionDetailsKey直接对应你需要替换的目标配置键,Spring Boot会自动用该值覆盖对应属性。

2. 实现ServiceConnectionDetailsFactory

创建工厂类,将SchemaRegistryContainer实例转换为上面定义的ConnectionDetails:

@Component
public class SchemaRegistryConnectionDetailsFactory implements ServiceConnectionDetailsFactory<SchemaRegistryContainer> {

    @Override
    public boolean supports(Class<?> source) {
        return SchemaRegistryContainer.class.isAssignableFrom(source);
    }

    @Override
    public SchemaRegistryConnectionDetails getConnectionDetails(SchemaRegistryContainer source) {
        return new SchemaRegistryConnectionDetails(source.getSchemaRegistryUrl());
    }
}

Spring Boot会自动检测到这个工厂类,当发现带有@ServiceConnection的SchemaRegistryContainer Bean时,自动调用它生成连接信息,完成属性覆盖。

3. 保留原有配置

你的ContainerConfig无需修改,保持@ServiceConnection注解在SchemaRegistryContainer的Bean方法上即可。

这样配置后,Spring Boot会自动识别自定义容器,通过工厂生成的ConnectionDetails自动替换spring.kafka.consumer.properties.schema-registry-url属性,完全不用退回到@DynamicPropertySource或静态字段的方式。

内容的提问来源于stack exchange,提问作者matejs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 17:55:15