MyBatis的工作流程及源码连贯阅读方式
MyBatis 的工作流程可概括为以下核心步骤加载配置读取全局配置文件mybatis-config.xml解析数据源、事务管理器、映射文件mapper.xml或注解配置。创建 SqlSessionFactory使用配置信息构建SqlSessionFactory对象通常通过SqlSessionFactoryBuilder该对象是应用全局单例。获取 SqlSession从SqlSessionFactory中打开一个SqlSession代表一次数据库会话提供执行 SQL 的方法。获取 Mapper 代理对象通过SqlSession.getMapper(Class)为映射器接口生成动态代理对象代理内部调用SqlSession的 SQL 执行方法。执行 SQL调用 Mapper 接口中的方法代理底层会根据方法签名和参数通过SqlSession找到对应 SQL 语句依据命名空间和 ID并设置参数如#{param}占位符后交给 JDBC 执行。结果映射JDBC 返回结果集后MyBatis 自动将结果集映射为 Java 对象支持简单类型、Map、POJO 等并返回给调用方。事务控制与资源关闭业务代码中可显式提交/回滚事务最后关闭SqlSession释放数据库连接。核心思想将 SQL 与 Java 代码解耦通过动态代理和配置映射简化 JDBC 操作。连贯的源码阅读总体思路从 API 调用入手逐层跟进去阅读框架源码最好的方式是从一个最简单的可运行的 API 调用示例入手在 IDE 中开启 Debug 模式逐层跟进去。结合Mybatis3.5.x版本源码以这段经典代码为起点Stringresourcemybatis-config.xml;InputStreaminputStreamResources.getResourceAsStream(resource);// ① 构建 SqlSessionFactorySqlSessionFactorysqlSessionFactorynewSqlSessionFactoryBuilder().build(inputStream);// ② 打开 SqlSessiontry(SqlSessionsessionsqlSessionFactory.openSession()){// ③ 获取 Mapper 代理对象BusinessMappermappersession.getMapper(BusinessMapper.class);// ④ 执行 SQL 查询从这里开始 Debug 进入⭐Businessbusinessmapper.selectBusinessById(1);System.out.println(business);}调试入口点在mapper.selectBusinessById(1)这一行打上断点然后 Debug 运行IDE 会进入到 MapperProxy 等核心类中。三大阶段完整调用链路MyBatis 的源码执行路径可以分成三个连贯的大阶段各个阶段各自有清晰的入口和调用链。第一阶段启动与初始化 —— 入口SqlSessionFactoryBuilder.build()这是整个框架的建房子阶段把配置文件变成内存中的配置模型。入口类SqlSessionFactoryBuilder它使用了建造者模式有 9 个重载的build()方法用以不同的方式创建工厂对象。核心调用链追踪路线按顺序打断点即可SqlSessionFactoryBuilder.build(InputStream)这是用户代码中调用的第一个方法创建 XMLConfigBuilder 对象。XMLConfigBuilder.parse()先检查是否已被解析过然后调用parseConfiguration()方法。XMLConfigBuilder.parseConfiguration(XNode)重点关注 这里按照 MyBatis 全局配置文件的节点顺序逐一解析每个标签properties→settings→typeAliases→plugins→environments→mappers等。每解析一个标签就把解析结果存入Configuration对象中。XMLMapperBuilder.parse()当遇到mappers标签时会进入到具体的 Mapper 映射文件解析每个 Mapper XML 被解析成一条MappedStatement对象包含 SQL 语句、参数映射、结果映射等信息存入Configuration.mappedStatements集合中。SqlSessionFactoryBuilder.build(Configuration)最后用解析好的Configuration对象创建DefaultSqlSessionFactory并返回。第一阶段的目标很明确Configuration对象是这个阶段的核心产物其中包含了 MyBatis 运行所需的全部元数据信息。可以在XMLConfigBuilder.parseConfiguration()的不同方法中打断点看看各个标签是如何被一步步解析并填充到Configuration对象中的。第二阶段获取代理对象和执行入口 —— 入口DefaultSqlSession.getMapper()这一阶段是建立数据库操作指挥部当调用sqlSession.getMapper()时它为背后的 Mapper 接口凭空变出一个可以执行 SQL 的实现类。入口类DefaultSqlSession.getMapper(ClassT type)调用链连贯地跟进去DefaultSqlSession.getMapper()直接委托给configuration.getMapper(type, this)。Configuration.getMapper()内部调用mapperRegistry.getMapper(type, sqlSession)。MapperRegistry.getMapper()核心 JDK 动态代理的创建点先从knownMappers集合中根据接口类型找到对应的MapperProxyFactory。然后调用mapperProxyFactory.newInstance(sqlSession)创建代理对象。newInstance()方法内部return (T) Proxy.newProxyInstance(... , new MapperProxy())。MapperProxy类的构造与结构MapperProxy是 JDK 动态代理的InvocationHandler实现类。当代理对象的方法被调用时最终会执行MapperProxy.invoke()。在这里建议关注的点看看MapperRegistry.knownMappers是什么时候被填充的——这正是在第一阶段解析 Mapper 映射关系时完成的。第三阶段SQL 执行与结果映射—— 真正的数据库操作链路这是 MyBatis 源码中最长也最精彩的一条链路。当调用mapper.selectBusinessById(1)时IDE 进入了MapperProxy.invoke()。执行链完整顺序按顺序打断点跟进去步骤核心类/方法职责1. 动态代理拦截MapperProxy.invoke()拦截 Mapper 接口的方法调用2. 方法包装与路由MapperMethod.execute()根据 SQL 类型SELECT/INSERT/UPDATE/DELETE决定执行路径3. SqlSession 入口DefaultSqlSession.selectOne()委托给 Executor 执行4.缓存处理CachingExecutor.query()检查二级缓存跨 SqlSession 级别5.一级缓存BaseExecutor.query()检查一级缓存会话级别若未命中则调用子类的doQuery()6. 真正的查询逻辑SimpleExecutor.doQuery()创建 StatementHandler准备 JDBC 执行环境7.创建 StatementHandlerConfiguration.newStatementHandler()最终返回RoutingStatementHandler它内部包装了真正的PreparedStatementHandler8.参数绑定PreparedStatementHandler.parameterize()内部调用DefaultParameterHandler.setParameters()循环为PreparedStatement的?占位符赋值9. 执行 SQLPreparedStatementHandler.query()调用PreparedStatement.execute()获得ResultSet10.结果映射DefaultResultSetHandler.handleResultSets()将 JDBCResultSet转换为 Java 对象或集合返回11. 资源回收DefaultSqlSession.close()关闭数据库连接释放资源串联起来完整调用链可以概括为一句话SqlSession → MapperProxy → MappedStatement → Executor → StatementHandler → ParameterHandler → JDBC 执行 → ResultSetHandler → 返回结果。总结快速定位的关键点功能起点类核心方法配置加载XMLConfigBuilderparseConfiguration()代理生成MapperProxyFactorynewInstance()方法拦截MapperProxyinvoke()二级/一级缓存CachingExecutor/BaseExecutorquery()SQL 参数绑定DefaultParameterHandlersetParameters()JDBC 执行与结果映射PreparedStatementHandler/DefaultResultSetHandlerquery()→handleResultSets()通过这种方式不需要一步一个脚印地找断点而是跟着代码执行的顺序自然地走进 MyBatis 的每一个核心环节。