在 Spring Boot 中使用 Mybatis 时,会经常使用到一个注解 MapperScan,它可以指定对哪些包进行扫描(basePackages
),将哪些类作为 Mapper 类(basePackageClasses
),多数据源下的一些设置等,除了 basePackages
外,另一个重要的时 factoryBean
,它的默认值是 MapperFactoryBean
,这个属性在后续至关重要。
在 MapperScan 的注解上,还使用了 @Import
,参数为 MapperScannerRegistrar
,实际的 Bean 对象的注册是在该类中完成的。
在其 registerBeanDefinitions 的方法中,主要完成了以下几件事情:
- 生成一个
MapperScannerConfigurer
的BeanDefinitionBuilder
- 对属性进行设置,其中重要的一点是在不指定
basePackages
属性时,它会获取当当前注解所在的类的全限定包。 - 在 Spring 容器中注册
MapperScannerConfigure
。
MapperScannerConfigure
实现了 BeanDefinitionRegistryPostProcessor
,它允许在 Bean 对象在注册过程中进行自定义操作,甚至注册更多的 Bean 对象。MapperScannerConfigure
实现了 postProcessBeanDefinitionRegistry
方法。简单来说,在该方法下会通过 ClassPathMapperScanner
读取到 basePackages
、basePackageClasses
等设置的所有的接口,将其注册到 Spring 容器内。
ClassPathMapperScanner
继承自ClassPathBeanDefinitionScanner
,重写了 doScan 方法:
java
@Override
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
if (beanDefinitions.isEmpty()) {
LOGGER.warn(() -> "No MyBatis mapper was found in '" + Arrays.toString(basePackages)
+ "' package. Please check your configuration.");
} else {
// 处理 Bean 对象的定义,实际上是对其属性进行设置
processBeanDefinitions(beanDefinitions);
}
return beanDefinitions;
}
在 processBeanDefinitions
方法中,主要进行了以下操作:
- 设置实际的
beanClass
为注解中设置的factoryBean
,默认为MapperFactoryBean
(也是该类属性的默认值)。 - 设置被代理的接口。
- 设置
sqlSessionTemplate
属性。
MapperFactoryBean 实现了 FactoryBean,在其简介中提到了实现了 FactoryBean 的类都是某个对象的获取工厂
Interface to be implemented by objects used within a {@link BeanFactory} which are themselves factories for individual objects. 】
也就是说在 Spring 容器进行依赖注入的时候,最终会调用 FactoryBean 的 getObject 获取实际的对象, MapperFactoryBean 的实现如下:
java
@Override
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}
也就是使用了 MyBaits 原生的 getMapper 拿到接口的代理类,Spring 整合 MyBatis 的流程结束。
但是实际开发过程中是,会出现不写 MapperScan 的情况。
在这种情况下,利用 Spring 的 SPI 机制,自动注入 MybatisAutoConfiguration 类。该类除了基本的注入 SqlSessionFactory 和 SqlSessionTemplate 外,还会在未注入 MapperFactoryBean
和 MapperScannerConfigurer
时,使用 AutoConfiguredMapperScannerRegistrar
进行自动注册。该类的大致流程也是先拿到 MapperScannerConfigurer
的 BeanDefinitionBuilder
,然后设置其属性,最后注册到 Spring Boot 的容器中。
关注公众号:KeepLoving 一起学习更多源码知识。