假如在项目中定义动态数据源,以下配置中DynamicDataSource是org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource
的子类
@ConfigurationProperties("spring.datasource.source")
@Bean
public DataSource sourceDataSource() {
return DruidDataSourceBuilder.create().build();
}
@ConfigurationProperties("spring.datasource.target")
@Bean
public DataSource targetDataSource() {
return DruidDataSourceBuilder.create().build();
}
@Primary
@Bean
public DataSource dynamicDataSource() throws SQLException {
DataSource source = sourceDataSource();
DataSource target = targetDataSource();
//此处DynamicDataSource是org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource的子类
DynamicDataSource dynamicDataSource = new DynamicDataSource();
return dynamicDataSource;
}
整个项目引入Spring Boot自动配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.1.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.17</version>
</dependency>
启动过程中会出现如下异常
***************************
APPLICATION FAILED TO START
***************************
Description:
The dependencies of some of the beans in the application context form a cycle:
serviceRunner (field private com.xquant.platform.test.migrate.mapper.ColumnDefineMapper com.xquant.platform.test.migrate.runner.ServiceRunner.columnDefineMapper)
↓
columnDefineMapper defined in file [D:\20200702\xquant-platform-component-test-parent\xquant-platform-component-test-migrate\target\classes\com\xquant\platform\test\migrate\mapper\ColumnDefineMapper.class]
↓
sqlSessionFactory defined in class path resource [org/mybatis/spring/boot/autoconfigure/MybatisAutoConfiguration.class]
┌─────┐
| dynamicDataSource defined in class path resource [com/xquant/platform/test/migrate/config/DataSourceConfig.class]
↑ ↓
| sourceDataSource defined in class path resource [com/xquant/platform/test/migrate/config/DataSourceConfig.class]
↑ ↓
| org.springframework.boot.autoconfigure.jdbc.DataSourceInitializerInvoker
└─────┘
可以看到这里,是由于dynamicDataSource查找sourceDataSource,然后实例sourceDataSource又会查找DataSourceInitializerInvoker,最后导致又会查找dynamicDataSource,导致了循环依赖。这个DataSourceInitializerInvoker为什么会出现呢?因为在org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
会引入一个Registrar注册了一个后置处理器。
这个注册过程其实org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
中完成的。
这个后置处理器会在所有DataSource类型的Bean的初始化后进行处理,此时会去获取DataSourceInitializerInvoker类型的bean.
而这个DataSourceInitializerInvoker类型的bean又会依赖DataSource,导致循环依赖
而这个Bean只是用于执行一些脚本的(Bean to handle DataSource initialization by running schema-*.sql on InitializingBean.afterPropertiesSet() and data-*.sql SQL scripts on a DataSourceSchemaCreatedEvent.
),可以不要。
注册一个BeanDefinitionRegistryPostProcessor移除对应的后置处理器,这样在数据源初始化的时候就不会去获取DataSourceInitializerInvoker了。
package com.xquant.platform.test.migrate.processor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.stereotype.Component;
@Component
public class DataSourceBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor {
public static final String DATA_SOURCE_INITIALIZER_POST_PROCESSOR = "dataSourceInitializerPostProcessor";
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
/**
* MyBatisAutoConfiguration会自动注册一个dataSourceInitializerPostProcessor 导致引入动态数据源的是时候查找其他数据源,
* 但是创建完成之后通过dataSourceInitializerPostProcessor处理会导致循环依赖
* dynamicDataSource->sourceDataSource->dataSourceInitializerPostProcessor->DataSourceInitializerInvoker
* ->dynamicDataSource循环依赖
*/
if (registry.containsBeanDefinition(DATA_SOURCE_INITIALIZER_POST_PROCESSOR)) {
registry.removeBeanDefinition(DATA_SOURCE_INITIALIZER_POST_PROCESSOR);
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
注册的这个BeanDefinitionRegistryPostProcessor是在ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry作用之后,而在用户注册的BeanPostProcessor实例化之前执行的。
再次启动,就不会报异常了。