回顾
前面已经将基础支持层看完了,各种底层模块的功能
- 类型转换
- 参数解析器
- 数据库连接池
- 事务
- 缓存
核心处理层
下面开始学习核心处理层
首先,核心处理层包括6个部分
- 配置解析
- 参数映射
- SQL解析
- SQL执行
- 结果集映射
- 插件
MyBatis初始化
首先先看第一个部分,配置解析,MyBatis跟Spring一样,MyBatis也有配置文件,因此也需要去解析配置文件,而在MyBatis中的配置文件主要有两个,分别是mybatis-config.xml和映射配置文件
建造者模式
建造者模式是用来将一类复杂对象的构建过程与它的表示分离,让相同的建造工程可以有不同的表示,比如A产品和B产品的建造流程是一样的,那么A产品和B产品就可以使用同一套建造流程!这时候就是使用相同的构建过程,但表示的产品不一致了
首先建造者模式需要三个对象
- 建造者(接口):负责使用特定建造顺序去建造产品!
- 导演:调用具体的建造者去创建产品,为建造者提供数据来源!
- 产品
建造者模式的优点
- 使用导演来构建出具体的产品,但构建的细节在建造者,所以导演根本不知道创建产品的具体细节,只负责构建所需的信息传递,实现了产品对象的上层代码和产品对象的解耦,最上层的指挥完全不知道产品的建造流程,我们不需要改动指挥的代码!!!
- 建造者模式将复杂的产品的创建过程分散到了不同的构造步骤中,这样可以对产品创建过程实现更加精细的控制,同时让创建过程更加清晰,建造者将复杂产品的创建过程分开多个方法来创建,并且使用一个build方法来规定了先执行哪个方法,说白了就是先创建哪个部位
- 每个具体的构造者有产品的每个部位的创建方法,因此一个具体的构建者是可以单独创建出完整的产品对象的,而具体的建造者之间是独立的,因此当我们新增产品时,去新添加建造者即可!然后指挥调用新的建造者来build即可!
构造者模式的缺点
- 创建的产品要有共同点,组成部分相似,并且创建的流程要基本一致,如果产品很多、产品内部变化复杂、产品之间的差异性很大,是不适合使用建造者模式的,因为产品很多且内部变化复杂会导致建造者越来越多,而产品之间的差异性很大,也会导致建造者越来越多。。。。。。
初始化!BaseBuilder!
在MyBatis中,初始化过程就采用了建造者模式,说白了创建SqlSessionFactory的时候采用了建造者模式,具体的产品是SqlSessionFactory,指挥者是SqlSessionFactoryBuilder,那谁是建造者呢?看代码!
指挥者SqlSessionFactoryBuilder会调用build方法来调用建造者来进行创建SqlSessionFactory(产品),源码如下
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
//建造者就是XMLConfigBuilder
//而且注意,这里建造者建造的并不是直接的SqlSessionFactory
//创建出需要的建造者
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
//build方法就是指挥者去调用建造者去创建产品了!
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
可以看到,对于SqlSessionFactory这个产品的建造者就是XMLConfigBuilder对象,可能因为这个产品只有一款,所以这里没有使用接口
下面就来看一下MyBatis的建造者系列(XmlConfigBuilder是继承了BaseBuilder的,因此从BaseBuilder开始看起)

BaseBuilder其实就扮演着建造者接口的角,虽然其是一个抽象类,所有的具体建造者都是在其基础上建立的
三个关键成员属性
- configuration:存储MyBatis的所有配置信息的
- typeAliasRegistry:之前我们也看过了,这是类型别名注册中心(对Java类型取别名,比如java.lang.Integer转化为int)
- typeHandlerRegistry:类型转换器注册中心(TypeHandler,用来将数据库类型转化为Java类型的)
而且从构造方法上可以看到,typeAliasRegistry和typeHandlerRegistry都是从Configuration来的,也就是从配置文件上来的!!!

现在BaseBuilder先看到这
XMLConfigBuilder
回到我们的XMLConfigBuilder,SqlSessionFactoryBuilder就是指挥XMLConfigBuilder来进行,先来看一下XMLConfigBuilder的结构

