百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分类 > 正文

MyBatis 初始化流程(mybatis配置流程)

ztj100 2024-10-27 18:32 21 浏览 0 评论

之前已经创建了MyBatis的简答项目,今天我们来分析一下MyBatis 基于 XML 配置文件创建 Configuration 对象的过程。

MyBatis 使用 org.apache.ibatis.session.Configuration 对象作为一个存储所有配置信息的容器,Configuration 对象的属性和 mybatis-config.xml 配置文件的组织结构几乎完全一样(当然,Configuration 对象的功能并不限于此,它还负责创建一些 MyBatis 内部使用的对象,如 Executor 等,这些暂不在本文中讨论)。

MyBatis初始化基本过程:

初始化的基本过程如下序列图所示:


读取配置文件

从之前项目(MyBatis架构介绍及简单示例)的Test 主函数第一步可以看出,首先读取 mybatis-config.xml 解析成 Reader。

String resource = "mybatis-config.xml";
Reader reader = Resources.getResourceAsReader(resource);

创建 SqlSessionFactoryBuilder 对象

从 SqlSessionFactoryBuilder 的名字中可以看出,SqlSessionFactoryBuilder 是用来创建 SqlSessionFactory 对象的。

从 SqlSessionFactoryBuilder 源码可以看出,SqlSessionFactoryBuilder 中只有一些重载的 build 函数,这些 build 函数的入参都是 MyBatis 配置文件的输入流,返回值都是 SqlSessionFactory;由此可见,SqlSessionFactoryBuilder 的作用很纯粹,就是用来通过配置文件创建 SqlSessionFactory 对象的。

public class SqlSessionFactoryBuilder {
    public SqlSessionFactory build(Reader reader) {
        return build(reader, null, null);
    }
    public SqlSessionFactory build(Reader reader, String environment) {
        return build(reader, environment, null);
    }
    public SqlSessionFactory build(Reader reader, Properties properties) {
        return build(reader, null, properties);
    }
    public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
        try {
            XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
            return build(parser.parse());
        } catch (Exception e) {
            throw ExceptionFactory.wrapException("Error building SqlSession.", e);
        } finally {
            ErrorContext.instance().reset();
            try {
                reader.close();
            } catch (IOException e) {
                // Intentionally ignore. Prefer previous error.
            }
        }
    }
    public SqlSessionFactory build(InputStream inputStream) {
        return build(inputStream, null, null);
    }
    public SqlSessionFactory build(InputStream inputStream, String environment) {
        return build(inputStream, environment, null);
    }
    public SqlSessionFactory build(InputStream inputStream, Properties properties) {
        return build(inputStream, null, properties);
    }
    public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
        try {
            XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
            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.
            }
        }
    }
    public SqlSessionFactory build(Configuration config) {
        return new DefaultSqlSessionFactory(config);
    }
}

SqlSessionFactory 创建过程

下面是具体如何创建 SqlSessionFactory 对象的 build 函数,通过构造 XMLConfigBuilder 对象,利用其 parse() 方法返回的 Configuration 对象,构建DefaultSqlSessionFactory 对象。

public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
    try {
        XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
        return build(parser.parse());
    } catch (Exception e) {
        throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
        ErrorContext.instance().reset();
        try {
            reader.close();
        } catch (IOException e) {
            // Intentionally ignore. Prefer previous error.
        }
    }
}
public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
}

创建Configuration对象的过程

以上是整个创建 SqlSessionFactory 的流程,而从上面可以看出创建 Configuration 对象,主要是通过 XMLConfigBuilder 对象,调用其 parse() 方法返回 Configuration 对象。

1.构造 XMLConfigBuilder 对象

SqlSessionFactoryBuilder 的 build 函数首先会构造一个 XMLConfigBuilder 对象,该对象是用来解析XML配置文件的。XMLConfigBuilder 的继承自 BaseBuilder, BaseBuilder 有 XMLxxxBuilder 子类,这些 XMLxxxBuilder 是用来解析 XML 配置文件的,不同类型 XMLxxxBuilder 用来解析 MyBatis 配置文件的不同部位。比如:XMLConfigBuilder 用来解析 MyBatis 的配置文件, XMLMapperBuilder 用来解析MyBatis中的映射文件(如上文提到的 UserMapper.xml),XMLStatementBuilder用来解析映射文件中的SQL语句。

当创建 XMLConfigBuilder 对象时,就会初始化 Configuration 对象,并且在初始化 Configuration 对象的时候,一些别名会被注册到 Configuration 的 typeAliasRegistry 容器中。

private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
    super(new Configuration());
    ErrorContext.instance().resource("SQL Mapper Configuration");
    this.configuration.setVariables(props);
    this.parsed = false;
    this.environment = environment;
    this.parser = parser;
}
public Configuration() {
    // 注册别名
    typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
    typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);
    typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
    typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
    typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);
    typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);
    typeAliasRegistry.registerAlias("FIFO", FifoCache.class);
    typeAliasRegistry.registerAlias("LRU", LruCache.class);
    typeAliasRegistry.registerAlias("SOFT", SoftCache.class);
    typeAliasRegistry.registerAlias("WEAK", WeakCache.class);
    ……
}

2.解析配置文件,返回 Configuration 对象

当有了 XMLConfigBuilder 对象之后,接下来就可以用它来解析配置文件了。

