【Mybatis】【一】图论-Mapper 接口都是怎么注入到 Spring容器中的?
1 前言
这节我们看个源码相关的东西,就是我们平时写的 Mapper 接口是怎么注入到 Spring 中呢?
我们会去想:
比如Mapper接口在启动时是如何被发现的?
Mapper接口我们知道肯定是会创建代理的,那么代理对象又是如何创建的呢?
我们接下来就来看看。
1.1 入口分析
我们的 Mapper 接口,首先要有人扫描它吧,是不是,从扫描到识别到生成代理,是不是这个过程。那么扫描它的入口在哪里?
从源码看下来,我看到了,有两个入口:
(1)主动方式:@MapperScan 方式的入口(也是我们本节重点看的)
(2)没有主动下的默认方式:MybatisAutoConfiguration.AutoConfiguredMapperScannerRegistrar mybatis-spring 这个包里如果没有配置 @MapperScan 的话,它会有一个自动扫描基础包下的所有接口
可以看到 AutoConfiguredMapperScannerRegistrar 其实也是往里边注入了一个 MapperScannerConfigurer 的 BeanDefinition,所以两种方式最后的落点都是 MapperScannerConfigurer 这个类。
那接下来我们就主要从 @MapperScan 的方式看起。
2 @MapperScan 引发的效应
在SpringBoot与Mybatis整合的过程中,往往都会在启动类上标注 @MapperScan注解,并指定basePackage。
那我们跟进去这个注解进去瞅瞅,会发现一个 @Import ,可以看到引入的是类 MapperScannerRegistrar。
那我们进入这个类看看:
ConfigurationClassPostProcessor
解析,如果发现@Import引入的是一个 ImportBeanDefinitionRegistrar 的实现,则会立即调用其 registerBeanDefinitions
方法。那我们继续看:可以看到王我们的容器里注入的一个Bean的描述文件,并且类型是 MapperScannerConfigurer,那我们来看看这个类结构:
可以看到的就是 BeanDefinitionRegistryPostProcessor ,这不是我们熟悉的一个后置处理器么,我们Debug看看:
就会执行到 MapperScannerConfigurer里的 postProcessBeanDefinitionRegistry 方法啦:
然后我们进入 Scan方法,这里要注意的是 doScan实际调用的是 mybatis-spring中的 ClassPathMapper 里的方法哈,这个很关键哈:
我们进入到doScan中来看看,对我们的BeanDefinition进行了转换,变成了MapperFactoryBean,并且设置了 SqlSessionTemplate、SqlSessionFactory等属性。
到这里我们的 Mapper接口的Bean描述文件就放进了 Spring容器了,并且Bean类型是 MapperFactoryBean包装起来的。
3 MapperFactoryBean
那我们对象怎么创建的呢,就交给了 MapperFactoryBean 看名字,就是一个FactoryBean 用来生成Bean对象的哇,里边有一个getObject 方法呀,那我们直接来看看:
可以看到其实就是通过 SqlSession来进行代理对象的创建,代理创建的细节我之前看过了哈,这里就不说了哈。
4 涉及到的关键组件
- @MapperScan 配置扫描包并引入MapperScannerRegistrar
- MapperScannerRegistrar 扫描Mapper接口以及增强MapperFactoryBean创建代理对象的埋入
- ImportBeanDefinitionRegistrar Bean描述文件放进Spring容器
- ClassPathBeanDefinitionScanner ClassPathMapperScanner 扫描增强
5 小结
好啦,本节我们主要看了一下 Mapper接口是怎么和 Spring融合的哈,下一节我用源码一步步分析,请看下节,有理解不对的地方欢迎指正哈。