MyBatis源码深度复盘(二):初始化全过程源码解析(配置加载+Configuration容器)
2026/6/5 14:33:39 网站建设 项目流程

专栏系列:MyBatis源码深度复盘全套教程

上一篇我们搭建了MyBatis源码全局认知,理清了整体架构、核心组件和SQL执行总链路。

从本篇开始,正式进入源码硬核拆解阶段

很多同学只知道 MyBatis 运行时执行 SQL,却不知道:MyBatis 在项目启动阶段,就已经完成了 80% 的工作

我们日常写的mybatis-config.xml、Mapper映射文件、SQL语句、参数映射、返回值映射,全部在启动时被解析、加载、封装到 Configuration 容器中

本篇带你逐行断点调试MyBatis初始化全过程,彻底搞懂:

  • SqlSessionFactory 是如何构建的?

  • 全局配置文件、Mapper文件如何被解析?

  • Configuration 全局容器到底存了什么?

  • MappedStatement 如何实现一条SQL对应一个对象?

  • 面试高频:为什么 Mapper 接口不需要实现类?


一、MyBatis初始化核心概述

1.1 初始化核心入口

MyBatis 所有初始化操作,全部始于:SqlSessionFactoryBuilder.build()

核心流程一句话总结:

读取配置文件 → 解析配置 → 构建 Configuration 容器 → 创建 SqlSessionFactory 工厂

后续所有数据库操作,都由 SqlSessionFactory 生产 SqlSession 来完成。

1.2 初始化阶段做了哪些事?

  • 解析全局核心配置(环境、数据源、settings、插件、别名)

  • 解析所有 Mapper 映射文件(SQL语句、参数、返回值)

  • 将每一条 SQL 封装为MappedStatement对象

  • 将所有配置信息存入全局唯一 Configuration 容器

  • 构建 SqlSessionFactory,完成初始化


二、初始化完整执行链路(前置总览)

在深入源码前,先记住完整调用链路,后续所有源码都围绕这条链路展开:

  1. SqlSessionFactoryBuilder.build():初始化总入口

  2. XMLConfigBuilder.parse():开始解析全局配置文件

  3. parseConfiguration():逐一解析标签(settings、environments、mappers、plugins)

  4. mapperElement():解析 Mapper 文件路径,加载映射文件

  5. XMLMapperBuilder.parse():解析单份 Mapper 文件

  6. buildStatementFromContext():解析 select/insert/update/delete 标签

  7. XMLStatementBuilder.parseStatementNode():封装 SQL 为 MappedStatement

  8. Configuration.addMappedStatement():存入全局容器

  9. 返回 SqlSessionFactory:初始化完成


三、源码逐行拆解:初始化核心流程

3.1 初始化入口:SqlSessionFactoryBuilder.build()

我们原生 MyBatis 使用的第一步代码,就是初始化工厂:

// 读取全局配置文件 InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml"); // 构建SqlSessionFactory SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);

进入build()方法核心源码:

该方法核心逻辑:创建 XML 配置解析器、调用 parse 方法解析配置、返回工厂对象

