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配置
<?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官网文档,文档上对每一个配置项都已经做出了很详细的说明和示例。

  • 程序入口代码
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)方法
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

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

  • SqlSessionFactoryBuilder会根据输入流inputStream等创建XMLConfigBuilder对象
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对象
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()方法
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

  • 25
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值