MyBatis源码阅读指南

MyBatis源码阅读指南

概要:

  1. 前言
  2. 整体架构
  3. 学习重点
  4. 学习路径
  5. 总结
    注:文本有4301个字,预计阅读11分钟,请君耐心
    前言
    在MyBatis 3.5.1这个版中有968个类、2770个字段、8422个方法、42504行代码、186428个指令码。其源码体量只有Spring 的1/5,也是Hibernate的1/5。但在功能上这三个框架并无高低之分,但从源码轻量级来讲,MyBatis无疑是最成功的。
    极简主义风格
    这其中原因在于作者Clinton Begin 极简主义风格,以及恰到好处的设计,不去盲目追求可扩展性。比如:在MyBatis代码中很少有注释,但你并不会因此看不懂,而Spring 源码中随处可见大量的注释,反而还看不懂,这就是极简主义的好处。
    不增加新概念
    此外MyBatis也是尽可能的不增加新概念。比如:它的插件机制和Spring AOP功能都是一样的。MyBatis的整个实现不到350行代码,涉及概念有拦截器、执行器两种。而Spring AOP 用一整个模块实现,代码有5700行。涉及概念有通知、连接点、切入点、切面、引入、目标、代理、织入等。这里我不评判这些概念有无必要,但它增加了用户理解难度,这点是确定的。
    MyBatis源码阅读指南_第1张图片 综上1所述,如果你想完整的吃透一个框架源码,MyBatis绝对是最省力气的。更重要的是它优秀的设计也非常值得我们去学习。那我们应该如何开始呢?首先得了解它的宏观架构。

整体架构

       MyBatis可分为三层,接口层、数据处理层、扩展与支撑层。

MyBatis源码阅读指南_第2张图片
接口层
指用于操作数据库的增删改查接口,如SqlSession以及用户自定义的Mapper接口,都属于接口层组件。通常我们对MyBatis源码学习是从接口层开始的,但这并不是一个好方法,至于原因会在学习路径中讲到。
数据处理层
SQL执行流程实现,内容包括动态SQL语句构建、参数映射处理、结果映射集处理。他是整个MyBatis源码的核心,也是我们学习的重点和难点。

扩展与支撑层
指对主流程功能上的扩展与支撑。

  • 扩展:对主流程,在易用性、性能上进行扩展。如SqlSession与Mappr接
  • 口就是易用性扩展。缓存与懒加载则是执行性能的扩展。
  • 支撑:主程所依赖的工具,如数据源、反射工具、日志管理、配置构建器、脚本执行器等。

学习重点

   数据处理层是MyBatis核心与重点,我们学MyBatis源码其实就是学它,搞定它MyBatis源码就掌握了80%,当然它的难度也是最大的。为方便理解,我把它分成了执行流程与映射配置两部分。
  • 执行流程:体现SQL执行过程中的每个步骤。
  • 映射配置:SQL执行前后的动态SQL解析、参数映射、结果集映射。

执行流程:
一个完整SQL执行流程,至少包含以下节点:

  1. 执行器:处理一至多个SQL、以及、缓存、事务、批处理等。
  2. Sql处理器 :用于声明Statement、参数设置、执行、以及结果集处理。
  3. 参数处理器:基于映射进行具体的参数赋值处理。
  4. 结果集处理器:基于映射进行具体的结果集处理。
    MyBatis源码阅读指南_第3张图片(注:图中绿色字体表示,表示交给下个组件实现)
    每个节点都会完成SQL执行过程中特定任务,越到后面,其负责的事情就会越具体。
    MyBatis源码阅读指南_第4张图片

我们可以把 执行器理解成一个“指挥官”,它组织一至多次的SQL进攻,并把握进攻的节奏和方式,但自己不参与实际的战斗。

  • 缓存:佯攻,虚张声势并不会真正对数据库发起进攻。
  • 批处理:部队集结在一起,然后一起进攻
  • 事务:决定何时结束战斗
  • SQL执行:真正发起进攻(交给小队去执行)
    MyBatis源码阅读指南_第5张图片

Sql处理器理解成一个“队长”,它带队负责一次具体的SQL进攻。不仅自己要亲自上阵,还要分配任务给队员。

  • SQL声明:申请作战武器
  • 参数处理:炮弹上膛,分配任务给队员
  • 执行:开火发射
  • 结果集处理:清理战场,分配任务给队员

最后参数处理器、结果集处理器、类型处理器都是负责具体局部任务的士兵。 将军、队长、士兵都有了,我们用户应该是什么呢?
用户当然是上帝啦,我们在上帝视角去配置、决定这场战争的走向。

映射配置
MyBatis源码中映射配置特指以下三件事情:

  • 动态SQL:基于配置的脚本,以及参数生成Sql字符串。

1.参数映射:转换JAVA参数,并设置成SQL参数

  • 结果集映射解析:指定数据结果集,转换成JAVA对象。有1对1转换、1对多转换,还包括映射循环依赖等解决方案。它是MyBatis当中最难的知识点。
    看到这里,你可能会奇怪,结果集映射,与结果集处理不是一回事吗?为啥要分开讲?确实是在干同一件事情。但关注点不一样,结果集处理关注流程,关注其在Sql流程当中的位置,上下承接了哪些组件?而勿略具体的处理细节。结果集映射就是具体的1对1、1对多的处理细节。
    分开讲的目的,是帮助读者你能循序渐近,有层次的去掌握MyBatis,而不是一开始就陷入无休止的细节当中。参数映射也是同理的。

学习路径

MyBatis源码阅读指南_第6张图片

在山脚下任何一条路都是通往山顶的,但不是随便哪条路都能登顶,专业运动员一定懂得挑选最合适的路线。

关于MyBatis源码学习路径,供我们选择的有三条:

  1. 从上往下,按接口层、数据处理层、基础支撑层的顺序学习。
  2. 从下往上,反过来,先把底层依赖掌握,再去掌握上层应用。
  3. 从中间往两头,即直接学习中间数据处理流程,然后在去学习其中牵扯出的技术。
    思考一下:会选择哪一种?你平时是按哪一种方式去学习?
    我们应该选择第三种。因为源码的体量非常大,必须先抓核心。
    而第一种方式很难抓住核心,因为接口层是抽象的,其实例也要被代理、要被适配之后,才会进入核心。比如SqlSession在走SQL执行流程前,要经过系列的参数转换,或方法适配。
    同样也不适合用第三种,即使它是基础很重要,但因为它都是为数据处理层服务,如果脱离应用场景去学习,会加大理解难度。给人一种不能落地的感觉。
    实践证明,第三种是最可靠的。直接去学习核心流程,在核心流程学习过程中,把相关依赖搞定。最后做为流程的延伸去讲解接口层。
    最后确定学习路径如下:
  4. 执行流程
  5. 映射配置
  6. 扩展支撑

学习目标分解

MyBatis源码阅读指南_第7张图片

不带着目标去看源码的人,他不是在学习,他只是在消磨时间。

学MyBatis源码之前一定要分解目标,并适时检查自己是否完成目标,这样才能持续学习下去。我们经常说源码学了就忘记,原因就是没有学习目标去检查,导致学了半桶水也不知道。这种不完善的知识体系是最容易忘记的。以下就是我们要给自设定的学习目标:

第一目标:Sql执行流程
MyBatis源码学习的第一个目标就是要搞定四个组件所组成的Sql执行流程。这个四个组件分别是,执行器(Execute)、Sql处理器(StatementHandler)、参数处理器(ParameterHandler)、结果集处理器(ResultSetHandler)。这个目标又可分解成4个小目标

  1. 理解四个组件执行上的顺序
  2. 每个组件的作用及意义
  3. 掌握Execute 的三个实现逻辑
  4. 掌握StatementHandler的三个实现逻辑

