:初始化全过程源码解析(配置加载+Configuration容器))
✨专栏系列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完成初始化二、初始化完整执行链路前置总览在深入源码前先记住完整调用链路后续所有源码都围绕这条链路展开SqlSessionFactoryBuilder.build()初始化总入口XMLConfigBuilder.parse()开始解析全局配置文件parseConfiguration()逐一解析标签settings、environments、mappers、pluginsmapperElement()解析 Mapper 文件路径加载映射文件XMLMapperBuilder.parse()解析单份 Mapper 文件buildStatementFromContext()解析 select/insert/update/delete 标签XMLStatementBuilder.parseStatementNode()封装 SQL 为 MappedStatementConfiguration.addMappedStatement()存入全局容器返回 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.xmlurl加载磁盘绝对路径文件class绑定 Mapper 接口注解方式package批量扫描包下所有 Mapper 接口4.2 XMLMapperBuilder 解析单份Mapper文件每一个 Mapper.xml 文件都会被XMLMapperBuilder单独解析核心步骤解析 mapper 根节点的 namespace绑定对应 Mapper 接口解析 select / insert / update / delete 标签解析 sql、resultMap、parameterMap 等配置将每一条 SQL 封装为 MappedStatement4.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六、经典面试题终极解答本篇核心Q1MyBatis初始化过程中做了哪些核心工作MyBatis初始化核心就是配置解析 容器初始化通过SqlSessionFactoryBuilder构建工厂XMLConfigBuilder解析全局配置文件依次加载环境、插件、别名、类型处理器等全局配置随后扫描并解析所有Mapper映射文件将每一条CRUD SQL封装为MappedStatement对象注册到全局唯一的Configuration容器中最终生成SqlSessionFactory工厂完成初始化。Q2MappedStatement的作用是什么什么时候加载MappedStatement是单条SQL的封装对象存储SQL语句、参数类型、返回值类型、执行配置等所有信息在项目启动初始化阶段加载运行时直接读取使用无需重复解析SQL大幅提升执行效率。Q3为什么Mapper接口不需要实现类就能执行SQL核心原因启动时已完成SQL与接口方法的绑定。MyBatis初始化时通过Mapper文件的namespace绑定Mapper接口将接口方法与对应的MappedStatementSQL一一映射绑定。运行时通过动态代理拦截接口方法根据方法全限定名匹配对应的MappedStatement直接执行预设SQL无需开发者手动编写实现类。Q4Configuration容器的特点全局唯一、启动一次性加载、运行时只读存储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源码全套教程点赞收藏不迷路