public SqlSessionFactory build(InputStream inputStream) { // 创建XML配置解析器 XMLConfigBuilder parser = new XMLConfigBuilder(inputStream); // 解析配置并构建SqlSessionFactory return build(parser.parse()); }

3.2 核心:XMLConfigBuilder.parse() 解析全局配置

parse()是初始化的核心转折点,负责解析整个 mybatis-config.xml,最终返回Configuration对象。

public Configuration parse() { // 防止重复解析 if (parsed) { throw new BuilderException("Each XMLConfigBuilder can only be used once."); } parsed = true; // 从根节点configuration开始解析 parseConfiguration(parser.evalNode("/configuration")); return configuration; }

3.3 关键方法:parseConfiguration() 解析所有全局标签

这是 MyBatis 初始化最核心的方法之一,所有全局配置全部在这里解析,对应我们配置文件中的所有标签。

private void parseConfiguration(XNode root) { try { // 解析properties配置 propertiesElement(root.evalNode("properties")); // 解析settings全局参数 Properties settings = settingsAsProperties(root.evalNode("settings")); loadCustomVfs(settings); loadCustomLogImpl(settings); // 解析别名配置 typeAliasElement(root.evalNode("typeAliases")); // 解析插件配置 pluginElement(root.evalNode("plugins")); // 解析对象工厂 objectFactoryElement(root.evalNode("objectFactory")); objectWrapperFactoryElement(root.evalNode("objectWrapperFactory")); reflectorFactoryElement(root.evalNode("reflectorFactory")); settingsElement(settings); // 解析环境配置(数据源、事务) environmentsElement(root.evalNode("environments")); // 解析数据库厂商标识 databaseIdProviderElement(root.evalNode("databaseIdProvider")); // 解析类型处理器 typeHandlerElement(root.evalNode("typeHandlers")); // 【重中之重】解析所有Mapper映射文件 mapperElement(root.evalNode("mappers")); } catch (Exception e) { throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e); } }

这里对应我们开发中的所有配置,重点记住两个核心:

  • settingsElement:加载全局运行参数(缓存、日志、驼峰命名、超时时间等)

  • mapperElement:加载所有 Mapper 映射文件,SQL 全部在这里解析


四、核心重点:Mapper映射文件解析流程

mapperElement()是整个初始化阶段最重要的环节,我们所有写的 SQL、接口映射,全部在这里完成注册。

4.1 mapperElement 加载 Mapper 文件

支持四种 Mapper 加载方式:

  • resource:加载 classpath 下的 Mapper.xml

  • url:加载磁盘绝对路径文件

  • class:绑定 Mapper 接口(注解方式)

  • package:批量扫描包下所有 Mapper 接口

4.2 XMLMapperBuilder 解析单份Mapper文件

每一个 Mapper.xml 文件,都会被XMLMapperBuilder单独解析,核心步骤:

  1. 解析 mapper 根节点的 namespace(绑定对应 Mapper 接口)

  2. 解析 select / insert / update / delete 标签

  3. 解析 sql、resultMap、parameterMap 等配置

  4. 将每一条 SQL 封装为 MappedStatement

4.3 核心:MappedStatement 构建过程

所有 SQL 语句,最终都会被解析为MappedStatement对象,这是 MyBatis 的SQL存储核心

MappedStatement 包含所有SQL信息:

  • SQL 原始语句

  • SQL 命令类型(SELECT/INSERT/UPDATE/DELETE)

  • 入参类型、出参类型

  • 缓存配置、超时配置、分页配置

  • 对应的 Mapper 方法全限定名(唯一标识)

解析完成后,会调用configuration.addMappedStatement(ms),将所有 SQL 配置存入全局容器。


五、Configuration全局容器核心详解

5.1 Configuration是什么?

Configuration 是 MyBatis 全局唯一的配置容器,整个项目生命周期中只有一个实例,所有配置、SQL、映射关系全部存在这里。

可以简单理解为:MyBatis的大仓库

5.2 Configuration核心存储内容

  • MappedStatement集合:存储所有SQL语句(核心)

  • Mapper接口注册器:存储所有Mapper接口与代理工厂映射

  • 插件链:存储所有自定义拦截器

  • 类型处理器:所有数据库类型与Java类型映射

  • 全局运行参数:驼峰、缓存、日志、超时等配置

  • 环境与数据源信息:事务管理器、数据源对象

5.3 核心设计特点

  • 全局单例:一个SqlSessionFactory对应一个Configuration

  • 启动一次性加载,运行时只读,保证高性能

  • 所有后续SQL执行,都是从Configuration中取配置、取SQL


六、经典面试题终极解答(本篇核心)

Q1:MyBatis初始化过程中做了哪些核心工作?

MyBatis初始化核心就是配置解析 + 容器初始化

通过SqlSessionFactoryBuilder构建工厂,XMLConfigBuilder解析全局配置文件,依次加载环境、插件、别名、类型处理器等全局配置;随后扫描并解析所有Mapper映射文件,将每一条CRUD SQL封装为MappedStatement对象,注册到全局唯一的Configuration容器中,最终生成SqlSessionFactory工厂,完成初始化。

Q2:MappedStatement的作用是什么?什么时候加载?

MappedStatement是单条SQL的封装对象,存储SQL语句、参数类型、返回值类型、执行配置等所有信息;在项目启动初始化阶段加载,运行时直接读取使用,无需重复解析SQL,大幅提升执行效率。

Q3:为什么Mapper接口不需要实现类就能执行SQL?

核心原因:启动时已完成SQL与接口方法的绑定

MyBatis初始化时,通过Mapper文件的namespace绑定Mapper接口,将接口方法与对应的MappedStatement(SQL)一一映射绑定。运行时通过动态代理拦截接口方法,根据方法全限定名匹配对应的MappedStatement,直接执行预设SQL,无需开发者手动编写实现类。

Q4:Configuration容器的特点?

全局唯一、启动一次性加载、运行时只读;存储MyBatis全部配置信息、SQL映射信息、插件、类型处理器等核心资源,是MyBatis运行的核心数据支撑。


七、本篇核心总结

1. MyBatis初始化总入口为SqlSessionFactoryBuilder.build(),核心产出是 SqlSessionFactory 和 Configuration 全局容器。

2. 初始化两大核心:全局配置解析+Mapper SQL映射解析

3. 每一条SQL在启动时都会被封装为MappedStatement,存入Configuration,运行时直接复用。

4. Mapper接口无实现类的本质:启动绑定方法与SQL,运行动态代理执行


下篇预告

下一篇我们深入Mapper动态代理源码,彻底搞懂:

✅ getMapper() 如何生成代理对象?

✅ MapperProxy 拦截原理?

✅ JDK动态代理在MyBatis中的落地细节?

持续更新MyBatis源码全套教程,点赞收藏不迷路!

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询