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

取消注释CosmosDB配置方法后Spring Boot应用启动失败求助

问题排查:取消LocalCosmosDBConfig方法注释后Bean创建失败导致应用无法启动

问题背景

使用Java、Akka框架与Azure Cosmos DB开发的应用,取消LocalCosmosDBConfig.java中的cosmosAsyncClient或cosmosConfig方法注释后,出现Bean创建警告,最终抛出错误导致应用无法启动。

相关代码

CosmosDBConfig.java

@Slf4j
@Configuration
@ConditionalOnProperty("condition")
public abstract class CosmosDBConfig extends AbstractCosmosConfiguration {

    protected final CosmosProperties cosmosProperties;

    protected CosmosDBConfig(CosmosProperties cosmosProperties) {
        this.cosmosProperties = cosmosProperties;
    }

    @Override
    public CosmosConfig cosmosConfig() {
        return CosmosConfig.builder()
            .enableQueryMetrics(cosmosProperties.isQueryMetricsEnabled())
            .responseDiagnosticsProcessor(
                responseDiagnostics -> log.info("{} Response Diagnostics {}",
                    getClassName(), responseDiagnostics
                ))
            .build();
    }

    protected CosmosClientBuilder cosmosClientBuilder() {
        CosmosClientBuilder builder = createCosmosClientBuilder();
        setCosmosCredentials(builder);
        return builder;
    }

    @Override
    public CosmosAsyncClient cosmosAsyncClient(CosmosClientBuilder cosmosClientBuilder) {
        return CosmosFactory.createCosmosAsyncClient(cosmosClientBuilder);
    }

    protected void setCosmosCredentials(CosmosClientBuilder builder) {
        if (StringUtils.hasText(getKey())) {
            log.info("Connecting to Cosmos DB using Azure Key Credentials");
            builder.credential(new AzureKeyCredential(getKey()));
        } else {
            log.info("Connecting to Cosmos DB using Azure Token Credentials");
            builder.credential(new DefaultAzureCredentialBuilder().build());
        }
    }

    protected String getClassName() {
        return this.getClass().getSimpleName().replaceAll("\\$.*", "");
    }

    // 子类需实现创建带专属连接属性的cosmosClientBuilder
    abstract CosmosClientBuilder createCosmosClientBuilder();

    // 子类需实现获取专属连接密钥的逻辑
    abstract String getKey();
}

LocalCosmosDBConfig.java

@Slf4j
@Configuration
@ConditionalOnProperty("condition")
@EnableReactiveCosmosRepositories(basePackages = "com.example.repository",
    reactiveCosmosTemplateRef = "localDatabaseTemplate")
public class LocalCosmosDBConfig extends CosmosDBConfig {

    private static final String LOCAL_COSMOS_CLIENT_BUILDER = "localCosmosClientBuilder";
    private static final String LOCAL_COSMOS_ASYNC_CLIENT = "localCosmosAsyncClient";
    private static final String LOCAL_COSMOS_CONFIG = "localCosmosConfig";

    @Value("${azure.cosmos.regions}")
    private List<String> regions;

    @Value("${azure.cosmos.endpoint-discovery-enabled}")
    private boolean endpointDiscoveryEnabled;

    public LocalCosmosDBConfig(CosmosProperties cosmosProperties) {
        super(cosmosProperties);
    }

    @Override
    protected CosmosClientBuilder createCosmosClientBuilder() {
        log.info("Building {} Cosmos DB Connection for: {}", getClassName(),
            cosmosProperties.getLocalUri()
        );

        return new CosmosClientBuilder().endpoint(cosmosProperties.getLocalUri())
            .gatewayMode(new GatewayConnectionConfig())
            .preferredRegions(regions)
            .endpointDiscoveryEnabled(endpointDiscoveryEnabled);
    }

    @Override
    protected String getKey() {
        return cosmosProperties.getLocalKey();
    }

    @Override
    @Primary
    @Bean(LOCAL_COSMOS_CLIENT_BUILDER)
    public CosmosClientBuilder cosmosClientBuilder() {
        return super.cosmosClientBuilder();
    }

//  @Override
//  @Primary
//  @Bean(LOCAL_COSMOS_ASYNC_CLIENT)
//  public CosmosAsyncClient cosmosAsyncClient(
//      @Qualifier(LOCAL_COSMOS_CLIENT_BUILDER) CosmosClientBuilder cosmosClientBuilder) {
//      log.info("Building {} Cosmos Async Client for: {}", getClassName(), cosmosProperties.getLocalUri());
//      return super.cosmosAsyncClient(cosmosClientBuilder);
//  }

//  @Override
//  @Primary
//  @Bean(LOCAL_COSMOS_CONFIG)
//  public CosmosConfig cosmosConfig() {
//      return super.cosmosConfig();
//  }

    @Bean
    public ReactiveCosmosTemplate localDatabaseTemplate(
//      @Qualifier(LOCAL_COSMOS_ASYNC_CLIENT) CosmosAsyncClient cosmosAsyncClient,
//      @Qualifier(LOCAL_COSMOS_CONFIG) CosmosConfig cosmosConfig,
        CosmosAsyncClient cosmosAsyncClient,
        CosmosConfig cosmosConfig,
        MappingCosmosConverter mappingCosmosConverter) {
        return new ReactiveCosmosTemplate(cosmosAsyncClient, cosmosProperties.getLocalDatabase(), cosmosConfig,
            mappingCosmosConverter
        );
    }

