共计 4485 个字符,预计需要花费 12 分钟才能阅读完成。
前言
在原始 Mybatis
的应用中,应用 Mybatis
时会先读取配置文件 mybatis-config.xml
为字符流或者字节流,而后通过 SqlSessionFactoryBuilder
基于配置文件的字符流或字节流来构建 SqlSessionFactory
。本节将联合Mybatis
源码,对读取配置文件 mybatis-config.xml
和构建 SqlSessionFactory
的原理进行学习。
注释
原始 Mybatis
读取配置文件 mybatis-config.xml
和构建 SqlSessionFactory
的一个示例如下。
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
上述示例中的 Resources
工具类提供了办法能够读取 classpath 下指定名字的文件为字符流或者字节流,这里是应用了其提供的 getResourceAsStream()
办法将 mybatis-config.xml
文件读取为字节流。SqlSessionFactoryBuilder
是一个建造者,其提供了共计 9 个重载的 build()
办法用于构建 SqlSessionFactory
,这 9 个build()
办法能够分为三类,概括如下。
- 基于配置文件字符流构建
SqlSessionFactory
; - 基于配置文件字节流构建
SqlSessionFactory
; - 基于
Configuration
类构建SqlSessionFactory
。
实际上,基于配置文件字符流和基于配置文件字节流构建的形式,最终都是将字符流或字节流解析并生成 Configuration
类,而后基于 Configuration
类构建SqlSessionFactory
。
上面以基于配置文件字节流构建 SqlSessionFactory
的过程为例,对整个读配置文件的流程进行阐明。下面的示例中调用的 build()
办法如下所示。
public SqlSessionFactory build(InputStream inputStream) {return build(inputStream, null, null);
}
下面被调用的重载的 build()
办法如下所示。
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
//XMLConfigBuilder 会解析配置文件并生成 Configuration 类
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
// 调用入参为 Configuration 的 build()办法构建 SqlSessionFactory 并返回
return build(parser.parse());
} catch (Exception e) {throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {ErrorContext.instance().reset();
try {inputStream.close();
} catch (IOException e) {}}
}
能够发现,配置文件的解析是产生在 XMLConfigBuilder
的parse()
办法中,在查看 parse()
办法前,先看一下 XMLConfigBuilder
的类图,如下所示。
通过 XMLConfigBuilder
的类图能够晓得,XMLConfigBuilder
解析配置文件是依附 XPathParser
,而XPathParser
是Mybatis
提供的基于 JAVA XPath
的解析器。同时,XMLConfigBuilder
外部保护了一个 Configuration
,通过XPathParser
解析配置文件失去的配置属性均会丰盛到 Configuration
中。
当初开始剖析 XMLConfigBuilder
的parse()
办法,其实现如下所示。
public Configuration parse() {if (parsed) {throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
要了解 parse()
办法,最好是和一个理论的配置文件进行对照,如下给出一个理论的配置文件。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="useGeneratedKeys" value="true"/>
</settings>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test?characterEncoding=utf-8&serverTimezone=UTC&useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<package name="com.mybatis.learn.dao"/>
</mappers>
</configuration>
所以在 parse()
办法中,首先是获取配置文件的 configuration 节点(根节点),而后将 configuration 节点传入 parseConfiguration()
办法,接着在 parseConfiguration()
办法中会依据传入的 configuration 节点顺次获取子节点并读取子节点属性,最初将获取到的属性丰盛进 Configuration
。parseConfiguration()
办法实现如下所示。
private void parseConfiguration(XNode root) {
try {propertiesElement(root.evalNode("properties"));
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
loadCustomLogImpl(settings);
typeAliasesElement(root.evalNode("typeAliases"));
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
reflectorFactoryElement(root.evalNode("reflectorFactory"));
settingsElement(settings);
// 丰盛 environments 标签及其子标签的属性到 Configuration 中
environmentsElement(root.evalNode("environments"));
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
typeHandlerElement(root.evalNode("typeHandlers"));
// 丰盛 mappers 标签的属性到 Configuration 中
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {throw new BuilderException("Error parsing SQL Mapper Configuration. Cause:" + e, e);
}
}
最初 parse()
办法会返回 Configuration
,SqlSessionFactoryBuilder
会基于 Configuration
创立 DefaultSqlSessionFactory
并返回,如下所示。
public SqlSessionFactory build(Configuration config) {return new DefaultSqlSessionFactory(config);
}
DefaultSqlSessionFactory
类图如下所示。
至此,读取配置文件 mybatis-config.xml
和构建 SqlSessionFactory
的基本原理曾经介绍结束。
总结
本篇文章是对 Mybatis
读取配置文件并构建 SqlSessionFactory
的一个整体流程进行了介绍,即通过 Resources
工具类获取配置文件输出字符流或字节流,而后通过 SqlSessionFactoryBuilder
创立 DefaultSqlSessionFactory
,在SqlSessionFactoryBuilder
中是通过 XMLConfigBuilder
来实现配置文件属性的读取并丰盛进 Configuration
,SqlSessionFactoryBuilder
也是基于 XMLConfigBuilder
返回的 Configuration
创立的 DefaultSqlSessionFactory
。实际上,对于Mybatis
配置文件的读取,最要害的局部在于如何注册 映射文件 / 映射接口,该局部内容,会在前面的文章中进行学习。