Spring集成Mybatis的原理分析


我们在 MyBatis与Spring的集成 中分析了我们Spring与MyBatis集成的配置方法,后来我们有继续介绍了我们MyBatis相关的源码分析,这里我们就来看一看我们Spring是如何集成我们MyBatis的。


我们以前说了我们MyBatis集成到Spring之中,我们几乎就不需要配置MyBatis的配置文件了,除非一些在settings中的配置,其他的一律都可以在我们的Spring配置之中完成,其中针对MyBatis的配置最重要的如下:
Spring集成Mybatis的原理分析

在我们的Spring集成完MyBatis之后,我们就可以非常简单的来使用了,当然我们使用@Autowired注解也是可以的
Spring集成Mybatis的原理分析

但是为什么可以这样用呢?我们在 初识MyBatis 知道了我们MyBatis中使用的Mapper它的生命周期可都是方法级别的,这里集成了Spring为什么就可以直接在类中注入了呢?这样会产生安全问题么?
Spring集成Mybatis的原理分析



SqlSessionFactoryBean

在了解上述Mapper生命周期问题之前,我们先来了解一下我们的SqlSessionFactory,我们都知道我们在MyBatis中SqlSessionFactory是有SqlSessionFactoryBuilder进行创建的,存在于程序的整个生命周期。
Spring集成Mybatis的原理分析
这里我们在将MyBatis继承到Spring中之后,我们的SqlSessionFactory就是由SqlSessionFactoryBean进行创建了,如下:
Spring集成Mybatis的原理分析

其中我们发现SqlSessionFactoryBean实现了Factory以及InitializingBean接口,这两个接口我们都曾在Spring之中介绍过了,Spring基础组件的使用——@FactoryBean及源码分析Spring系列之Bean的生命周期及相关源码,这里就不赘述了。
Spring集成Mybatis的原理分析

我们知道FactoryBean接口是可以向Spring容器中注入Bean的,我们可以通过 getObject() 方法获取我们想要注入Spring容器的Bean
Spring集成Mybatis的原理分析

我们发现我们这个getObject() 方法是为了获取SqlSessionFactory的,先获取SqlSessionFactory之前会先判断一些我们的SqlSessionFactory有没有没实例化,要是没有的话,会通过实现InitializingBean接口的afterPropertiesSet方法去实例化
Spring集成Mybatis的原理分析
Spring集成Mybatis的原理分析

这里我们就会发现很熟悉,没错,这里又是我们的初始化的流程呀,就是为了得到我们的Configuration,然后去创建SqlSessionFactory,这里和我们在 MyBatis初始化阶段 中介绍了类似。
Spring集成Mybatis的原理分析


MapperFactoryBean

上述介绍了继承Spring后,我们的MyBatis是通过SqlSessionFactoryBean来读取配置文件获取到了SqlSessionFactory,那我们原来在MyBatis中是通过SqlSessionFactory获取SqlSession,然后再由SqlSession来获取Mapper接口对象的
Spring集成Mybatis的原理分析

那么我们在集成到Spring中是如何完成这一步的呢?

我们在Spring配置文件中针对某一个Mapper接口可以进行如下设置,就是通过了MapperFactoryBean来完成从SqlSessionFactory中取得SqlSession,并获取Mapper接口的对象
Spring集成Mybatis的原理分析

我们发现它也是实现了FactoryBean这个接口,那我们还是去看看其 getObject() 方法
Spring集成Mybatis的原理分析

我们发现这里就是先获取到SqlSession,然后再去获取Mapper
Spring集成Mybatis的原理分析

这里是不是就又很眼熟了,就是我们在 MyBatis binding模块分析 中介绍的呀,然后就是动态代理获取Mapper接口的实现类呀
Spring集成Mybatis的原理分析

那么再说过我们Mapper的生命周期的问题,这里为什么就可以注册到类之中了呢?

其实在我们的上述的配置信息中应该知道答案了,因为我们就不是直接注入的Mapper接口的对象呀,我们注入的是MapperFactoryBean,我们的使用的时候,才会去通过getObject方法通过里面的动态代理来获取Mapper接口的实现类。




MapperScannerConfigurer

但是我们一般在Spring配置文件中是看不到像我们上述那样去配置Mapper接口的,因为我们一个项目中一般是由非常非常多的Mapper的,难道我们需要一个一个的去配置么?


所以我们在Spring配置中一般直接使用MapperScannerConfigurer进行扫描
Spring集成Mybatis的原理分析

其中我们主要看看MapperScannerConfigurer实现的BeanDefinitionRegistryPostProcessor接口,这个接口我们在Spring中 Spring组件之BeanDefinitionRegistryPostProcessor使用及其源码 也是说过的
Spring集成Mybatis的原理分析
Spring集成Mybatis的原理分析

MapperScannerConfigurer中的postProcessBeanDefinitionRegistry方法中创建了一个扫描器,其中我们主要看其中的两个属性annotationClass和markerInterface
Spring集成Mybatis的原理分析

其中我们介绍过annotationClass的用法,其实markerInterface的用法也是类似的,只是annotationClass是设置后只扫描加上某个注解的Mapper文件,而markerInterface是设置后只扫描实现了某个接口的Mapper文件
Spring集成Mybatis的原理分析

配置好了之后,就对我们的basePackage进行扫描
Spring集成Mybatis的原理分析
Spring集成Mybatis的原理分析

我们发现这个方法是可以被继承的,我们直接看其子类的实现
Spring集成Mybatis的原理分析

它首先调用父类的doScan方法进行扫描,就是我们上面方法内的内容,我们这里主要看看其在扫描完,得到符合要求的接口之后做的处理
Spring集成Mybatis的原理分析

这里就是我们最核心的了,首先我们一开始就说了MapperScannerConfigurer实现了BeanDefinitionRegistryPostProcessor,这个接口我们之前在Spring中介绍过,它主要可以在Bean定义的时候可以修改一些信息。

首先进行遍历,因为我们一个basePackage下可能有很多的Mapper接口,然后把每一个接口进行注册,在注册时我们将其设置为MapperFactoryBean,并且我们还给它添加了SqlSessionFactory,这是不是就和我们上述介绍MapperFactoryBean引入一个Mapper接口的形式一模一样了,它就是通过这样,把扫描到的所有符合条件的Mapper接口都转换成了我们一开始介绍的形式。
Spring集成Mybatis的原理分析