MyBatis的MapperScan和Mapper注解,你会混淆吗?

2,943 阅读2分钟

背景

笔者参与的项目使用了多模块结构,不同模块使用 SpringBoot ,基本结构差不多,最近排查一个问题时,发现两个模块,一个没有使用 @MapperScan ,另一个使用了该注解,但是 MyBatis 的 Mapper 类都能被正确扫描到。

统一代码结构,去掉 @MapperScan 注解后,对应模块报错,提示注入 DAO 类失败。于是对比了下两个工程,跟踪两个注解的使用方法,找到了问题的根源。本文来整理下这个过程。

@MapperScan 扫描方式

@MapperScan 注解会将指定目录下所有 DAO 类封装成 MyBatis 的 BaseMapper 类,然后注入 Spring 容器中,不需要额外的注解,就可以完成注入,常见的 DAO 定义如下:

package cn.xxx.xxx.xxx.dao;
public interface IXXXDao  extends BaseMapper<XXX>{}

需要注意的是@MapperScan 扫描路径下除了 MyBatis 的 DAO 类,不应该有自定义的普通 DAO 接口及其实现类

例如:这个工程中,dao 目录下大部分是继承 BaseMapper 的 DAO,但还有一个自定义的 普通 DAO 接口和 impl 下它的实现类。 在这里插入图片描述 工程启动类使用了扫描注解:

@MapperScan({"cn.com.xx.xxmodule.dao"})

项目启动时会报错: 在这里插入图片描述 可见非继承自 BaseMapper普通接口及其实现类都被封装成 Mapper 类注入了,最终导致引用该 DAO 的 Service 类依赖注入失败。

规避办法有两个:

  1. 自定义的普通接口类单独放置,区别 MyBatis 的 dao 和工程自定义 dao【推荐】。
  2. 为 Impl 实现类添加 @Primary 接口,弊端是无实际意义的接口定义也被当做 Mapper 封装了【不推荐】。

@Mapper 注解方式

使用 @Mapper 注解时,debug 日志模式下,我们能看到 MyBatis 自动注入时会自动扫描启动类目录下所有的 @Mapper 注解,主要日志为:

2020-10-25 10:01:31,850 DEBUG (MybatisPlusAutoConfiguration.java:275)- 
Searching for mappers annotated with @Mapper
2020-10-25 10:33:08,200 DEBUG (MybatisPlusAutoConfiguration.java:275)- 
Using auto-configuration base package 'cn.xx.xx.xx'

启示录

详细了解这俩的用法后,发现项目中用得很混乱,这是两种不同的注入 MyBatis DAO 实体的方法,选择其一即可,而项目中这两种注解都存在。

实际上,使用 @MapperScan 后,对应包的 DAO 类就无需 @Mapper 了;如果使用 @Mapper ,就不需要 @MapperScan

而工程中,基本上所有的 DAO 类都用了 @Mappper 注解,同时又为启动类设置了 @MapperScan,那么由于 @MapperScan 注解优先级高,@Maper 注解就失效了。

究其根源可能是,代码都是拷贝过来的,没人深究不同配置有什么区别吧。而@MapperScan 的出现,就是为了解决每个类都要写 @Mapper 这个繁琐步骤的!