从MyBatis官方文档学习源码-总体介绍

495 阅读4分钟

1. 官方文档理解的重要性

一个好的程序员应该学会如何阅读官方文档,一个好的官方文档应该是一个简单清晰,很准确的告诉读者该产品具备什么、解决什么,笔者认为MyBatis就是具备这样优点的产品。本文一改其他文章一上来贴几个架构图把读者砸晕的方式,从官方文档来学习MyBatis源码。

首先打开 官方网址,一个优秀的产品应该是世界的,发现支持中文,果断换中文版。 例行下载源码,开始进入入门章节。

在这里插入图片描述

入门中提到
“从xml中构建 SqlSessionFactory”

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

从 SqlSessionFactory 中获取 SqlSession

既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句

探究已映射的 SQL 语句

现在你可能很想知道 SqlSession 和 Mapper 到底具体执行了些什么操作,但 SQL 语句映射是个相当广泛的话题,可能会占去文档的大部分篇幅。 但为了让你能够了解个大概,这里会给出几个例子。

提到几个“大佬”级别的类,通通拿小本子记下:

  1. SqlSessionFactory
  2. SqlSessionFactoryBuilder
  3. Configuration
  4. SqlSession
  5. Mapper(可能的名字xxxMapper 或者MapperXXX之类,待确认)

阅读Java API章节 SqlSession

使用 MyBatis 的主要 Java 接口就是 SqlSession。你可以通过这个接口来执行命令,获取映射器示例和管理事务。在介绍SqlSession 接口之前,我们先来了解如何获取一个 SqlSession 实例。SqlSessions 是由SqlSessionFactory 实例创建的。SqlSessionFactory 对象包含创建 SqlSession 实例的各种方法。而SqlSessionFactory 本身是由 SqlSessionFactoryBuilder 创建的,它可以从 XML、注解或 Java配置代码来创建 SqlSessionFactory。

通篇阅读后,可以大致推断出SqlSession为Mybatis接口层。构建架构图: 在这里插入图片描述 我们第一步能明确SqlSession为接口层,其他暂时为黑盒,待我们层层拨开。接下来我们就以这个SqlSession为线索,展开源码阅读。


2. SqlSession的创建:我从哪里来?

从官方文档可以理解构建逻辑:

  1. SqlSessions 是由SqlSessionFactory 实例创建的;
  2. 而SqlSessionFactory 本身是由 SqlSessionFactoryBuilder创建;
  3. 而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例;

在这里插入图片描述

带着从*“可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory”* 的指示。我们先来了解 Configuration, 阅读官方文档 XML配置 章节,不难得出一个典型的mybatis-config.xml 顶层节点结构如下: Configuration结构 打开org.apache.ibatis.session.Configuration类 在这里插入图片描述 试着寻找xml节点的蛛丝马迹, 可以看出Configuration就是xml对应的类。

public class Configuration {

  //对应environments(环境配置)
  protected Environment environment;
  
  //对应properties(属性)
  protected Properties variables = new Properties();

 //对应objectFactory(对象工厂)
  protected ObjectFactory objectFactory = new DefaultObjectFactory();

//对应typeHandlers(类型对应器)
protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry(this);

//对应typeAlias(类型别名)
  protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();

//对应mappers(映射器)
  protected final MapperRegistry mapperRegistry = new MapperRegistry(this);

//对应 plugins(插件)
  protected final InterceptorChain interceptorChain = new InterceptorChain();

//...省略

  public Configuration() {
	//与databaseIdProvider(数据库厂商标识)
    typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);
   }

settings(设置)好像没有直接搜索到,通过属性搜索发现settings是散落在 Configuration 中的,不明白MyBatis作者为什么不通过一个Settings 类把setting属性封装起来。现在通通找到xml中节点对应或相似对应。


现在, 可以将SqlSession的创建过程拆解为3个阶段:

  1. Configuration初始化过程;
  2. SqlSessionFactory实例的创建过程;
  3. 创建SqlSessions实例化的过程;

官方示例:


String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

简单描述上述代码:

首先,创建了SqlSessionFactoryBuilder对象;

然后, 以Mybatis主配置文件输入流作为参数,调用 SqlSessionFactoryBuilder对象的build方法。

下面是代码实现片段:

public class SqlSessionFactoryBuilder {

//SqlSessionFactory 创建方法
  public SqlSessionFactory build(Reader reader) {
    return build(reader, null, null);
  }

// 构建SqlSessionFactory重载方法
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    try {
   
       //创建XMLConfigBuilder
      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.
      }
    }
  }

在build()方法中,首先创建一个XMLConfigBuilder对象,然后调用XMLConfigBuilder对象的parse方法对主配置文件进行解析, 生成Configuration对象。以ConfigBuilder对象作为参数调用重载的builder()方法,方法实现片段:

  public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
  }

DefaultSqlSessionFactory类

public class DefaultSqlSessionFactory implements SqlSessionFactory {

  private final Configuration configuration;

  //接收Configuration作为参数的构造方法
  
  public DefaultSqlSessionFactory(Configuration configuration) {
    this.configuration = configuration;
  }
  ...//省略

最后,SqlSessionFactory接口的默认实现,即DefaultSqlSessionFactory。通过new 创建了一个DefaultSessionFactory对象。


3.后记

以上, 我们梳理了 MyBatis 的 SqlSession 的创建过程,但是跳过了Configuration的具体构造过程,下一节我们继续来看Configuration的创建。同时来探究Configuration这个类的内部。