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的理解将达到架构师级别。祝你学习顺利!

相关推荐
im_AMBER2 小时前
Leetcode 84 水果成篮 | 删除子数组的最大得分
数据结构·c++·笔记·学习·算法·leetcode·哈希算法
hssfscv2 小时前
Javaweb学习笔记——Maven
笔记·学习·maven
d111111111d2 小时前
STM32-HAL库学习,初识HAL库
笔记·stm32·单片机·嵌入式硬件·学习
AAA阿giao2 小时前
从树到楼梯:数据结构与算法的奇妙旅程
前端·javascript·数据结构·学习·算法·力扣·
头疼的程序员2 小时前
计算机网络:自顶向下方法(第七版)第一章 学习分享
网络·学习·计算机网络
先生沉默先2 小时前
c#Socket学习,使用Socket创建一个在线聊天,数据模型(2)
服务器·学习·c#
阿拉斯攀登2 小时前
设计模式:责任链模式(mybatis数据权限实现)
设计模式·mybatis·责任链模式
有谁看见我的剑了?2 小时前
ESXI 虚机机硬盘类型和硬盘模式学习
运维·学习·云计算
阿拉斯攀登2 小时前
设计模式:责任链模式(MyBatis)
设计模式·mybatis·责任链模式