在上一篇中,我们介绍了在SpringBoot容器中,Mybatis加载mapper interface的过程,但对于mapper加载的全过程,这仅仅完成了50%,剩下的50%就是mapper的关联SQL配置的加载过程,本篇,我们将围绕下面两个问题进行展开:
1、mapper的关联SQL配置是如何进行加载的?
2、Mybatis是如何将mapper interface与SQL配置关联在一起的?
首先,我们先来回顾一下mapper interface
的加载过程:
上面的流程图就是Mybaits加载mapper interface
的全流程,其实,mapper关联的SQL配置的加载过程就包含在其中,我们以MapperFactoryBean
作为切入点,来分析一下。
MapperFactoryBean
从名字中我们就可以看出来,这是一个Mapper bean
的工厂类,它继承了SqlSessionDaoSupport
类并实现了FactoryBean
接口,具备了FactoryBean
的能力。
在SpringBoot初始化mapper bean
的过程中,会调用checkDaoConfig
方法,在方法中,首先会检查mapper interface
是否已经完成了初始化,如果没有,则进行初始化,我们继续进入configuration.addMapper(this.mapperInterface)
看看其实现:
调用了Configuration
的addMapper
方法,我们继续。
OK,最终进入了MapperRegistry
的addMapper
方法,进行最终的加载,在MapperRegistry
中,存储了已经加载完成的mapper interface
的Map容器,在addMapper
方法中,会进行两步操作:
1、检查mapper interface
是否在初始化好的容器列表中;
2、如果没有,则放入容器列表中,然后初始化关联的mapper annotation
或XML配置信息。
看到这里,我们大概清楚mapper的SQL关联配置真正的加载实现所在了,我们继续深入。
真正的解析配置的动作是由MapperAnnotationBuilder
的parse
方法执行的,在分析其实现之前,我们先来看一下这个类所在的目录结构:
上图是Mybatis项目的目录结构,可以看到,MapperAnnotationBuilder
所属与builder
包下,在该包下,存在两个子目录结构,分别是annotation
与xml
,看到这里,想必您肯定也一目了然,这正是对应了Mybatis的两种mapper关联SQL配置的方式,换句话说,就是两种书写SQL语句的方式,而默认的情况下,SpringBoot加载Mybaits是使用MapperAnnotationBuilder
作为解析入口。
OK,我们继续分析MapperAnnotationBuilder
的parse
方法的实现:
上图是MapperAnnotationBuilder
的parse
方法实现内容,主要分为五个部分:
1、获取mapper interface
全路径限定名称;
2、检查mapper interface
是否已经加载过;
3、如果没有加载,尝试加载关联的XML配置文件;
4、将mapper interface
加入到已加载列表中;
5、遍历mapper interface
中的全部方法,进入annotation
加载流程。
我们来重点分析其中关键两个部分,XML配置的加载过程与annotation
配置的加载过程,首先来看XML配置的加载过程。
进入loadXmlResource
方法,其中主要进行了两步操作:
1、根据mapper interface
的全限定路径名称,寻找classpath
下同名的XML文件;
2、解析加载XML文件。
我们继续深入:
XML的解析过程可以如上图所示,首先仍是判断该mapper interface
是否已经加载过,如果没有,开始对XML配置中的标签进行逐个解析,详细的解析过程我们就不深入分析了,主要是解析XML的DOOM树结构,获取标签中的具体内容,需要关注的是解析过程中的最后一个方法:buildStatementFromContext
。
进入statementParser.parseStatementNode()
:
实现比较长的一个方法,不过其实现内容可以一目了然,主要是对XML配置文件中的各个标签进行解析的过程,重点关注的是在方法的最后,执行的builderAssistant.addMappedStatement
方法。
builderAssistant.addMappedStatement
方法的实现如上图所示,在其中通过MappedStatement.Builder
的构造器构造出一个statementBuilder
对象,存入Configuration
的mapperStatement
的Map集合中,而这个Map集合的key,就是XML配置文件中的
中的属性值。
而MappedStatement
对象,其中则存储了mapper interface
对应的SQL语句,而mapper interface
与SQL的关联关系,正是通过mapper interface
的全限定路径名称进行关联的。
但在SpringBoot加载mapper interface
关联的XML配置文件的过程,其实并不是在这里进行的,而是在SqlSessionFactoryBean
中进行加载的,我们来看一下其实现。
SqlSessionFactoryBean
实现了InitializingBean
接口,实现了afterPropertiesSet
方法,在bean初始化的时候会调用该方法,在afterPropertiesSet
中,调用了buildSqlSessionFactory
方法:
我们主要关注下面的实现:
mapperLocations
是通过SpringBoot的application.properties
文件中的mybatis.mapper-locations
参数注入进来的,这里会扫描XML配置文件所在目录下的全部XML配置文件,并逐一解析,完成加载过程。
OK,XML配置文件的加载过程我们就分析完毕,再回头看一下annotation
配置的加载过程。
上面我们先分析了XML配置文件的加载与关联mapper interface
的过程,下面我们再看一下Annotation
的加载过程:
我们来看上图中的第五步,这里会遍历mapper interface
中的全部方法列表,逐个进行解析,在解析之前,有一个isBridge
的判断,判断该方法是否是桥接方法,那么什么是桥接方法呢?简单的说,就是由Java编译器隐式的自动生成的一种方法,具体的解析可以参见:
Java反射中method.isBridge() 桥接方法:https://blog.csdn.net/liu20111590/article/details/81294362
进入parseStatement
方法实现:
看到这里,是不是有种还是原来的配方,还是原来的味道的感觉?没有错,这里的解析过程与XML配置文件的解析过程非常相似,对方法上的@Annotation进行逐个解析,最终生成一个MappedStatement
对象。
本篇,我们介绍了Mybatis加载Mapper关联SQL配置的整个过程,现在也可以解释文章开头的两个问题:
1、mapper的关联SQL配置是如何进行加载的?
2、Mybatis是如何将mapper interface与SQL配置关联在一起的?
整个加载过程非常的冗长,建议您看完本篇后,可以下载一下mybatis3与mybatis-spring的项目源码,跟着我的思路,一步一步走一遍,相信您也会有非常大的收获。
对于Mybatis的整个初始化流程就介绍完毕了,那么又来了新的问题,Mybaits是如何执行一条SQL语句的?在下一篇中,我们会揭开这个答案,敬请期待!
感谢您的阅读。
更多精彩文章, 请关注我的个人公众号:老宣说
让我们一起共同学习成长!
感谢您的支持!