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

如何让自定义MyDataSource引用默认DataSource并避免循环依赖?

解决自定义DataSource包装类的循环引用问题

你编写的MyDataSource实现DataSource接口并标注@Component,构造器需要注入DataSource,但Spring尝试注入自身导致循环引用报错:

Error creating bean with name 'myDataSource': Requested bean is currently in creation: Is there an unresolvable circular reference?

由于无法修改默认DataSource的配置,只能通过调整自定义MyDataSource的实现来解决,以下是两种可行方案:

方案一:通过@Qualifier指定默认DataSource的Bean名称

Spring自动配置的默认DataSource Bean名称通常为dataSource,直接在构造器参数上标注@Qualifier指定该名称,即可明确注入目标:

@Component
public class MyDataSource implements DataSource {

  private final DataSource wrapped;

  public MyDataSource(@Qualifier("dataSource") DataSource wrapped) {
    this.wrapped = wrapped;
    // 初始化逻辑
  }

  // 实现DataSource接口的所有方法,委托给wrapped实例
  @Override
  public Connection getConnection() throws SQLException {
    return wrapped.getConnection();
  }

  // 其他方法同理实现...
}

如果不确定默认DataSource的Bean名称,可以通过以下方式在启动时打印所有DataSource类型的Bean:

@Component
public class DataSourceChecker implements ApplicationListener<ContextRefreshedEvent> {
  @Override
  public void onApplicationEvent(ContextRefreshedEvent event) {
    ApplicationContext context = event.getApplicationContext();
    Map<String, DataSource> dataSources = context.getBeansOfType(DataSource.class);
    dataSources.forEach((name, ds) -> System.out.println("DataSource Bean名称:" + name + ",类型:" + ds.getClass().getName()));
  }
}

方案二:通过ApplicationContext自动筛选默认DataSource

如果不想依赖Bean名称,可以通过ApplicationContext获取所有DataSource实例,过滤掉自身后使用剩余的默认实例:

@Component
public class MyDataSource implements DataSource {

  private DataSource wrapped;
  private final ApplicationContext context;

  public MyDataSource(ApplicationContext context) {
    this.context = context;
  }

  @PostConstruct
  public void initWrappedDataSource() {
    Map<String, DataSource> dataSourceMap = context.getBeansOfType(DataSource.class);
    this.wrapped = dataSourceMap.values().stream()
        .filter(ds -> !(ds instanceof MyDataSource))
        .findFirst()
        .orElseThrow(() -> new IllegalStateException("未找到可用的默认DataSource"));
  }

  // 实现DataSource接口的所有方法,委托给wrapped实例
  @Override
  public Connection getConnection() throws SQLException {
    return wrapped.getConnection();
  }

  // 其他方法同理实现...
}

问题原因说明

Spring自动装配时,会将所有匹配类型的Bean纳入候选范围。MyDataSource本身是DataSource类型的Bean,当构造器请求注入DataSource时,Spring会把正在创建的MyDataSource也作为候选,从而触发循环引用检测报错。通过明确指定目标Bean或过滤自身实例,即可避免该问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 17:47:53