Mybatis源碼如何閱讀,教你一招!!!


前言

  • 前一篇文章簡單的介紹了Mybatis的六個重要組件,這六劍客占據了Mybatis的半壁江山,和六劍客搞了基友,那么Mybatis就是囊中之物了。對六劍客感興趣的朋友,可以看看這篇文章:Mybatis源碼解析篇之六劍客
  • 有些初入門的朋友可能很害怕閱讀源碼,不知道如何閱讀源碼,與其我一篇文章按照自己的思路寫完Mybatis的源碼,但是你們又能理解多少呢?不如教會你們思路,讓你們能夠自己知道如何閱讀源碼。

環境配置

  • 本篇文章講的一切內容都是基於Mybatis3.5SpringBoot-2.3.3.RELEASE

從哪入手?

  • 還是要說一說六劍客的故事,既然是Mybatis的重要組件,當然要從六劍客下手了,沿用上篇文章的一張圖,此圖記錄了六劍客先后執行的順序,如下:
    六劍客執行流程圖

  • 閱讀源碼最重要的一點不能忘了,就是開啟DEBUG模式,重要方法打上斷點,重要語句打上斷點,先把握整體,再研究細節,基本就不難了。

  • 下面就以Myabtis的查詢語句selectList()來具體分析下如何閱讀。

總體把握六劍客

  • 從六劍客開整,既然是重要組件,源碼執行流程肯定都是圍繞着六劍客,下面來對六劍客一一分析,如何打斷點。

  • 下面只是簡單的教你如何打斷點,對於六劍客是什么不再介紹,請看上篇文章。

SqlSession

  • 既然是接口,肯定不能在接口方法上打斷點,上文介紹有兩個實現類,分別是DefaultSqlSessionSqlSessionTemplate。那么SpringBoot在初始化的時候到底注入的是哪一個呢?這個就要看Mybatis的啟動器的自動配置類了,其中有一段這樣的代碼,如下:
  //如果容器中沒有SqlSessionTemplate這個Bean,則注入
  @Bean
  @ConditionalOnMissingBean
  public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
    ExecutorType executorType = this.properties.getExecutorType();
    if (executorType != null) {
      return new SqlSessionTemplate(sqlSessionFactory, executorType);
    } else {
      return new SqlSessionTemplate(sqlSessionFactory);
    }
  }
  • 從上面的代碼可以知道,SpringBoot啟動時注入了SqlSessionTemplate,此時就肯定從SqlSessionTemplate入手了。它的一些方法如下圖:
    SqlSessionTemplate方法

  • 從上圖的標記可以知道,首當其沖的就是構造方法了;既然是分析selectList()的查詢流程,當然全部的selectList()方法要打上斷點了;上篇文章也講了Mapper的接口最終是走的動態代理生成的實例,因此此處的getMapper()也打上斷點。

  • 對於初入門的來說,上面三處打上斷點已經足夠了,但是如果你仔細看一眼selectList()方法,如下:

  @Override
  public <E> List<E> selectList(String statement) {
    //此處的sqlSessionProxy是什么,也是SqlSession類型的,此處斷點運行到這里可以知道,就是DefaultSqlSession實例
    return this.sqlSessionProxy.selectList(statement);
  }
  • sqlSessionProxy是什么,沒關系,這個不能靠猜,那么此時斷點走一波,走到selectList()方法內部,如下圖:
  • 從上圖可以很清楚的看到了,其實就是DefaultSqlSession。哦,明白了,原來SqlSessionTemplate把過甩給了DefaultSqlSession了,太狡詐了。
  • DefaultSqlSession如何打斷點就不用說了吧,自己搞搞吧。

Executor

  • 上面文章講過執行器是什么作用,也講過Mybatis內部是根據什么創建執行器的。此處不再贅述了。

  • SpringBoot整合各種框架有個特點,萬變不離自動配置類,框架的一些初始化動作基本全是在自動配置類中完成,於是我們在配置類找一找在哪里注入了Executor的Bean,於是找到了如下的一段代碼:

  • 從上面的代碼可以知道默認創建了CachingExecutor,二級緩存的執行器,別管那么多,看看它重寫了Executor的哪些接口,與selectList()相關的方法打上斷點,如下圖:

  • 從上圖也知道哪些方法和selectList()相關了,顯然的query是查詢的意思,別管那么多,先打上斷點。

  • 此時再仔細瞅一眼query()的方法怎么執行的,哦?發現了什么,如下:

@Override
  public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
      throws SQLException {
      //先嘗試從緩存中獲取
    Cache cache = ms.getCache();
    if (cache != null) {
      flushCacheIfRequired(ms);
      if (ms.isUseCache() && resultHandler == null) {
        ensureNoOutParams(ms, boundSql);
        @SuppressWarnings("unchecked")
        List<E> list = (List<E>) tcm.getObject(cache, key);
        if (list == null) {
          list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
          tcm.putObject(cache, key, list); // issue #578 and #116
        }
        return list;
      }
    }
    //沒有緩存,直接調用delegate的query方法
    return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }
  • 從上面的代碼知道,有緩存了,直接返回了,沒有緩存,調用了delegate中的query方法,那么這個delegate是哪個類的對象呢?參照sqlSession的分析的方法,調試走起,可以知道是SimpleExecutor的實例,如下圖:
  • 后面的SimpleExecutor如何打斷點就不再說了,自己嘗試找找。

StatementHandler

  • 很熟悉的一個接口,在學JDBC的時候就接觸過類似的,執行語句和設置參數的作用。
  • 這個接口很簡單,大佬寫的代碼,看到方法名就知道這個方法是干什么的,如下圖:
  • 最重要的實現類是什么?當然是PreparedStatementHandler,因此在對應的方法上打上斷點即可。

ParameterHandler

  • 這個接口很簡單,也別選擇了,總共兩個方法,一個設置,一個獲取,在實現類DefaultParameterHandler中對應的方法上打上斷點即可。

TypeHandler

  • 類型處理器,也是一個簡單的接口,總共'兩個'方法,一個設置參數的轉換,一個對結果的轉換,啥也別說了,自己找到對應參數類型的處理器,在其中的方法打上斷點。

ResultSetHandler

  • 結果處理器,負責對結果的處理,總共三個方法,一個實現類DefaultResultSetHandler,全部安排斷點。

總結

  • 授人以魚不授人以漁,與其都分析了給你看,不如教會你閱讀源碼的方式,先自己去研究,不僅僅是閱讀Mybatis的源碼是這樣,閱讀任何框架的源碼都是如此,比如Spring的源碼,只要找到其中重要的組件,比如前置處理器,后置處理器,事件觸發器等等,一切都迎刃而解。
  • 如果你覺得作者寫的不錯,有所收獲,不妨關注分享一波,后續更多精彩內容更新。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM