Mybatis中SqlSource解析流程详解

前面几篇文章都在详细分析mapper的加载过程,但是始终没有看到sql的解析过程,今天来详细分析下。

解析sql的位置

前面分析到不管是通过注解还是通过xml方式生成mapper,最终都是调用MapperBuilderAssistant类的addMappedStatement方法,这个方法接受的其中一个SqlSource参数,SqlSource类中就是XML文件或者注解方法中映射语句的实现

那么SqlSource对象是在哪里创建的呢?

在通过注解实现mapper的流程中是在MapperAnnotationBuilder类的parseStatement方法中对SqlSource进行初始化,初始化代码如下图:

通过xml文件实现mapper的流程中是在XMLStatementBuilder类的parseStatementNode方法中对SqlSource进行初始化,初始化代码如下图:

可以看到创建SqlSource对象都是通过LanguageDriver实现的,翻译过来叫做语言驱动,它是一个接口,通过上面源码可以看出来我们可以自己实现这个接口,并且可以指定使用哪个语言驱动。今天我们只关注mybatis自带的一个实现XMLLanguageDriver。

XMLLanguageDriver介绍

XMLLanguageDriver类有重载了两个createSqlSource方法,主要区别在于第二个参数script,从前面两张源码图中可以知道接受XNode类型的script是在解析xml时使用,接受String类型的script是在解析注解时使用,今天只解析接受XNode类型的方法。

这个方法比较简单只有两步:初始化一个XMLScriptBuilder对象,执行XMLScriptBuilder对象的parseScriptNode方法。所以重点来到XMLScriptBuilder这个类。

XMLScriptBuilder详解

XMLScriptBuilder类部分源码如下图:

XMLScriptBuilder的初始化比较简单,要记住XNode context对应的是xml中的一个select、update等节点,在最后调用了initNodeHandlerMap方法设置了select、update等节点子节点对应的处理器。

接着是parseScriptNode方法,可以看到parseScriptNode方法调用了parseDynamicTags方法生成了一个MixedSqlNode对象,然后根据属性isDynamic判断创建对应的SqlSource对象。

所以最终要看parseScriptNode方法,同时可以判断isDynamic这个属性肯定也会在这个方法中发生变化,parseScriptNode方法的源码如下图:

parseDynamicTags方法解析节点下面所有子节点进行遍历,如果节点是文本节点这解析里面的内容生成SqlNode(这里是TextSqlNode或者StaticTextSqlNode)对象放到contents集合中。

如果是脚本节点比如where、if等就调用初始化时保存的节点处理器,如上图的ForEachHandler、IfHandler处理器,这些对象的处理方法handleNode的第一行代码又在调用parseDynamicTags方法,就像是一种递归。所以我们可以得出xml中的where、if、foreach这些节点时可以彼此包含的,解析时再进行递归解析

当然要想调用parseDynamicTags方法,这些对象都是属于当前类XMLScriptBuilder的内部类。

大的方向梳理了我们再来看这个方法到底在干什么,首先这个方法会收集SqlNode对象放到contents集合中,最后把contents作为参数生成MixedSqlNode对象。在处理的过程中如果遇到if、foreach等节点还会把contents传递进去,从上面的图中可以看到ForEachHandler、IfHandler处理器也会调用parseDynamicTags方法生成MixedSqlNode然后再生成对应的SqlNode放到contents中。

所以最终来到两个关键类MixedSqlNode、SqlNode,当然SqlNode肯定有各种子类。

MixedSqlNode与SqlNode

那么MixedSqlNode与SqlNode是什么样子的呢?又是如何组合的?具体源码如下图:

可以看到SqlNode是一个接口,而MixedSqlNode只是他的一种实现类,同时来贴出来了静态文本处理的类和if节点对应的IfSqlNode类,还有一些其他比如WhereSqlNode、ForEachSqlNode等就不再列出来了。

每一种实现类的初始化都比较简单,比如StaticTextSqlNode是保存一段文本,IfSqlNode保存了if节点的test属性对应的值和从if节点下解析出来的MixedSqlNode节点。

而他们有一个由SqlNode规定的apply方法,这才是他们正真的作用所在,比如MixedSqlNode是遍历所有节点执行对应的apply方法,StaticTextSqlNode就只是把对应sql拼接到后面,IfSqlNode是在进行判断后调用MixedSqlNode去执行if节点下所有的节点。

至于参数DynamicContext后面在调用的时候会分析的。

现在回到XMLScriptBuilder的parseScriptNode方法,方法在执行了parseDynamicTags方法后根据isDynamic属性初始化了SqlSource,对应类结构图如下图:

我们主要关注DynamicSqlSource这个类,可以看到它就两个属性configuration、rootSqlNode,分别是全局配置和刚刚分析的MixedSqlNode,也可以从他的getBoundSql方法中看到后面对rootSqlNode的使用,这个留着后面分析。

总结

