使用的是如下版本的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目录下的其他配置类。


我不是码农
3 声望1 粉丝

java开发码农