@MapperScan 和 @Mapper 源码解读

news/2024/10/9 12:48:18/

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


问题描述 : 在一个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、只使用@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");
  });
}


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


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

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


http://www.ppmy.cn/news/1015474.html

相关文章

20.5 HTML 媒体

1. video视频标签 video视频标签: 是HTML中用于在网页上嵌入视频的元素.常用的视频标签属性: - src属性: 指定视频文件的URL地址. - controls属性: 用于显示视频播放控件(如播放按钮, 进度条等), 使用户能够控制视频的播放. - width和height: 指定视频的宽度和高度. - autopla…

打造本地户外装备小程序商城教程大揭秘

在如今的移动互联网时代,小程序已经成为了各行各业的发展利器。尤其对于户外用具行业来说,一个专属的小程序商城将能够极大地提升企业的品牌形象和销售业绩。下面就来介绍一下快速上手制作户外用具小程序的攻略吧。 首先,登录乔拓云平台进入商…

5、螺旋矩阵

螺旋矩阵是指一个呈螺旋状的矩阵,它的数字由第一行开始到右边不断变大,向下变大,向左变大,向上变大,如此循环。如: 1 2 3 4 10 11 12 5 9 8 7 …

【Windows】Windows11系统用户自己添加开机启动项的方法

按win R快捷键,打开运行窗口,在输入框中输入shell:startup后点击运行,打开启动文件夹: 把想增加的开机启动软件的快捷方式图标拖入到该文件夹中,如下图所示: 按ctrl shift esc打开任务管理器&#xff0c…

在HTML页面中引入vue组件

1. 什么是组件化开发? 组件化开发是一种软件开发的方法论,旨在通过将复杂的系统分解为独立的、可重用的组件来提高开发效率和代码的可维护性。组件化开发将系统按照功能、模块或界面的不同部分进行拆分,每个部分都对应一个独立的组件&#x…

MQ百万级数据堆积如何处理

问题分析 如果,如果哈,RabbitMQ或者是kafka,这些消息队列出现大量的数据堆积,乃至是成千上万,我们作为一个开发工程师或者是架构师,我们如何去解决这种突发情况呢?可能大家会想,怎么…

跨平台特性

跨平台 Java的跨平台特性是通过Java虚拟机实现的,跨平台特性也被称作“Write Once,Run Anywhere”。 Java是如何实现跨平台的? 编写Java代码:Java开发者编写Java代码,以.java扩展名保存 编译字节码:Java…

CTF流量题解http1.pcapng

使用Wireshark工具打开流量文件http1.pcapng,如下图所示。 在过滤检索栏输入http,wireshark自动进行过滤。