背景
笔者参与的项目使用了多模块结构,不同模块使用 SpringBoot ,基本结构差不多,最近排查一个问题时,发现两个模块,一个没有使用 @MapperScan
,另一个使用了该注解,但是 MyBatis 的 Mapper
类都能被正确扫描到。
统一代码结构,去掉 @MapperScan
注解后,对应模块报错,提示注入 DAO 类失败。于是对比了下两个工程,跟踪两个注解的使用方法,找到了问题的根源。本文来整理下这个过程。
@MapperScan 扫描方式
@MapperScan
注解会将指定目录下所有 DAO 类封装成 MyBatis 的 BaseMapper
类,然后注入 Spring 容器中,不需要额外的注解,就可以完成注入,常见的 DAO 定义如下:
package xxx.xxx.xxx.dao;
public interface IXXXDao extends BaseMapper<XXX>{}
需要注意的是:@MapperScan
扫描路径下除了 MyBatis 的 DAO 类,不应该有自定义的普通 DAO 接口及其实现类。
工程启动类使用了扫描注解:
@MapperScan({"xx.xxmodule.dao"})
项目启动时会报错:
可见非继承自 BaseMapper
的普通接口及其实现类都被封装成 Mapper 类注入了,最终导致引用该 DAO 的 Service 类依赖注入失败。
规避办法有两个:
- 自定义的普通接口类单独放置,区别 MyBatis 的 dao 和工程自定义 dao【推荐】。
- 为 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
这个繁琐步骤的!