关键的属性
- parsed:代表是否已经解析过mybatis-config.xml配置文件了(用改标志来让配置文件只被解析一次!!!)
- XPathParser:用来解析mybatis-config.xml配置文件的XPathParser对象,前面已经看过了,其底层是解析DOM树的
- environment:environment标签的default属性
- ReflectorFactory:负责创建和缓存Reflector对象的,Reflector就是用来将行记录映射成Java Bean的

可以看到执行的是build方法,而在build方法之前先会执行构造者的parse方法,下面就来看看这个构造者如何创建产品的
源码如下
public Configuration parse() {
//判断MyBatis文件是否已经解析过了
if (parsed) {
//如果已经解析过,抛错
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
//没有解析过,将标志位改为true,开始解析
parsed = true;
//在mybatis配置文件中找到configuration节点,并开始进行解析
//之前已经分析过XPathParser的evalNode方法了,就是解析该标签节点
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
- 判断是不是已经解析过了,如果解析过了,抛错
- 如果没有解析过,修改标志位,代表现在进行解析
- 使用XPathParser取解析configuration标签节点后,调用parseConfiguration去处理解析结果
parseConfiguration
该方法就是用来正式解析MyBatis总配置文件下有用的信息了,也就是configuration标签节点下的信息

该方法源码如下,可以看到,这就是parseConfiguration方法就是建造者的建造流程了!说得更具体一点是解析配置文件,然后按照建造流程去取配置文件里面的对应节点信息来创建Configuration的流程!!!
private void parseConfiguration(XNode root) {
try {
//解析configuration标签下的properties属性,组装Configuration的properties部分
propertiesElement(root.evalNode("properties"));
//获取configuration标签下的settings属性
Properties settings = settingsAsProperties(root.evalNode("settings"));
//从settings部分去设置vfsImpl字段(虚拟文件系统,之前提到过这个用来查找文件的!!)
loadCustomVfs(settings);
loadCustomLogImpl(settings);
//解析typeAliases标签,并组装Configuration的typeAliases部分
typeAliasesElement(root.evalNode("typeAliases"));
//解析plugins标签,并组装Configuration的plugins部分
pluginElement(root.evalNode("plugins"));
//解析objectFatory标签,并组装Configuration的objectFactory部分
objectFactoryElement(root.evalNode("objectFactory"));
//解析objectWrapperFactory标签,并组装Configuration的objectWrapperFactory部分
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
//解析reflectorFactory标签,并组装Configuration的reflectorFactory部分
reflectorFactoryElement(root.evalNode("reflectorFactory"));
//将上面解析出的settings属性,组装Configuration的setting部分
settingsElement(settings);
//解析environments属性,组装Configuration的environments部分
environmentsElement(root.evalNode("environments"));
//解析databseIdProvider属性,组装Configuration的databaseIdProvider部分
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
//解析typeHandlers属性,组装Configuration的typeHandlers部分
typeHandlerElement(root.evalNode("typeHandlers"));
//解析mappers属性,组装Configuration的mappers部分
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
可以看到,其实XMLConfigBuilder建造的产品其实是Configuration,也就是解析出来的配置文件里面的内容,并且按照一定的顺序来解析配置文件里面的标签,然后进行组装到Configuration中,最后完成创建,也就是说对于Configuration这个产品来说已经被分成几部分来完成创建了,解析组装的顺序如下
- properties标签
- typeAlias标签
- plugins标签
- objectFactory标签
- objectFactoryWrapper标签
- settings标签
- environments标签
- databaseIdProvider标签
- typeHandler标签
- mapper标签
下面就看一下,MyBatis是如何对这几个标签节点进行解析的
解析Properties标签
对应的方法为propertiesElement,源码如下
先说明一下properties标签的作用,该标签的子标签其实就是用来记录一些配置信息的,比如数据库的连接信息,账号密码。。。。。。。
private void propertiesElement(XNode context

本文详细解读MyBatis配置文件解析过程,通过BaseBuilder与XMLConfigBuilder展示如何利用建造者模式逐步初始化SqlSessionFactory,涉及配置文件结构、标签解析和自定义组件的整合。
最低0.47元/天 解锁文章

被折叠的 条评论
为什么被折叠?