public Configuration parse() {
    if (parsed) {
        throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    parsed = true;
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
}
private void parseConfiguration(XNode root) {
    try {
        // 解析<properties>节点
        propertiesElement(root.evalNode("properties"));
        // 解析<settings>节点
        Properties settings = settingsAsProperties(root.evalNode("settings"));
        loadCustomVfs(settings);
        // 解析<typeAliases>节点
        typeAliasesElement(root.evalNode("typeAliases"));
        // 解析<plugins>节点
        pluginElement(root.evalNode("plugins"));
        // 解析<objectFactory>节点
        objectFactoryElement(root.evalNode("objectFactory"));
        objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
        // 解析<reflectorFactory>节点
        reflectorFactoryElement(root.evalNode("reflectorFactory"));
        settingsElement(settings);
        // 解析<environments>节点
        environmentsElement(root.evalNode("environments"));
        databaseIdProviderElement(root.evalNode("databaseIdProvider"));
        typeHandlerElement(root.evalNode("typeHandlers"));
        // 解析<mappers>节点
        mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
        throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
}

从上述代码中可以看到,XMLConfigBuilder 会依次解析配置文件中的 properties、settings、environments、typeAliases、plugins、mappers 等属性。具体的解析细节不在本文展开,主要是 XMLConfigBuilder 将 XML 配置文件的信息转换为 Document 对象,而 XML 配置定义文件 DTD 转换成 XMLMapperEntityResolver 对象,然后将封装到 XpathParser 对象中,XpathParser 的作用是提供根据 Xpath 表达式获取基本的 DOM 节点 Node 信息的操作,而解析 mappers 节点还使用到了前面提到了 XMLMapperBuilder。

总结

上述的初始化过程中,涉及到了以下几个对象:

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

SqlSessionFactory: SqlSession 工厂类,以工厂形式创建 SqlSession 对象,采用了工厂设计模式;

XMLConfigBuilder: 负责将 mybatis-config.xml 配置文件解析成 Configuration 对象,供 SqlSessonFactoryBuilder 使用,创建 SqlSessionFactory;

Configuration: 该对象是 mybatis-config.xml 文件中所有 MyBatis 配置信息。

以上就是 MyBatis 初始化创建 SqlSessionFactory 完整流程,对于具体每个节点的解析逻辑后面文章再继续深入分析。

参考文献:

  1. 《MyBatis 技术内幕》
  2. 《Mybatis从入门到精通》

相关推荐

再说圆的面积-蒙特卡洛(蒙特卡洛方法求圆周率的matlab程序)

在微积分-圆的面积和周长(1)介绍微积分方法求解圆的面积,本文使用蒙特卡洛方法求解圆面积。...

python编程:如何使用python代码绘制出哪些常见的机器学习图像?

专栏推荐...

python创建分类器小结(pytorch分类数据集创建)

简介:分类是指利用数据的特性将其分成若干类型的过程。监督学习分类器就是用带标记的训练数据建立一个模型,然后对未知数据进行分类。...

matplotlib——绘制散点图(matplotlib散点图颜色和图例)

绘制散点图不同条件(维度)之间的内在关联关系观察数据的离散聚合程度...

python实现实时绘制数据(python如何绘制)

方法一importmatplotlib.pyplotaspltimportnumpyasnpimporttimefrommathimport*plt.ion()#...

简单学Python——matplotlib库3——绘制散点图

前面我们学习了用matplotlib绘制折线图,今天我们学习绘制散点图。其实简单的散点图与折线图的语法基本相同,只是作图函数由plot()变成了scatter()。下面就绘制一个散点图:import...

数据分析-相关性分析可视化(相关性分析数据处理)

前面介绍了相关性分析的原理、流程和常用的皮尔逊相关系数和斯皮尔曼相关系数,具体可以参考...

免费Python机器学习课程一:线性回归算法

学习线性回归的概念并从头开始在python中开发完整的线性回归算法最基本的机器学习算法必须是具有单个变量的线性回归算法。如今,可用的高级机器学习算法,库和技术如此之多,以至于线性回归似乎并不重要。但是...

用Python进行机器学习(2)之逻辑回归

前面介绍了线性回归,本次介绍的是逻辑回归。逻辑回归虽然名字里面带有“回归”两个字,但是它是一种分类算法,通常用于解决二分类问题,比如某个邮件是否是广告邮件,比如某个评价是否为正向的评价。逻辑回归也可以...

【Python机器学习系列】拟合和回归傻傻分不清?一文带你彻底搞懂

一、拟合和回归的区别拟合...

推荐2个十分好用的pandas数据探索分析神器

作者:俊欣来源:关于数据分析与可视化...

向量数据库:解锁大模型记忆的关键!选型指南+实战案例全解析

本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在...

用Python进行机器学习(11)-主成分分析PCA

我们在机器学习中有时候需要处理很多个参数,但是这些参数有时候彼此之间是有着各种关系的,这个时候我们就会想:是否可以找到一种方式来降低参数的个数呢?这就是今天我们要介绍的主成分分析,英文是Princip...

神经网络基础深度解析:从感知机到反向传播

本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在...

Python实现基于机器学习的RFM模型

CDA数据分析师出品作者:CDALevelⅠ持证人岗位:数据分析师行业:大数据...

取消回复欢迎 发表评论: