MyBatis源码学习

非常棒的学习规划!这清晰地勾勒出了MyBatis源码学习的核心脉络和进阶路径。你的分解逻辑性很强,从主干到分支,从核心到扩展,非常适合系统性学习。

下面,我对你的三个目标进行一些补充和结构化,希望能让你的学习过程更顺畅。

第一目标:SQL执行流程(主干与脉络)

这是理解MyBatis如何工作的"生命线"。务必做到能画图、能口述。

  1. 宏观流程(简化版)
    SqlSession -> Executor -> StatementHandler -> ParameterHandler -> JDBC Statement -> ResultSetHandler -> 返回结果。

  2. 四大组件深度解析

    • 执行器 Executor
      • 作用 :调度中心,控制一级缓存、事务、延迟加载等,并最终将请求委派给 StatementHandler
      • 三个关键实现
        • SimpleExecutor :默认。每次执行都创建新的 Statement,用完关闭。
        • ReuseExecutor :重用预处理 Statement 对象。基于SQL字符串作为键进行缓存。
        • BatchExecutor :用于批处理,将多个更新操作的 Statement 缓存起来,最后统一执行。
      • 设计模式 :模板方法模式(BaseExecutor 定义了骨架,子类实现具体步骤)。
    • SQL处理器 StatementHandler
      • 作用 :与JDBC Statement 交互的直接负责人,负责创建 Statement、参数设置、执行SQL。
      • 三个关键实现(与 Executor 类似,但关注点不同)
        • SimpleStatementHandler :处理普通的 Statement
        • PreparedStatementHandler :处理 PreparedStatement最常用,防SQL注入)。
        • CallableStatementHandler :处理 CallableStatement(存储过程)。
      • 为什么分开Executor 关注执行策略(缓存、批处理),StatementHandler 关注与JDBC API的具体交互方式。
    • 参数处理器 ParameterHandler
      • 作用 :将用户传入的Java参数,按照 ParameterMapping 规则,设置到 PreparedStatement 中。
      • 核心逻辑 :类型处理(TypeHandler)的用武之地。
    • 结果集处理器 ResultSetHandler
      • 作用 :将 ResultSet 结果集,根据 ResultMap 规则,映射成Java对象列表。
      • 这是最复杂的一块,但第一阶段先理解其接口位置和作用即可。

学习建议:动手调试一个最简单的查询方法,跟着调试器一步步走完这个流程,画出时序图。


第二目标:映射配置(血肉与难点)

这是MyBatis强大灵活性的来源,也是最复杂的地方。

  1. MappedStatement

    • 定位 :它是核心配置的承载者 。一个 <select|insert|update|delete> 标签或一个 @Select 注解的最终形态。
    • 与三大映射的关系 :它内部包含了 SqlSource(动态SQL)、ParameterMap(历史遗留,现多用 ParameterHandler 中的 TypeHandler)、ResultMap(结果映射)。可以把它看作一个执行命令的所有蓝图
  2. 动态SQL (SqlSource)

    • 解析过程 :XML/注解中的SQL文本 -> XMLScriptBuilder 解析 -> 形成包含 SqlNode(如 IfNode, TrimNode)的抽象语法树 -> 动态拼接。
    • SqlSource 主要实现
      • DynamicSqlSource :包含动态标签(<if>, <where>等),执行时根据参数动态生成SQL。
      • RawSqlSource:静态SQL,在启动时即可确定SQL字符串,性能稍好。
      • ProviderSqlSource :用于注解中使用 @InsertProvider 等场景。
    • 映射工具包 ognl :MyBatis早期使用OGNL表达式语言来解析 #{}, ${} 中的表达式,获取参数值。
  3. 参数映射

    • 过程 :Java方法参数 -> 转换为 ParamMap(处理 @Param 和多参数) -> 通过 TypeHandler 为每个 ParameterMapping 设置值。
    • 关键点 :理解 ParameterMapping 的组成(属性名、Java类型、JDBC类型、TypeHandler)。
  4. 结果集映射 (ResultMap) - 最难部分

    • 核心逻辑ResultSetWrapper 包装结果集元数据,ResultMap 描述映射规则,通过 ResultHandler 进行组装。
    • 关联映射(<association>, <collection>
      • 嵌套查询 (Nested Select):触发子查询,可能引起N+1问题。
      • 嵌套结果 (Nested Results):通过多表联查一次性查出,在内存中通过结果集处理器进行对象组装。
    • 循环依赖:MyBatis通过"提前暴露对象"的方式解决。例如,A中有B属性,B中有A属性,在创建A的早期就将半成品A放入缓存,供B创建时引用,最后再完善A。
    • 延迟加载:基于动态代理(Javassist或CGLIB),在访问关联属性时才触发查询。
    • 自动映射 :当 ResultMap 不完整或未配置时,按照列名-属性名的规则(开启autoMapping时)进行映射。
  5. 配置中心 Configuration

    • 定位 :MyBatis的单例工厂和配置仓库 。几乎所有组件(MappedStatement, ResultMap, Executor 等)都从这里创建和获取。
    • 加载解析XMLConfigBuilder 解析 mybatis-config.xmlXMLMapperBuilder 解析 Mapper.xml,最终将所有信息注册到 Configuration 的各个Map容器中。

学习建议 :分而治之。先攻克 SqlSource,再研究简单的 ResultMap(无关联),最后集中火力攻击关联映射、延迟加载和循环依赖。多写测试用例,观察不同配置下生成的SQL和执行过程。


第三目标:扩展支撑(皮肤与生态)

让MyBatis更好用、更强大的外围系统。

  1. 会话 SqlSession

    • 设计模式门面模式 。对外提供简洁的API(如 selectOne),对内隐藏了 Executor 等复杂组件的交互细节。
    • 意义 :是用户与MyBatis交互的主要入口
  2. Mapper接口动态代理

    • 核心MapperRegistry 负责管理接口与代理工厂 MapperProxyFactory
    • 流程 :调用 Mapper 接口方法 -> 被 MapperProxyInvocationHandler)拦截 -> 将方法名和参数转换为 MappedStatement 的ID -> 交给 SqlSession 执行。
    • MapperMethod:这是转换的关键类,它封装了SQL命令的类型(增删改查)和执行逻辑。
  3. 缓存

    • 一级缓存 :在 BaseExecutor 中,基于 PerpetualCache 实现,作用域为 SqlSession (默认开启)。
      • 失效场景 :更新操作、手动清空、配置刷新、不同的 SqlSession
    • 二级缓存 :在 CachingExecutor(装饰器模式)中实现,作用域为 Mapper 级别 (需手动开启)。
      • 结构TransactionalCacheManager 管理事务性的缓存提交。它是一个责任链,最终的存储也是 PerpetualCache,但可以被 RedisCache 等第三方缓存装饰。
    • 执行顺序:二级缓存 -> 一级缓存 -> 数据库。
  4. 插件机制

    • 底层原理动态代理 + 责任链模式(InterceptorChain
    • 可拦截的四大组件Executor, StatementHandler, ParameterHandler, ResultSetHandler
    • 关键对象Interceptor(用户实现)、Plugin(包装类,利用 InvocationHandler 生成代理对象)、@Signature 注解(指定拦截点)。
  5. 懒加载

    • 实现 :是结果集映射 的一个特性。当配置 fetchType="lazy" 时,关联对象会被替换成一个由 JavassistCGLIB 生成的代理对象。
    • 触发 :当调用代理对象的 getter 方法时,代理对象会调用 ResultLoader 去执行延迟的SQL查询。

学习建议 :这部分相对有趣。可以尝试自己写一个简单的插件(如打印SQL执行时间),理解代理链的生成过程。深入研究 CachingExecutor 如何装饰普通的 Executor,理解装饰器模式的应用。

总结与学习路线图

你的规划已经非常完美。我再提供一个建议的学习顺序:

  1. 第一阶段(攻克主干)

    • SqlSession.selectOne() 开始调试。
    • 理清 Executor -> StatementHandler -> ParameterHandler -> ResultSetHandler 的调用链。
    • 理解 ConfigurationMappedStatement 如何为这条链提供"蓝图"。
  2. 第二阶段(深入映射)

    • 先搞懂静态SQL (RawSqlSource) 如何工作。
    • 再研究动态SQL (DynamicSqlSource) 的解析和拼接。
    • 重点攻坚:结果集映射。从简单映射到自动映射,再到关联映射,最后研究延迟加载和循环依赖。
  3. 第三阶段(掌握扩展)

    • 理解 SqlSessionMapper 接口如何简化使用(门面+动态代理)。
    • 研究缓存机制(一二级缓存的实现与区别)。
    • 动手编写插件,理解拦截原理。
    • 最后通读懒加载的实现,它融合了动态代理和结果集映射。

记住,带着问题看源码 (比如"<if>标签是怎么实现的?"、"@Param注解是怎么生效的?"),并善用IDE的调试功能,你的学习效率会非常高。

你这份学习计划已经超越了绝大多数人,坚持下去,你对MyBatis的理解将达到架构师级别。祝你学习顺利!

相关推荐
西岸行者4 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意4 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码4 天前
嵌入式学习路线
学习
毛小茛4 天前
计算机系统概论——校验码
学习
babe小鑫4 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms4 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下4 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。4 天前
2026.2.25监控学习
学习
im_AMBER4 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J4 天前
从“Hello World“ 开始 C++
c语言·c++·学习