• @MapperScan 和 @Mapper 源码走读


    一.从开发中遇到的问题开始

    问题描述 : 在一个springboot+mybatis的项目中,在dao也就是Mapper接口上配置了@Mapper注解,其他同事在启动类还配置了@MapperScan注解(包扫描没有配全面),进行批量指定所生成的Mapper接口动态代理接口类,所以开始的时候没有在@MapperScan直接我新建的dao包,就报错,但是有@Mapper注解。

    No qualifying bean of type 'com.xxx.mapper.xxxMapper' 
    available: expected at least 1 bean which qualifies as autowire 
    candidate. Dependency annotations:{@org.springframework.beans
    .factory.annotation.Autowired(required=true)}
    
    • 1
    • 2
    • 3
    • 4

    1、只使用@Mapper注解,不使用@MapperScan注解。会扫描@Mapper注解所在接口,生成动态代理类,注入到Spring容器中。

    2、只使用@MapperScan注解,不使用@Mapper注解。会扫描@MapperScan注解配置的包下面的接口生成动态代理类,注入到Spring容器中。

    3、@Mapper、@MapperScan注解都使用,@Mapper接口,在@MapperScan注解中有配置包路径,那么可以正常使用。

    4、@Mapper、@MapperScan注解都使用,@Mapper接口,在@MapperScan注解中没有配置包路径,那么会报错,解决办法,就是在@MapperScan注解中配置正确路径下的包即可。

    二.@Mapper、@MapperScan注解解释

    @Mapperscan:标注在 springboot 的启动类上面,配置 basePackages 属性,可以去扫描指定路径下的接口扫描为 Mapper 接口。

    @Mapper:标注在接口上,表明这是一个 Mapper 接口。

    工作原理:两者都使普通接口转为 mapper 接口,也即是把接口的beanClass设置为mapperFactoryBean

    三.源码分析

    1.@MapperScan注解扫描分析

    可以发现 @Mapperscan注解类中包含有注解@Import(MapperScannerRegistrar.class)
    在这里插入图片描述

    MapperScannerRegistrar实现了ImportBeanDefinitionRegistrar ,那么在启动时spring容器会调用并执行 registerBeanDefinitions() 方法,扫描对应路径上(@MapperScan注解上带的basepackages)的类扫描到spring容器中.

    在这个方法中重点看这行代码:
    在这里插入图片描述

    代码中会实例化 MapperScannerConfigurer,这个类实现了BeanDefinitionRegistryPostProcessor,会容器启动时调用postProcessBeanDefinitionRegistry() 方法,在这方法中设置了接口的 beanClass 。
    在这里插入图片描述

    ClassPathMapperScanner 重写了doScan方法,主要是扫描路径,并将扫描的信息转为beanDefinition,设置其为MapperFactoryBean,最终将扫描好并封装为MapperFactoryBean的类加入到ioc容器中
    在这里插入图片描述

    mapperFactoryBean重写了getObejct()方法。
    在这里插入图片描述

    跟踪 getObject() 方法,发现最终实例化接口的代码如下:
    在这里插入图片描述

    也即是我们写 mapper 接口,然后 mybatis 为我们生成一个 MapperProxy 对象去实现 mapper 接口。

    1.1@MapperSca总结

    @MapperScan 实际做的事情:
    1.扫描指定路径,并将路径下的信息记录为BeanDefinition;
    2.将获取的BeanDefinition,设置为MapperFactoryBean,注入IOC;

    2.@Mapper注解扫描分析

    @Mapper 注解是在 mybatis加载时候起作用的,在 MybatisAutoConfiguration 中:

    如果当前IOC容器没有MapperFactoryBean.class, MapperScannerConfigurer.class这两个bean,则会执行如下代码
    在这里插入图片描述
    由该类的头部注解可知,在 spring 上下文中没有 MapperScannerConfigurer 实例时候会进行对@Mapper注解类的初始化。由此可知 @Mapper和@Mapperscan只有一个起作用,而 @Mapperscan 优先级较高。因此当 @Mapperscan 不存在时候,MybatisAutoConfiguration 该类的头部注解@import,会实例化 AutoConfiguredMapperScannerRegistrar ,这个类 会调用registerBeanDefinitions方法,将MapperScannerConfigurer这个类注入到了IOC容器中。
    在这里插入图片描述
    可以看到,和之前@MapperScan对应上了,都是注册了MapperScannerConfigurer,也就是两种注解方式都是通过MapperScannerConfigurer扫描mapper注册的

    下面我们仔细翻一下源码,看下MapperScannerConfigurer到底怎么处理@MapperScan和@Mapper
    在这里插入图片描述
    registerFilters方法指定了是走@Mapper注解扫描,还是@MapperScan包扫描

     public void registerFilters() {
      boolean acceptAllInterfaces = true;
     
      // 如果指定了扫描类型(@Mapper走这里)
      // annotationClass在前面的AutoConfiguredMapperScannerRegistrar#registerBeanDefinitions被注入
      // 就是这段builder.addPropertyValue("annotationClass", Mapper.class);
      if (this.annotationClass != null) {
        addIncludeFilter(new AnnotationTypeFilter(this.annotationClass));
        acceptAllInterfaces = false;
      }
     
      ......
      // 如果没指定扫描类型,则扫描全部(@MapperScan走这里)
      if (acceptAllInterfaces) {
        addIncludeFilter((metadataReader, metadataReaderFactory) -> true);
      }
     
      // exclude package-info.java
      addExcludeFilter((metadataReader, metadataReaderFactory) -> {
        String className = metadataReader.getClassMetadata().getClassName();
        return className.endsWith("package-info");
      });
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    三.@MapperScan和@Mapper的使用建议

    mapper接口所在包比较集中式可以在启动类上加@MapperScan注解指定mapper接口所在的包路径。

    如果mapper接口所在的包路径比较分散(多部门,多人开发),建议直接在接口上加@Mapper注解,去掉启动类上的@MapperScan包扫描

  • 相关阅读:
    数学建模入门
    cobbler装机
    想要通过镜像下载Hadoop压缩包
    流媒体传输 - RTMP 协议
    从零开始学Spring Boot系列-返回json数据
    “5G+北斗”赋能千行百业,中海达亮相2023中国移动全球合作伙伴大会
    swiper 增加一个鼠标移入分页器的小点后就切换展示图片
    SpringBoot项目打包部署
    无约束优化算法
    周阳老师JUC并发编程
  • 原文地址:https://blog.csdn.net/weixin_42232931/article/details/127969816