记一次 Spring Boot多数据源 循环引用问题

本文详细解析了升级MyBatis版本后遇到的循环引用问题,提供了两种解决方案:一是直接在配置类中new数据源;二是通过排除DataSourceAutoConfiguration并在SpringBoot启动时导入MyBatisConfig。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如题,升级了一下mybatis版本后出现循环引用的问题。

具体异常如下

***************************
APPLICATION FAILED TO START
***************************

Description:

The dependencies of some of the beans in the application context form a cycle:
     略
      ↓
   sqlSessionFactory defined in class path resource [com/suike/config/database/MyBatisConfig.class]
┌─────┐
|  dataSource defined in class path resource [com/suike/config/database/MyBatisConfig.class]
↑     ↓
|  dataSourceDev defined in class path resource [com/suike/config/database/dataSource/DruidDBConfigDev.class]
↑     ↓
|  dataSourceInitializer
└─────┘

然后抛出一堆的:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSourceDev' defined in class path resource [xxx类]: Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSourceInitializer': Invocation of init method failed; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'dataSource': Requested bean is currently in creation: Is there an unresolvable circular reference?
	

 

我的配置一共3个,前两个是数据源,第3个是Mybatis的配置类

@Configuration
public class DruidDBConfigDev {

    @Bean(name="dataSourceDev")
    public DruidDataSource dataSource(){
        DruidDataSource datasource = new DruidDataSource();
		//略
        return datasource;
    }
}
@Configuration
public class DruidDBConfigProd {

    @Bean(name="dataSourceProd")
    public DruidDataSource dataSource(){
        DruidDataSource datasource = new DruidDataSource();
		//略
        return datasource;
    }
}
@Configuration() 
@MapperScan(value = "com.suike.mapper")
public class MyBatisConfig {

    //重点在这个方法
    @Bean
    @Primary
    public DynamicDataSource dataSource(@Qualifier("dataSourceDev") DataSource dataSourceDev,
                                        @Qualifier("dataSourceProd") DataSource dataSourceProd) {

        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put(DatabaseType.dataSourceDev, dataSourceDev);
        targetDataSources.put(DatabaseType.dataSourceProd, dataSourceProd);

        DynamicDataSource dataSource = new DynamicDataSource();
        dataSource.setTargetDataSources(targetDataSources);// 该方法是AbstractRoutingDataSource的方法
        dataSource.setDefaultTargetDataSource(dataSourceDev);// 默认的datasource设置为myTestDbDataSource
        return dataSource;
    }

    /**
     * 根据数据源创建SqlSessionFactory
     */
    @Bean
    public SqlSessionFactory sqlSessionFactory(DynamicDataSource dataSource) throws Exception {
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource);
        return sessionFactory.getObject();
    }


    @Bean
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }


    /**
     * 配置事务管理器
     */

    @Bean
    public DataSourceTransactionManager transactionManager(DynamicDataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean
    public TransactionTemplate txTemplate(DataSourceTransactionManager transactionManager) {
        return new TransactionTemplate(transactionManager);
    }


}

 

看完3个配置,再回过头来看异常信息

┌─────┐
|  dataSource defined in class path resource [com/suike/config/database/MyBatisConfig.class]
↑     ↓
|  dataSourceDev defined in class path resource [com/suike/config/database/dataSource/DruidDBConfigDev.class]
↑     ↓
|  dataSourceInitializer
└─────┘

看起来意思就是MyBatisConfig需要依赖DruidDBConfigDev数据源,而DruidDBConfigDev数据源创建的时候又需要依赖这个dataSourceInitializer。

但是dataSourceInitializer又需要依赖MyBatisConfig

 

 

解决方案1:

不要把数据源注入spring,直接在配置类配置数据源的方法里new一个数据源

如:

    /**
     * @Primary 指定在同一个接口有多个实现类可以注入的时候,默认选择哪一个,而不是让@Autowire注解报错(一般用于多数据源的情况下)
     * @Qualifier 根据名称进行注入,通常是在具有相同的多个类型的实例的一个注入(例如有多个DataSource类型的实例)
     */
    @Bean
    @Primary
    public DynamicDataSource dataSource() {

        DruidDataSource datasource1 = new DruidDataSource();
        datasource1.setUrl("");
        datasource1.setUsername("");
        datasource1.setPassword("");
        datasource1.setDriverClassName("com.mysql.jdbc.Driver");

        DruidDataSource datasource2 = new DruidDataSource();
        //略

        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put(DatabaseType.dataSourceDev, datasource1);
        targetDataSources.put(DatabaseType.dataSourceProd, datasource2);

        DynamicDataSource dataSource = new DynamicDataSource();
        dataSource.setTargetDataSources(targetDataSources);// 该方法是AbstractRoutingDataSource的方法
        dataSource.setDefaultTargetDataSource(datasource1);// 默认的datasource设置为myTestDbDataSource
        return dataSource;
    }

 

解决方案2(推荐):

保持原来的配置,在Spring boot启动的时候排除DataSourceAutoConfiguration,并另外导入MyBatisConfig

@Import({MyBatisConfig.class})
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class App extends SpringBootServletInitializer {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }

}

 

 

转载于:https://my.oschina.net/yejunxi/blog/2885730

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值