Mybatis原始碼解析3——核心類SqlSessionFactory,看完我悟了

YSOcean發表於2021-09-02

這是昨晚的武漢,晚上九點鐘拍的,疫情又一次來襲,曾經熙熙攘攘的夜市也變得冷冷清清,但比前幾周要好很多了。希望大家都能保護好自己,保護好身邊的人,生活不可能像你想象的那麼好,但也不會像你想象的那麼糟。

好了,言歸正傳,搞技術的努力提升技術才是王道。

這是Mybatis 原始碼解析第三篇文章

①、Mybatis 原始碼解析1——從JDBC到Mybatis

②、Mybatis 原始碼解析2——從0到1例項搭建

在上一篇文章《Mybatis從0到1例項搭建》中,可樂給大家手擼了一遍如何通過 Mybatis 對資料庫一張表進行增刪改查。至此,Mybatis 的前奏已經演奏完畢,接下來,我們將會進入高潮部分,請大家搬好小板凳,可樂將會用最通俗易懂,圖文並茂的方式,給大家深入剖析 Mybatis 的實現原理。

本篇文章我們首先解析 SqlSessionFactory 的建立過程。

1、例項程式碼

在例項程式碼中,我們在測試類中寫了一個 init() 方法,裡面包括了 SqlSessionFactory 的構建,分為兩步。

第一步:讀取配置檔案 mybatis-config.xml 輸入流

第二步:根據輸入流構建 SqlSessionFactory;

public void init() {
    //定義mybatis全域性配置檔案
    String resource = "mybatis-config.xml";
    //載入 mybatis 全域性配置檔案
    InputStream inputStream = null;
    try {
        inputStream = Resources.getResourceAsStream(resource);
    } catch (IOException e) {
        e.printStackTrace();
    }
    //構建sqlSession的工廠
    sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

}

沒什麼難的,去掉 try-catch,也就兩行程式碼。

InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

是的,那只是你以為的兩行程式碼,其實......

話不多說,可樂就來給大家揭祕這冰山下面的東西。

2、構建過程圖示

大家可以先看可樂為大家總結的兩張流程圖。

溫馨提示:結合流程圖,再來服用程式碼,效果更佳。

3、程式碼剖析

根據上面的時序圖,我們分析根據原始碼分析每個步驟。

①、獲取配置檔案輸入流

InputStream inputStream = Resources.getResourceAsStream("mybatis.config.xml");

這裡沒什麼好說的,就是獲取配置檔案的輸入流。

②、build(in)

這裡的 in 就是上一步獲取的輸入流 inputStream。

  public SqlSessionFactory build(InputStream inputStream) {
    return build(inputStream, null, null);
  }

在進入到 build 方法:

  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.
      }
    }
  }

③、XMLConfigBuilder(in)

這一段程式碼是為了解析我們的配置檔案,配置檔案是 XML形式 ,我在之前的部落格介紹過解析 XML 的幾種方式。

一種是基於樹的結構來解析的稱為DOM;另一種是基於事件流的形式稱為SAX和(StAX)

兩者各有優缺點,我這裡不做詳細說明,想了解的可以看我之前的文章。

而 Mybatis 使用的是 DOM 形式,並結合 XPath 來解析配置檔案。

④、parse()

    public Configuration parse() {
        if (this.parsed) {
            throw new BuilderException("Each XMLConfigBuilder can only be used once.");
        } else {
            this.parsed = true;
            this.parseConfiguration(this.parser.evalNode("/configuration"));
            return this.configuration;
        }
    }

從 /configuration 標籤處開始解析。然後我們進入到 this.parseConfiguration() 方法中:

    private void parseConfiguration(XNode root) {
        try {
            this.propertiesElement(root.evalNode("properties"));
            Properties settings = this.settingsAsProperties(root.evalNode("settings"));
            this.loadCustomVfs(settings);
            this.loadCustomLogImpl(settings);
            this.typeAliasesElement(root.evalNode("typeAliases"));
            this.pluginElement(root.evalNode("plugins"));
            this.objectFactoryElement(root.evalNode("objectFactory"));
            this.objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
            this.reflectorFactoryElement(root.evalNode("reflectorFactory"));
            this.settingsElement(settings);
            this.environmentsElement(root.evalNode("environments"));
            this.databaseIdProviderElement(root.evalNode("databaseIdProvider"));
            this.typeHandlerElement(root.evalNode("typeHandlers"));
            this.mapperElement(root.evalNode("mappers"));
        } catch (Exception var3) {
            throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + var3, var3);
        }
    }

看到這是不是很熟悉了,這不就是mybatis-config.xml 配置檔案裡面的各個標籤名嘛,是的,這就是解析該檔案,然後全部放在 configuration 物件中。需要注意的是,這裡的 configuration 物件不僅包括 mybatis-config.xml 檔案內容,也包括 xxxMapper.xml 檔案內容。

⑤、build(configuration)

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


就是去 new 了一個 DefaultSqlSessionFactory 物件,將 configuration 作為引數。

⑥、DefaultSqlSessionFactory(configuration)

    public DefaultSqlSessionFactory(Configuration configuration) {
        this.configuration = configuration;
    }

4、總結

自此,SqlSessionFactory 的建立過程就講完了,總的來說就是一個封裝了配置檔案的工廠類。那麼得到了 SqlSessionFactory 這個工廠物件,接下來幹嘛?生產 SqlSession,然後通過 SqlSession 進行資料庫的增刪改查操作

沒錯,接下來,可樂將給大家介紹 SqlSession 的互動過程,這也是 Mybatis 裡面最重要的一個物件。

相關文章