MyBatis初始化基本过程

MyBatis初始化方式

MyBatis初始化提供了两种方式:

  • 基于XML配置文件:基于XML配置文件的方式是将MyBatis的所有配置信息放在XML文件中mybatis-config.xmlMyBatis通过加载并XML配置文件,将配置文信息组装成内部的Configuration对象
  • 基于Java API:基于Java API的方式是手动创建Configuration对象,然后将配置参数set 进入Configuration对象中。

任何框架的初始化,应该都是先加载配置信息,接下来我们将使用基于XML配置文件的方式,来深入讨论MyBatis是如何通过配置文件构建Configuration对象。

基于Xml配置初始化

XML 配置文件中包含了对 MyBatis 系统的核心设置,包括获取数据库连接实例的数据源(DataSource)以及决定事务作用域和控制方式的事务管理器(TransactionManager)。

通过一个简单的例子,分析一下基于Xml配置MyBatis是怎样完成初始化的,都做了些什么?

  • mybatis-config.xml配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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官网文档,文档上对每一个配置项都已经做出了很详细的说明和示例。

  • 程序入口代码
1
2
3
4
5
6
7
8
9
10
11
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)方法
1
java复制代码sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

  SqlSessionFactoryBuilder是SqlSessionFactory的构造器,用于创建SqlSessionFactory,采用了Builder设计模式

  • SqlSessionFactoryBuilder会根据输入流inputStream等创建XMLConfigBuilder对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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()方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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初始化基本过程:

image.png

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

screenshot-20240417-103455.png

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%