MyBatis初始化方式
MyBatis初始化提供了两种方式:
- 基于XML配置文件 :基于XML配置文件的方式是将MyBatis的所有配置信息放在XML文件中
mybatis-config.xml
,MyBatis通过加载并XML配置文件,将配置文信息组装成内部的Configuration对象。 - 基于Java API :基于Java API的方式是手动创建Configuration对象,然后将配置参数set 进入Configuration对象中。
** 任何框架的初始化,应该都是先加载配置信息,接下来我们将使用基于XML配置文件的方式,来深入讨论MyBatis是如何通过配置文件构建Configuration对象。**
基于Xml配置初始化
** XML 配置文件中包含了对 MyBatis 系统的核心设置,包括获取数据库连接实例的数据源(DataSource)以及决定事务作用域和控制方式的事务管理器(TransactionManager)。**
通过一个简单的例子,分析一下基于Xml配置MyBatis是怎样完成初始化的,都做了些什么?
- mybatis-config.xml配置
xml
<?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="lazyLoadingEnabled" value="true"/>
<!-- 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
<!--是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!-- 定义数据库的信息,默认使用development数据库构建环境 -->
<environments default="development">
<environment id="development">
<!-- 使用了 JDBC 的提交和回滚功能,它依赖从数据源获得的连接来管理事务作用域 -->
<transactionManager type="JDBC"/>
<!-- 数据库信息替换为自己的环境 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/work"/>
<property name="username" value="xxxx"/>
<property name="password" value="xxxx"/>
</dataSource>
</environment>
</environments>
<!-- 定义映射器 -->
<mappers>
<mapper class="org.apache.ibatis.example.mapper.ScheduleSettingMapper"/>
</mappers>
</configuration>
MyBatis配置项提供了很多配置项,这个配置文件中只配置了一些基本的节点,只是用来演示。
** 如果有对MyBatis配置项不了解的或者不知道MyBatis提供哪些配置** ,可以去看看MyBatis官网文档,文档上对每一个配置项都已经做出了很详细的说明和示例。
- 程序入口代码
java
String resource = "mybatis-config.xml";
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream(resource);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
SqlSessionFactory sqlSessionFactory = null;
//初始化
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
上述代码的功能是通过Resources工具类 ,调用ClassLoader读取classpath下的mybatis-config.xml 配置文件,得到一个输入流inputStream,SqlSessionFactoryBuilder 根据传入的数据流生成Configuration 对象,然后根据Configuration对象创建默认的SqlSessionFactory实例。
源码分析
前面提到,SqlSessionFactoryBuilder 根据传入的数据流生成Configuration 对象,然后根据Configuration对象创建默认的SqlSessionFactory实例,现在让我们通过源码来一步一步看一看
- 调用SqlSessionFactoryBuilder对象的build(inputStream)方法
java
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSessionFactoryBuilder是SqlSessionFactory的构造器,用于创建SqlSessionFactory,采用了Builder设计模式。
- SqlSessionFactoryBuilder会根据输入流inputStream等创建XMLConfigBuilder对象
java
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
// 创建XMLConfigBuilder对象用来解析XML配置文件生成Document对象,创建Configuration对象
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
// XMLConfigBuilder 对象调用parse()方法,将XML配置文件内的信息解析成Configuration对象
Configuration configuration = parser.parse();
// 根据解析好的Configuration对象,创建DefaultSqlSessionFactory对象
return build(configuration);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
// 可以通过Configuration创建DefaultSqlSessionFactory对象
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
通过new XMLConfigBuilder()创建对象时,会生成Configuration 对象和XPathParser对象
- Configuration对象主要是用来保存xml文件的配置信息
- XPathParser 对象持有解析mybatis-config.xml 文件和Mapper 文件生成Document对象 和解析mybatis-3-config.dtd 文件和mybatis-3-mapper.dtd 转换成XMLMapperEntityResolver对象
java
public XMLConfigBuilder(Class<? extends Configuration> configClass, InputStream inputStream, String environment,
Properties props) {
this(configClass, new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
}
private XMLConfigBuilder(Class<? extends Configuration> configClass, XPathParser parser, String environment,
Properties props) {
// Configuration的初始化
super(newConfig(configClass));
ErrorContext.instance().resource("SQL Mapper Configuration");
// 设置自定义配置
this.configuration.setVariables(props);
// 解析标志
this.parsed = false;
// environment初始化
this.environment = environment;
// 包装配置 InputStream 的 XPathParser
this.parser = parser;
}
- SqlSessionFactoryBuilder调用XMLConfigBuilder对象的parse()方法
java
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
// 通过XPathParser获取<configuration>节点对应的Node对象
XNode xNode = parser.evalNode("/configuration");
// 解析/configuration子节点信息
parseConfiguration(xNode);
return configuration;
}
private void parseConfiguration(XNode root) {
try {
// 解析properties节点
propertiesElement(root.evalNode("properties"));
// 解析settings节点
Properties settings = settingsAsProperties(root.evalNode("settings"));
// 配置自定义虚拟文件系统实现
loadCustomVfsImpl(settings);
// 配置自定义日志实现
loadCustomLogImpl(settings);
// 解析typeAliases节点
typeAliasesElement(root.evalNode("typeAliases"));
// 解析plugins节点
pluginsElement(root.evalNode("plugins"));
// 解析objectFactory节点
objectFactoryElement(root.evalNode("objectFactory"));
// 解析objectWrapperFactory节点
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
// 解析reflectorFactory节点
reflectorFactoryElement(root.evalNode("reflectorFactory"));
settingsElement(settings);
// 解析environments节点
environmentsElement(root.evalNode("environments"));
// 解析databaseIdProvider节点
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
// 解析typeHandlers节点
typeHandlersElement(root.evalNode("typeHandlers"));
// 解析mappers节点
mappersElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
XMLConfigBuilder对象的parse()方法 ,主要是通过XpathParser 根据Xpath表达式获取基本的DOM节点以及子节点Node信息的操作(解析的节点configuration, properties, settings, typeAliases, typeHandlers, objectFactory, objectWrapperFactory, plugins, environments, databaseIdProvider, mappers
), 然后将这些值解析出来设置到Configuration对象中,最后返回Configuration对象。
这里的节点解析就不一一去看了,后续会有单独的文章挑几个核心节点做详细介绍。
- 调用SqlSessionFactoryBuilder对象的build(configuration)方法
通过赋值的Configuration对象,调用build方法创建DefaultSqlSessionFactory对象。基于Java API方式,手动创建XMLConfigBuilder,并解析创建Configuration对象,最后调用此方法生成SqlSessionFactoryBuilder对象。
** 至此,我们就知道了MyBatis是如何通过配置文件构建Configuration对象,并使用它创建SqlSessionFactory对象。**
总结
我们通过一个时序图,把整个myBatis初始化过程串起来,方便小伙伴更加直观的把整个流程串起来,从而对整个初始化过程了解的更加清晰
MyBatis初始化基本过程:

** 每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 从 XML 配置文件或一个预先配置的 Configuration 实例来构建出来。**
