Springboot整合Mybatis,MybatisPlus源码分析,自动装配实现包扫描源码

1.简单项目:

我这里有一个简单的Springboot的Web项目,需要添加Springboot整合mybatis或者是mybatisPlus的依赖,这里我就以mybatis为例了,mybatisPlus跟mybatis是差不多的,首先添加依赖:

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.2</version>
        </dependency>

Springboot的主启动类:使用MapperScan注解配置了一个包扫描的路径。

@SpringBootApplication
@MapperScan("com.atlx")
public class Springboot2DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(Springboot2DemoApplication.class, args);
    }
}

如果我们不使用@MapperScan注解配置包扫描的路径的话,Springboot在启动的时候也会去扫描Mapper接口,但是扫描的路径跟Springboot启动扫描类生成BeanDefinition的路径是一样的,并且还只会去扫描加了@Mapper注解的类。但是如果我们使用了@MapperScan注解并且配置了扫描的路径的话那么Springboot就会根据我们配置的路径去扫描Mapper接口。

所以下面我们的分析就是根据有没有加@MapperScan注解来分析。

2.没有加@MapperScan注解:

如果一个Springboot项目中没有加@MapperScan注解的话,那么在扫描Mapper接口的时候Springboot回去扫描加了@Mapper注解的接口,下面我们通过源码进行分析:
首先在idea中找到Springboot整合mybatis的依赖包:

找到里面对应的spring.factories文件:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration,\
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

它里面有对应的springboot整合mybatis的自动配置文件:MybatisAutoConfiguration,进入自动配置文件:里面有一个非常核心的内部类:MapperScannerRegistrarNotFoundConfiguration

    @Configuration
    @Import({AutoConfiguredMapperScannerRegistrar.class})
    @ConditionalOnMissingBean({MapperFactoryBean.class, MapperScannerConfigurer.class})
    public static class MapperScannerRegistrarNotFoundConfiguration implements InitializingBean {
        public MapperScannerRegistrarNotFoundConfiguration() {
        }

        public void afterPropertiesSet() {
            MybatisAutoConfiguration.logger.debug("Not found configuration for registering mapper bean using @MapperScan, MapperFactoryBean and MapperScannerConfigurer.");
        }
    }

很显然这个内部类是一个自动配置了,并且还使用了@Import注解导入了:AutoConfiguredMapperScannerRegistrar这个类,这个类就是自动扫描的核心类,下面进入这个类:

需要注意的是要想使用@Import生效,那么必须要满足上面的条件注解:Spring容器中没有:MapperFactoryBean和MapperScannerConfigurer

进入AutoConfiguredMapperScannerRegistrar这个类:这里我就截取部分源代码:

 public static class AutoConfiguredMapperScannerRegistrar implements BeanFactoryAware, EnvironmentAware, ImportBeanDefinitionRegistrar {
        private BeanFactory beanFactory;
        private Environment environment;

        public AutoConfiguredMapperScannerRegistrar() {
        }

        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            if (!AutoConfigurationPackages.has(this.beanFactory)) {
                MybatisAutoConfiguration.logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.");
            } else {
                MybatisAutoConfiguration.logger.debug("Searching for mappers annotated with @Mapper");
                List<String> packages = AutoConfigurationPackages.get(this.beanFactory);
                if (MybatisAutoConfiguration.logger.isDebugEnabled()) {
                    packages.forEach((pkg) -> {
                        MybatisAutoConfiguration.logger.debug("Using auto-configuration base package '{}'", pkg);
                    });
                }

                BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
                builder.addPropertyValue("processPropertyPlaceHolders", true);
                builder.addPropertyValue("annotationClass", Mapper.class);
                builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(packages));
                BeanWrapper beanWrapper = new BeanWrapperImpl(MapperScannerConfigurer.class);

显然这个类实现了:ImportBeanDefinitionRegistrar这个类,那么自然需要重写:registerBeanDefinitions()方法,自然核心逻辑就在这个方法中:

在源码中能够清楚的发现它在构建一个beanDefinition:而构建的类就是:MapperScannerConfigurer

BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);

并且还对这个beanDefinition添加了一些属性:

                builder.addPropertyValue("annotationClass", Mapper.class);
                builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(packages));

其中比较关键的就是添加了需要扫描的注解为:Mapper注解。

需要扫描的路径为:Springboot扫描bean的路径,这里并不是直接写死的,而是通过一个工具类获取到的,而这个包路径则是在启动的时候在@SpringBootApplication这个注解的@EnableAutoConfiguration注解的@AutoConfigurationPackage注解中添加进去的。

并且它导入的MapperScannerConfigurer这个类它实现了:BeanDefinitionRegistryPostProcessor这个beanFactoryPostProcessor,那么自然就要重写postProcessBeanDefinitionRegistry()方法,而扫描的逻辑就是在这个方法中实现的,而这个方法的调用就是在Spring启动的Refresh()方法中的:invokeBeanFactoryPostProcessors(beanFactory);方法中。

到这里Springboot整合mybatis实现Mapper接口的自动扫描源码就分析结束了,下面我们看看加了@MapperScan注解的情况。

3.加了@MapperScan注解:

如果项目中加了@MapperScan注解,那么程序员自然就会去配置扫描的路径,而Springboot就会直接去扫描配置的这个路径:

下面我们直接进入@MapperScan()注解:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
@Repeatable(MapperScans.class)
public @interface MapperScan {

}

发现它也导入了:MapperScannerRegistrar这个类,那么其实现的逻辑跟上面的没有加@MapperScan注解的实现逻辑就是一样的了,只是扫描的包不一样而已。

4.总结:

在项目中使用MapperScan注解和不使用MapperScan注解其实区别不大,只是如果你不适应MapperScan注解的话,那么你需要对你的Mapper接口加上@Mapper注解那么Springboot才能够扫描到,如果你使用了@MapperScan注解的话,那么你只需要配置包路径即可。

注意:如果在项目中如果使用了@MapperScan注解的话,那么Springboot自动帮你扫描的那段逻辑也就是标题的第二点就不会生效了,因为我们看了它的源码,它那个内部类中有一个条件注解,其条件就是容器中不存在:MapperScannerRegistrar的话才会生效,显然当使用@MapperScan的时候也导入了MapperScannerRegistrar所以说容器中已经存在了,那么自动扫描那一套就自然不会生效,从而就不会导致重复扫描的问题了。

到这里不知道有没有一个疑问,就是:如果Springboot在启动的时候,先执行了Srpingboot的自动扫描,然后再执行了@MapperScan注解,这样的话也会导致扫描了两遍。其实不会的,它这里还是有一个优先级的, @MapperScan注解的优先级是大于Springboot的自动扫描。

  • 17
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我还没听说过

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值