    @Override
    protected String getDatabaseName() {
        return cosmosProperties.getLocalDatabase();
    }

    @Bean
    public CosmosAsyncContainer buildCloudBufferAsyncContainer(
//      @Qualifier(LOCAL_COSMOS_ASYNC_CLIENT) CosmosAsyncClient cosmosAsyncClient
        CosmosAsyncClient cosmosAsyncClient
    ) {
        CosmosAsyncDatabase database = cosmosAsyncClient.getDatabase(this.getDatabaseName());
        return database.getContainer(VehicleCloudEventsContainerName);
    }
}

报错日志

[WARN] - [org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext] - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cosmosAsyncClient' defined in class path resource [com/example/dispatcher/configuration/LocalCosmosDBConfig.class]: No matching factory method found on class [com.example.dispatcher.configuration.LocalCosmosDBConfig]: factory bean 'localCosmosDBConfig'; factory method 'cosmosAsyncClient()'. Check that a method with the specified name exists and that it is non-static.

[ERROR] - [akka.actor.SupervisorStrategy] - Error creating bean with name 'defaultValidator': Singleton bean creation not allowed while singletons of this factory are in destruction (Do not request a bean from a BeanFactory in a destroy method implementation!)
akka.actor.ActorInitializationException: akka://dispatcher/user/outboundStreamActor-1: exception during creation, root cause message: [Error creating bean with name 'defaultValidator': Singleton bean creation not allowed while singletons of this factory are in destruction (Do not request a bean from a BeanFactory in a destroy method implementation!)]

原因分析

  • 方法签名不匹配:Spring查找cosmosAsyncClient工厂方法时,默认优先寻找无参方法,但子类重写的方法需要传入CosmosClientBuilder参数,且未明确指定参数来源,导致Spring无法匹配到正确的工厂方法。
  • Bean冲突与优先级问题:AbstractCosmosConfiguration会自动注册默认的cosmosAsyncClient和cosmosConfig Bean,子类注册自定义Bean时,若未通过@Primary明确优先级,或未阻断默认Bean的注册,会引发Bean定义冲突,导致上下文初始化失败。
  • 依赖注入不明确:ReactiveCosmosTemplate和CosmosAsyncContainer的Bean定义中,未明确引用自定义的LOCAL_COSMOS_ASYNC_CLIENT和LOCAL_COSMOS_CONFIG,导致Spring尝试注入默认Bean,进一步加剧冲突。
  • 上下文销毁连锁反应:上下文初始化失败后进入销毁阶段,此时Akka Actor尝试初始化并请求Bean,触发"Singleton bean creation not allowed while singletons are in destruction"错误。

解决办法

1. 修正自定义Bean的方法签名与注入

取消LocalCosmosDBConfig中cosmosAsyncClient和cosmosConfig方法的注释,保留参数上的@Qualifier,确保Spring能找到正确的依赖:

@Override
@Primary
@Bean(LOCAL_COSMOS_ASYNC_CLIENT)
public CosmosAsyncClient cosmosAsyncClient(
    @Qualifier(LOCAL_COSMOS_CLIENT_BUILDER) CosmosClientBuilder cosmosClientBuilder) {
    log.info("Building {} Cosmos Async Client for: {}", getClassName(), cosmosProperties.getLocalUri());
    return super.cosmosAsyncClient(cosmosClientBuilder);
}

@Override
@Primary
@Bean(LOCAL_COSMOS_CONFIG)
public CosmosConfig cosmosConfig() {
    return super.cosmosConfig();
}

2. 明确依赖注入的Bean来源

修改localDatabaseTemplate和buildCloudBufferAsyncContainer方法,添加@Qualifier引用自定义Bean:

@Bean
public ReactiveCosmosTemplate localDatabaseTemplate(
    @Qualifier(LOCAL_COSMOS_ASYNC_CLIENT) CosmosAsyncClient cosmosAsyncClient,
    @Qualifier(LOCAL_COSMOS_CONFIG) CosmosConfig cosmosConfig,
    MappingCosmosConverter mappingCosmosConverter) {
    return new ReactiveCosmosTemplate(cosmosAsyncClient, cosmosProperties.getLocalDatabase(), cosmosConfig,
        mappingCosmosConverter
    );
}

@Bean
public CosmosAsyncContainer buildCloudBufferAsyncContainer(
    @Qualifier(LOCAL_COSMOS_ASYNC_CLIENT) CosmosAsyncClient cosmosAsyncClient
) {
    CosmosAsyncDatabase database = cosmosAsyncClient.getDatabase(this.getDatabaseName());
    return database.getContainer(VehicleCloudEventsContainerName);
}

3. 禁用父类默认Bean的自动注册

在LocalCosmosDBConfig的@Configuration注解上添加@Exclude或调整@ConditionalOnProperty条件,避免AbstractCosmosConfiguration自动注册默认Bean;或者确保父类的@ConditionalOnProperty条件与子类一致,避免重复注册。

4. 验证依赖关系

检查所有Bean的依赖链,确保无循环依赖:

  • cosmosAsyncClient依赖localCosmosClientBuilder
  • localCosmosClientBuilder依赖配置属性
  • ReactiveCosmosTemplate依赖cosmosAsyncClient、cosmosConfig和mappingCosmosConverter

以上依赖均为单向,无循环,确保Spring能按顺序初始化Bean。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 19:44:58