如何让自定义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
相关产品推荐
相关产品推荐