在configuration中有一个map属性mappedStatements,他保存着MappedStatement对象,每个MappedStatement对象对应一个sql的所有信息,而MappedStatement也有一个属性SqlSource,通过SqlSource能够获取到对应的sql,而sql的解析时依靠SqlNode。

今天的重点就在于生成SqlNode的过程,它是通过XMLScriptBuilder类是处理xml中crud节点生成。

这里有意思的是设计时是XMLScriptBuilder自带处理节点的方法parseDynamicTags生成需要的MixedSqlNode,而在parseDynamicTags方法内部可能会调用内部类WhereHandler、IfHandler的handleNode方法生成对应的SqlNode,而在这些handleNode方法中第一步就是调用parseDynamicTags去生成MixedSqlNode,根据MixedSqlNode生成对应的SqlNode。通过这种递归实现了节点多层嵌套的解析

第二个有意思的点在于SqlNode的框架设计,MixedSqlNode存储一个SqlNode的集合,而具体的比如IfSqlNode又可以持有SqlNode,通过这样实现,每种SqlNode都可以拥有所有各种的SqlNode功能,但是他们有拥有自己独立的特点。

正是XMLScriptBuilder和SqlNode这种灵活的设计才可以使xml标签有非常强大的支持,同时解析的时候又不至于太复杂。

Java程序员日常学习笔记,如理解有误欢迎各位交流讨论!

(0)

相关推荐

  • Mybatis系列全解(八):Mybatis的9大动态SQL标签你知道几个?提前致女神!

    封面:洛小汐 作者:潘潘 2021年,仰望天空,脚踏实地. 这算是春节后首篇 Mybatis 文了~ 跨了个年感觉写了有半个世纪 ... 借着女神节 ヾ(◍°∇°◍)ノ゙ 提前祝男神女神们越靓越富越嗨 ...

  • Mybatis源码阅读套路,一次性打包发您~

    很多人看源码都不知道如何看,今天来教教大家如何看源码. 前提是我们需要对整个Mybatis的原理.工作流程和模块进行一个整体的直知晓,另外还要有使用经验. 建议先看这两篇文章: 本文主要内容: 源码下 ...

  • Java最新高频大厂面试集锦(附答案),真香警告

    44. 创建线程池有哪几种方式? 45. 线程池都有哪些状态? 46. 线程池中 submit() 和 execute() 方法有什么区别? 47. 在 Java 程序中怎么保证多线程的运行安全? 4 ...

  • Mybatis中类型映射处理器详解

    上一篇梳理了Configuration初始化分析,今天继续typeHandlers部分. 数据库厂商标识 接上一篇文章分析,下一个解析的是databaseIdProvider节点,这个节点好理解,从字 ...

  • Mybatis中mapper相关注解解析类详解

    上一篇文章分析发现解读mapper关键是两个类MapperAnnotationBuilder和XMLMapperBuilder,今天先来看MapperAnnotationBuilder. 基础介绍 根 ...

  • 什么是从革格?八字格局中从革格详解关于八字命理解析

    什么是从革格?详细了解什么是从革格就得先了解什么是从革,八字命理术语解释中,以金曰从革,从革也就是代表五行中的金,即十天干之庚金与辛金. 八字格局从革格诗诀: 秋月金居一类看.名为从革便相欢. 如无炎 ...

  • Mybatis对mapper的加载流程详解

    今天来分析Configuration初始化的最后一部分mapper的加载. 加载方法mapperElement XMLConfigBuilder配置Configuration的parseConfigu ...

  • 《伤寒论》中的咳嗽治法详解

    <伤寒论>本论398条中,论及咳嗽的条文计10条13次,涉及到多种病因和多个脏腑. 1.饮邪作祟致咳 饮邪作祟致咳是<伤寒论>论及咳嗽所提到的重要病机.人体水液代谢与肺.脾(胃 ...

  • 破产重整流程详解

    一.破产重整流程详解 重整申请一是重整对象的选择.需根据标的公司的股东人数.资产金额.员工人数.经营规模.经营范围.社会影响等指标来考察一个企业是否适合重整:二是明确重整的原因.不能清偿到期债务,并且 ...

  • 分布式光伏发电并网流程详解

    光伏资讯 746篇原创内容 公众号 做分布式光伏项目,并网流程是最关键的环节之一,并网申请工作贯穿着分布式光伏项目实施的全过程,并网验收更是项目结束的关键性指标. 随着光伏发电政策的不断完善,光伏并网 ...

  • 河道景观方案设计全流程详解

    城市河流最初的形式是城市边上自然的过境河,后来由于防御.运输.用水.防洪等需要,逐渐出现了护城河(壕).运河.引水河渠和排洪河道等城市河流. 到了近代,城市的快速发展导致城市河流出现了诸多问题,如严重 ...

  • 两轮与三轮电摩上牌流程·详解

    解析上牌流程之前首先需要说明一点: 符合摩托车型标准的两轮与三轮车可以正常上牌,上牌流程与燃油动力摩托车相同:反之不符合标准,以及车辆品牌不在工信部<目录>中的车辆是无法上牌的. 很多人在 ...