应用的是如下版本的 mybatis-plus 和多数据源,发现在 service 上加上 @DS 注解不会切换数据源,通过排查发现是 aop 没有失效
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.0</version>
</dependency>
<!-- 多数据源 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.3.3</version>
</dependency>
在 DynamicDataSourceAutoConfiguration 类里有定义一个 bean
@Role(value = BeanDefinition.ROLE_INFRASTRUCTURE)
@Bean
@ConditionalOnMissingBean
public Advisor dynamicDatasourceAnnotationAdvisor(DsProcessor dsProcessor) {DynamicDataSourceAnnotationInterceptor interceptor = new DynamicDataSourceAnnotationInterceptor(properties.isAllowedPublicOnly(), dsProcessor);
DynamicDataSourceAnnotationAdvisor advisor = new DynamicDataSourceAnnotationAdvisor(interceptor);
advisor.setOrder(properties.getOrder());
return advisor;
}
在这个配置类里定义的其余 bean 都有初始化,但唯独这个 bean 没有初始化,而这个类的作用就是定义 aop 的切面和切入点
我在本人的配置类里定义这个 bean 的话能够进行初始化,通过 debug,其实次要起因就是应用了该 @ConditionalOnMissingBean 注解导致的,不晓得为啥 dynamic-datasource-spring-boot-starter 的作者要加上这个注解,在 spring 有加载其余的 Advisor 实现类的时候(我这边次要是有援用到 spring 的 cache 依赖,其中的配置类 ProxyCachingConfiguration 有定义一个 BeanFactoryCacheOperationSourceAdvisor),所以该 bean 就不会加载。
为此,我顺便跑了一遍 spring 的 @Bean 加载流程,剖析如下:
springboot 启动的时候,其中有个回调接口 BeanDefinitionRegistryPostProcessor 的实现是 ConfigurationClassPostProcessor,这个实现类的作用就是加载所有的 @Configuration,会应用到 ConfigurationClassParser 类来进行解析,会解析是否有 @ComponentScans()、@ComponentScan(@SpringApplication 注解里也是应用到了这个注解)。
而后依据 basePackage 属性通过 ComponentScanAnnotationParser#parse 进行进一步的扫描,再应用 ClassPathBeanDefinitionScanner#doScan,#findCandidateComponents 扫描所有 spring 的 component 和 config(扫描内容由 ClassPathBeanDefinitionScanner 的 filter 判断,这里会扫描所有 @Component,@Configuation 里也用到了 @Component,所以都会扫描到)
而后会持续递归解析,最初失去所有的 config(并且通过 ConfigurationClassParser#retrieveBeanMethodMetadata 获取 config 里所有的 @Bean 信息保留到 BeanMethod 属性)和 component;接着应用 ConfigurationClassBeanDefinitionReader#loadBeanDefinitions,读取加载的 config 的 bean 配置退出到 BeanDefinition
这就是整个 BeanDefinition 的加载过程,能够看到,这加载过程其中是有先后顺序的,首先会加载以后 SpringBootApplication 的目录的配置,所以在下面那个问题我本人写一个配置 @Bean 的时候能够加载,因为这时候还没加载其余依赖包和配置,因而 Advisor 实现类就只有这个,所以加载能够胜利。加载实现之后才会加载 classpath 目录下的其余配置类。