美文网首页
Spring Boot多数据源 循环引用问题

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

作者: 催化剂 | 来源:发表于2020-06-11 09:40 被阅读0次

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

    具体异常如下

    ***************************APPLICATION FAILED TO START***************************Description:Thedependenciesofsomeofthebeansintheapplication 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类]: Initializationofbean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSourceInitializer': Invocationofinit 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);

        }

    }

    相关文章

      网友评论

          本文标题:Spring Boot多数据源 循环引用问题

          本文链接:https://www.haomeiwen.com/subject/rkxnzhtx.html