这个目标不是最难的,但是最要的。如果有一天你把学的MyBatis源码忘的差不多了,也希望你这个流程不要忘,这是MySql源码的主干和肪脉络。顺着它就可以把MyBatis知识再拾回来。
说明:关于参数处理、结果集处理其主要逻辑细节在于映射处理,可以放到映射篇章学习。
第二目标:映射配置
第二个要搞定的目标,就是SQL执行流程当中,所需要的三大映射:分别是动态SQL映射、参数映射、以及结果集映射。不仅要搞清楚映射配置的加载与解析,更重要的弄清楚映射逻辑。

  • 加载解析:指用户配置的XML解析成JAVA配置对象。比如…块,最终要解析成SqlSource。或…
    要解析成ResultMap对象。
  • 映射逻辑:比如SqlSource如何基于参数生成可执行SQL,ResultMap如何将结果集,解析成JAVA对象等。
    这里面涉及内容非常多,同样可以划分成一个个小目标:
    小目标
  1. 理解Sql映射声明(MappedStatement)的作用,以及它与三大映射的关系。
  2. 掌握动态SQL(sqlSource)解析过程,包括其脚本表达示的执行逻辑
  3. 掌握MyBatis所封装的映射工具包的使用
  4. 掌握参数转换过程,以及映射的封装过程
  5. 掌握结果集映射核心逻辑,包括关联映射,1对1、1对多的处理。还有更复杂的循环依赖处理
  6. 掌握全部配置(Confgiuration) 的核心定位,以及它的加载解析过程

结果集映射是整个MyBatis源码当中的最难的点,其关联映射会涉及子查询、一级缓存引用、循环依赖、延迟加载、懒加载、自动映射等知识点。个个都不是善茬,攻克不易。

第三目标:扩展支撑
前面两个目标如果搞定了,恭喜你,MyBatis实质上你已经拿下了,接下来的学习就会有一种水道渠成的轻松。

这个程度就好比你和女神已经同居,只差领证了。

    所谓扩展指对主流程的延伸。如:通过执行器可以完成所有功能,但使用太繁琐,会话(SqlSession)正是为简化它的使用。Mapper接口的设定也是一样,是为进一步简化使用会话。
   除了针对易用性扩展,还有提高执行性能的扩展,比如:缓存、懒加载等。最后的插件机制则是暴露给用户自定义的扩展。接下来我们继续分解学习目标:

小目标

  1. 掌握一二级缓存的结构,及执行逻辑。
  2. 理解会话的意义和其采用的设计模式。
  3. 掌握Mapper接口动态代理流程。
  4. 掌握插件机制底层原理。
  5. 掌握懒加载的流程。

在当前内容学习过程当中,
你也会掌握大量的设计模式,如二级缓存的装饰器+责任链模式、会话所采用的门面模式、以及Mapper接口对应动态代理模式等。

最后总结一下:

  • MyBatis源码最佳学习路径是,先抓主流程、在深入映射细节、最后在回到主流程的扩展上来,始终都要以主流为肪络。
  • 在学习过程中,主流程是重点、映射细节是难点、其中结果集映射是难点中的难点。我们要保证先掌握重点,再去攻克难点。
  • 学习之前一定要先划定目标,否则容易放弃。之所以学了就忘,是因为知识体系不够完整,必须要完整的学习MyBatis。

虽然MyBatis三个框架中源码量最少,但毕竟还是有上千个类、4万多行代码。面对这个体量我们一定要化繁为简,抓住核心。否则很容易陷入无边的逻辑细节当中。
最后祝大家,早日能拿下MyBatis去洞房,生出一个叫“知识”的娃儿来。
MyBatis源码阅读指南_第8张图片

长按识别二维码,有缘再叙

你可能感兴趣的:(笔记,mybatis,设计模式,java)