前置版本:
MybatisPlus3.0.5
前些日子,阿昌写过一篇【mybatisplus的SqlSessionFacotry的创建过程】的菜鸡文章,这里我打算再记录一篇,关于mybatisplus的sql语句的创建过程。建议打开源码一起翻着看
前戏
同样,学过springboot的人都知道,如果要整合什么框架,肯定要去找XXXAutoConfiguration
。
在MybatisPlusAutoConfiguration
中有如下,对SpringIoc容器进行注入sqlSessionFactory
在这个方法中,他会读取properties/yaml文件中的配置,和给Spring的上下文ApplicationContext进行设置内容。
最后他会调用factory.getObject()
刚开始,我们肯定是没有sqlsessionfactory的,所以肯定会执行afterPropertiesSet
在afterPropertiesSet
中,他会调用buildSqlSessionFactory
,来创建工厂
那好,我们已经到了SqlSessionFactory工厂的步骤,算是完成了前戏!!!
正文
buildSqlSessionFactory()是一个很长的方法,他总共有245行
。
整体的目的是根据
我们在上面前戏中,读取到的配置文件
的要求创建对应的工厂
。
那我们这次记录的重点是对sql语句的创建注入过程,那么他在buildSqlSessionFactory方法的哪里呢???
因为他很重要,所以他需要充足的条件,所以,在最后面
。
- 在
this.mapperLocations
中有我们这次读取到的所有mapper.xml文件
- 上面,他就先从全局配置中获取,是否有自动刷新配置。
原本我们项目启动一次会加载指定目录下的mapper.xml文件。
自动刷新配置就应该是设定有一个时机,他会再进行加载我们后加的mapper.xml文件。
- 然后,他就对加载到的所有的mapper.xml文件进行
遍历读取
- 这里他通过
XMLMapperBuilder
来读取对应的mapper.xml文件,通过构造器给this.resource = resource
附上值,然后执行bindMapperForNamespace
bindMapperForNamespace
这里为这个mapper.xml绑定对应的Namespace
,也就是对应的接口mapper类- 之后在根据
boundType(类对象Class)
,来加入到配置内容中addMapper
- 通过给
mybatisMapperRegistry
添加这个mapper内容
- 给
mybatisMapperRegistry
添加,就会对这个mapper进行解析
- 他会
new MybatisMapperAnnotationBuilder()
给传入配置内容和type(也就是大class对象)。进行初始化
- 拿到上面MybatisMapperAnnotationBuilder的对象,对用
parse()
方法,对我们上面传入的type(mapper接口类),和对应配置设置进行解析
- 那最关键的一步出现了,就是这个,就是这里
parse()方法
,可以通过这个Class对象,通过反射
拿到他里面接口的方法
- 他会拿到这个mapper接口类,里面的方法,对应接口上面注解的信息,和对应的xml文件的内容
- 下面这个是mapper接口文件里面的方法,通过.xml配置文件写的sql
- 下面也是在mapper接口文件的方法,但是是通过注解的方法写sql的
这里的每一个方法就对应mapper接口中的一个方法
然后他会判断是否是
桥接方法isBridge()
桥接方法
是 JDK 1.5 引入泛型后,为了使Java的泛型方法生成的字节码和 1.5 版本前的字节码相兼容,由编译器自动生成的方法。我们可以通过Method.isBridge()方法来判断一个方法是否是桥接方法。
- 通过判断,他如果
不是桥接方法
,他就会执行parseStatement,去解析sql语句 - getSqlSourceFromAnnotations(),会去对应这个方法的信息就获取对应的sql语句了!!!
- 先获取都头上的注解,
判断是不是注解写的sql
- 然后他就能拿到注解上的这个具体写的sql,传入
buildSqlSourceFromStrings
进行解析
那他是怎么解析的呢?点进去看看。
<script脚本>
- 发现,他会对这个传入获取的sql进行判断,是否带有
script脚本
,来判断执行哪个逻辑
先看script脚本这个
,他被包装了一层为XPathParser
,然后传入createSqlSource
在
createSqlSource
中,他会再进行包装,包装成XMLScriptBuilder
,然后就执行parseScriptNode
解析里面的内容里面具体是什么样子的呢???
解析里面的
动态标签
,判断他是否是动态的sql
- 解析他是否是动态sql,判断里面的node节点,
也就是xml标签里面还有xml标签
,就认为他是动态sql
判断完是否是动态sql,后就可以来用哪里
SqlSource
来封装他
没使用<script脚本>
- 回到之前的地方,如果他不是通过
<script>
脚本,那他就会走else的下面
- 通过
PropertyParser
的parse
来解析,看到熟悉的${}
了没有!!! - 用
${}
来解析替换参数
- 在
parse
里面进行出现了过的${}进行拼接
- 那有个问题,他是如何进行判断是否是动态sql的呢???
- 上面解析处理完了
${}
后,new TextSqlNode(script)
,然后就进行isDynamic
判断是否是动态sql
看上面,他是通过new一个
DynamicCheckerTokenParser
解析器,来去解析在
parse
中
- 他是在这里调用
handler的handleToken
方法
- 发现这里给他设置了
isDynamic
为true,那就可以判断,他是根据是否有存在这样的关键字${}
来判断他是否是动态sql
- 拿到这里就算解析完了一条sql语句,然后不断的循环解析
- 下面是一个例子
- 然后他就拼接封装给
assistant.addMappedStatement
- 在
addMappedStatement
方法中,最后会封装成一个MappedStatement.Builder
,加入到配置类configuration
中
- 这个configuration,也就是Configuration接口,这里是
MybatisConfiguration
- 最后我们看到了,他吧解析完的
statement
都加到了configuration
中
- 这样子就有了所有需要执行的sql语句信息,mp中的基础的17个基本查询方法他是分散的在里面
- 我们自己写的
自定义sql
是如下形式
总结
这样子如上,我们看到了,他是不断的去读取mapper接口
去反射回去对应的接口方法,获取头上的注解或者是.xml文件里面对应namespace名称空间的对应方法的xml标签,放入配置类中,并来获取组成遍历mapperLocations
然后在里面每一个都有一个methods
,同样也是进行遍历,判断解析,是否是动态sql
,是否是<script>脚本
,还是row原生等
最后把他放到Mybatis配置类中的mappedStatements
中
那么以上就是这次记录的全部内容,感谢你能看到这里!!! (•‾̑⌣‾̑•)✧˖°