阿昌教你看懂mybatisplus的sql语句的创建过程
阿昌 Java小菜鸡
## 前言

前置版本:MybatisPlus3.0.5

前些日子,阿昌写过一篇【mybatisplus的SqlSessionFacotry的创建过程】的菜鸡文章,这里我打算再记录一篇,关于mybatisplus的sql语句的创建过程。建议打开源码一起翻着看


前戏

同样,学过springboot的人都知道,如果要整合什么框架,肯定要去找XXXAutoConfiguration

MybatisPlusAutoConfiguration中有如下,对SpringIoc容器进行注入sqlSessionFactory

image

在这个方法中,他会读取properties/yaml文件中的配置,和给Spring的上下文ApplicationContext进行设置内容。

最后他会调用factory.getObject()

image

刚开始,我们肯定是没有sqlsessionfactory的,所以肯定会执行afterPropertiesSet

image

afterPropertiesSet中,他会调用buildSqlSessionFactory,来创建工厂

image

那好,我们已经到了SqlSessionFactory工厂的步骤,算是完成了前戏!!!


正文

buildSqlSessionFactory()是一个很长的方法,他总共有245行

整体的目的是根据我们在上面前戏中,读取到的配置文件的要求创建对应的工厂

那我们这次记录的重点是对sql语句的创建注入过程,那么他在buildSqlSessionFactory方法的哪里呢???

因为他很重要,所以他需要充足的条件,所以,在最后面

image

  • this.mapperLocations中有我们这次读取到的所有mapper.xml文件

image

  • 上面,他就先从全局配置中获取,是否有自动刷新配置。

原本我们项目启动一次会加载指定目录下的mapper.xml文件。

自动刷新配置就应该是设定有一个时机,他会再进行加载我们后加的mapper.xml文件。

image

  • 然后,他就对加载到的所有的mapper.xml文件进行遍历读取

image

  • 这里他通过XMLMapperBuilder来读取对应的mapper.xml文件,通过构造器给this.resource = resource附上值,然后执行bindMapperForNamespace

image

  • bindMapperForNamespace这里为这个mapper.xml绑定对应的Namespace,也就是对应的接口mapper类
  • 之后在根据boundType(类对象Class),来加入到配置内容中addMapper

image

  • 通过给mybatisMapperRegistry添加这个mapper内容

image

  • mybatisMapperRegistry添加,就会对这个mapper进行解析

image

  • 他会new MybatisMapperAnnotationBuilder()给传入配置内容和type(也就是大class对象)。进行初始化

image

  • 拿到上面MybatisMapperAnnotationBuilder的对象,对用parse()方法,对我们上面传入的type(mapper接口类),和对应配置设置进行解析

image

  • 那最关键的一步出现了,就是这个,就是这里parse()方法,可以通过这个Class对象,通过反射拿到他里面接口的方法

image

  • 他会拿到这个mapper接口类,里面的方法,对应接口上面注解的信息,和对应的xml文件的内容
  • 下面这个是mapper接口文件里面的方法,通过.xml配置文件写的sql

image

  • 下面也是在mapper接口文件的方法,但是是通过注解的方法写sql的

image

  • 这里的每一个方法就对应mapper接口中的一个方法

    image

  • 然后他会判断是否是桥接方法isBridge()

    桥接方法是 JDK 1.5 引入泛型后,为了使Java的泛型方法生成的字节码和 1.5 版本前的字节码相兼容,由编译器自动生成的方法。我们可以通过Method.isBridge()方法来判断一个方法是否是桥接方法。

image

  • 通过判断,他如果不是桥接方法,他就会执行parseStatement,去解析sql语句
  • getSqlSourceFromAnnotations(),会去对应这个方法的信息就获取对应的sql语句了!!!

image

  • 先获取都头上的注解,判断是不是注解写的sql
  • 然后他就能拿到注解上的这个具体写的sql,传入buildSqlSourceFromStrings进行解析

image

  • 那他是怎么解析的呢?点进去看看。

    image


<script脚本>

  • 发现,他会对这个传入获取的sql进行判断,是否带有script脚本,来判断执行哪个逻辑

image

  • 先看script脚本这个,他被包装了一层为XPathParser,然后传入createSqlSource

image

  • createSqlSource中,他会再进行包装,包装成XMLScriptBuilder,然后就执行parseScriptNode解析里面的内容

    image

  • 里面具体是什么样子的呢???

  • 解析里面的动态标签,判断他是否是动态的sql

image

  • 解析他是否是动态sql,判断里面的node节点,也就是xml标签里面还有xml标签,就认为他是动态sql

image

image

  • 判断完是否是动态sql,后就可以来用哪里SqlSource来封装他

    image

image


没使用<script脚本>

  • 回到之前的地方,如果他不是通过<script>脚本,那他就会走else的下面

image

  • 通过PropertyParserparse来解析,看到熟悉的${}了没有!!!
  • ${}来解析替换参数

image

  • parse里面进行出现了过的${}进行拼接

image

  • 那有个问题,他是如何进行判断是否是动态sql的呢???

image

  • 上面解析处理完了${}后,new TextSqlNode(script),然后就进行isDynamic判断是否是动态sql

image

  • 看上面,他是通过new一个DynamicCheckerTokenParser解析器,来去解析

  • parse

image

  • 他是在这里调用handler的handleToken方法

image

  • 发现这里给他设置了isDynamic为true,那就可以判断,他是根据是否有存在这样的关键字${}来判断他是否是动态sql

image


  • 拿到这里就算解析完了一条sql语句,然后不断的循环解析
  • 下面是一个例子

image

  • 然后他就拼接封装给assistant.addMappedStatement

image

  • addMappedStatement方法中,最后会封装成一个MappedStatement.Builder,加入到配置类configuration

image


  • 这个configuration,也就是Configuration接口,这里是MybatisConfiguration

image

  • 最后我们看到了,他吧解析完的statement都加到了configuration

image

  • 这样子就有了所有需要执行的sql语句信息,mp中的基础的17个基本查询方法他是分散的在里面

image

  • 我们自己写的自定义sql是如下形式

image

总结

这样子如上,我们看到了,他是不断的去读取mapper接口去反射回去对应的接口方法,获取头上的注解或者是.xml文件里面对应namespace名称空间的对应方法的xml标签,放入配置类中,并来获取组成遍历mapperLocations

image

然后在里面每一个都有一个methods,同样也是进行遍历,判断解析,是否是动态sql,是否是<script>脚本,还是row原生等

image

最后把他放到Mybatis配置类中的mappedStatements

image

image


那么以上就是这次记录的全部内容,感谢你能看到这里!!! (•‾̑⌣‾̑•)✧˖°

 请作者喝咖啡