前言

前面一篇介绍了BaseMapper的作用,只要自定义接口实现了BaseMapper,就可以使用单表CRUD,而不需要进行xml或sql的编写,怎么生成对应的sql,可以参考上一篇文章

在介绍如何利用BaseMapper生成的sql进行查询之前,本篇先来了解下BaseMapper的实现接口是如何加载到spring容器中的。
在使用MyBatis作为数据访问层框架的时候,通常需要将Mapper接口扫描并注册到Spring容器中,然后在业务逻辑代码中使用@Autowired或@Resource注解注入Mapper接口,从而实现对数据访问层的调用。

使用mapper示例,如下所示:

@Resource
private OrderMapper orderMapper;
...
{
    ...
    orderMapper.selectList(new QueryWrapper<>());
}

原理

demo项目传送门>

1、首先是在启动类上加注解@MapperScan(“top.xudj.mp.mapper”)扫码mapper,这些mapper接口都实现了BaseMapper,如下:

public interface UserMapper extends BaseMapper<User> {
}

2、@MapperScan注解的定义上使用了@Import注解,将MapperScannerRegistrar类导入到当前的配置类中。MapperScannerRegistrar实现了ImportBeanDefinitionRegistrar接口,用于动态向Spring容器中注入MapperScannerConfigurer,从而实现Mapper接口的自动扫描和注册。

3、启动项目,进入到了MapperScannerRegistrar类,MapperScannerRegistrar 实现了接口ImportBeanDefinitionRegistrar,
重写了registerBeanDefinitions方法,如下图所示:
image-1676600570395
在最后一行,可以看到进行beanDefinition的注册,这个beanDifinition就是MapperScannerConfigurer。

4、接着看MapperScannerConfigurer。
在其它beanDefinition都加载了后,还没有实例化前,会调用postProcessBeanDefinitionRegistry方法,因为MapperScannerConfigurer实现了BeanDefinitionRegistryPostProcessor接口,如下图所示
image-1676557480726
在postProcessBeanDefinitionRegistry方法中 扫描mapper接口所在包,完成mapper实例化。

5、扫描类是ClassPathMapperScanner,实现了spring的ClassPathBeanDefinitionScanner类,进入到spring的ClassPathBeanDefinitionScanner类中完成扫描,basePackage便是@MapperScan注解上的路径。
image-1676557958514

6、在spring的scan扫码后,进行了beanDefinition的注册。
之后回到ClassPathMapperScanner类,在调用spring的doScan之后,如下图所示,会进行后续的处理,往下看。
image-1676558126877

7、继续看ClassPathMapperScanner的processBeanDefinitions方法(第6步圈出的方法),核心的代码如下图所示:
image-1676558152292
修改BeanDefinition的类,beanClass修改为:class org.mybatis.spring.mapper.MapperFactoryBean
这里可以看到,以mapper接口为beanDefinition的beanClass被修改了。spring实例化的时候便会按这个类来创建实例。

8、在bean实例化的时候,再进一步通过实例化对应的mapper,对应的类是MapperFactoryBean,会调用其getObject方法。
image-1676558460846

MapperFactoryBean实现了接口FactoryBean,其用于进行复杂bean的创建所用,会调用对应的getObject方法。

9、继续往下看调用,进入到sqlSessionTemplate的getMapper方法
image-1676558612885
截图可以看到,configuration不是mybatis的,而是Mp的MybatisConfiguration类。

10、继续,进入到mapper的实例化类
image-1676558689019

11、进入到mapper代理类实现工厂类MybatisMapperProxyFactory,通过Proxy完成实例化mapper的代理类MybatisMapperProxy创建。
image-1676558749742

总结

至此,MybatisMapperProxy 作为mapper bean的一个实现代理类,完成了实例化,用于完成将来的查询。

com.baomidou.mybatisplus.core.override.MybatisMapperProxy implements InvocationHandler 使用了jdk的动态代理类