­

讀源碼【讀mybatis的源碼的思路】

  • 2022 年 2 月 14 日
  • 筆記

✿ 需要掌握的編譯器知識

★ 編譯器為eclipse為例子

  • 調試準備工作(步驟:Window -> Show View -》…):

    □ 打開調試斷點Breakpoint:
    image

    □ 打開變量監視:
    image

  • 要看一個方法的內部細節,按f5,進入
    image

  • 要快速跳到某個位置【在目標位置上打個斷點】,然後按f8
    image

  • 觀察方法的細節(執行流程),一步一步走,按f6
    image

  • 去除掉所有斷點(編譯器是eclipse)
    image

    □ 注意看開始標記的執行位置對不對
    image

  • f5調試的方式進入【若進入的是不相干的,按f7返回,再按f5進入一次
    舉例:

User user = mapper.get(1L); //在這裡打一個斷點進入,會先進入Long類,因為執行順序是(1L)先執行呀,所以先進入它之後,再執行get方法
  • 按ctr 和 按調試的f5的區別:
    □ ctr:是進入「被選中的代碼(類、接口、方法)」的定義的位置【強調點是代碼的定義
    □ f5:是對於當前代碼按執行的先後順序進行執行,進入、執行它的內部【強調點是代碼的執行

  • 按ctr 結合鼠標, 可以知道代碼下一步的去向(按ctr要注意的細節:ctr默認進入的是被選中的代碼的定義,不是實現過程,進入之後發現沒看到什麼有幫助理解的代碼,返回返回按住ctr,選擇實現(若是有多個實現,不知道選哪個,可以通過調試f5進入),再按鼠標進入。
    image
    image

  • 重新開始調試細節:
    (1)關閉上一次調試
    (2)點擊 開始調試之前,保留開始位置的斷點前面的√,其他斷點前面的√先去掉(開始調試之後才√回來)
    image

  • 進入一個方法後了解到方法的細節,想返回接着往下執行,按f7 返回 【返回按f7
    一般在深入了解某個模塊之後,可以按返回,返回。。。然後接着了解下一個模塊
    image


✿ 讀源碼的思路

1、重點理解執行邏輯(執行過程可以按control進入方法或類,理解下一步去向後,光標回到當前位置【快捷鍵是alt+←】)

2、看源碼過程理清思路,異常相關的(error、exception、throw),讓代碼更加健碩的細節可以忽略;棧相關的stack,底層的可以忽略

3、在代碼中,看到選擇分支的話,可以觀察變量的值(判斷條件)知道要進入哪個分支

4、在代碼中,看到不理解的代碼,可以先往下執行,然後通過觀察變量的值進行理解【還可結合官網進行理解】

5、讀取流、加載資源、綁定命名空間、參數轉化不是重點

6、構造構造器不是重點,重點是看 構造器的構造過程

7、構造解析器不是重點,重點是看 解析器的解析過程

8、創建了子類要注意:什麼類型的子類?當子類有封裝的父類或兄弟類時候,注意封裝的父類或兄弟類是什麼類型的?


1、重點理解執行邏輯(執行過程可以按control進入方法或類,理解下一步去向後,光標回到當前位置【快捷鍵是alt+←】)

  • 所以閱讀源碼,咱了解到:創建了一個SqlSessoinFactory會話工廠對象是通過默認的SqlSessoinFactory創建的,在創建的時候需要傳入一個配置對象【即創建會話工廠對象的時候還創建了一個配置對象】,至此,研究一下配置對象的創建過程。

image

2、看源碼過程理清思路,異常相關的(error、exception、throw),讓代碼更加健碩的細節可以忽略;棧相關的stack,底層的可以忽略

image

image

image

image

image

3、在代碼中,看到選擇分支的話,可以觀察變量的值(判斷條件)知道要進入哪個分支

image

4、在代碼中,看到不理解的代碼,可以先往下執行,然後通過觀察變量的值進行理解【還可以結合官網進行理解】

image

5、讀取流、加載資源、綁定命名空間、參數轉化不是重點

image

image

image

6、構造構造器不是重點,重點是看構造器的構造過程

image

7、構造解析器不是重點,重點是看解析器的解析過程

image

image

image

8、創建了子類要注意:什麼類型的子類?當子類有封裝的父類或兄弟類時候,注意封裝的父類或兄弟類是什麼類型的?

  • Executor
    • CachingExecutor(Simple) 帶有緩存的執行器

image


✿ 讀mybatis的源碼的思路

■ 1、 閱讀源碼的過程,應該閱讀哪一個,哪一個是閱讀重點呢?

  • 閱讀源碼構建會話工廠對象的源碼,咱了解到:創建了一個SqlSessoinFactory會話工廠對象是通過默認的SqlSessoinFactory創建的,在創建的時候需要傳入一個配置對象【即創建會話工廠對象的時候還創建了一個配置對象】,至此,研究一下配置對象的創建過程。
    image
  • 閱讀源碼構建會話工廠對象的源碼,咱了解到:創建一個sqlSession會話對象是通過默認的sqlSession,在創建的時候需要傳入三個參數,重點是觀察哪個呢?

□ configuration 配置對象(在閱讀會話工廠對象構建的源碼的時候咱就了解過它了,不是重點)
□ executor 執行器(重點,因為在return 會話對象之前構建了executor執行器
□ autoCommit (是否提交,布爾值,不是重點)
image

  • 結合理解邏輯,還有return的提示作用,知道閱讀重點是list的過程
    image

■ 2、 閱讀源碼mybatis操作數據庫的過程:

	/* 測試查詢 */
	@Test
	public void testGet() throws IOException {
		// 1、從classpath路徑加載mybatis全局配置文件mybatis-config.xml
		InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
		// 2、創建SqlSessoinFactory會話工廠對象,好比連接池DataSource
		SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
		SqlSessionFactory factory = builder.build(in);
		// 3、創建SqlSession會話對象,好比連接對象Connection
		SqlSession session = factory.openSession();
		// 4、獲取mapper對象
		UserMapper mapper = session.getMapper(UserMapper.class);
		//執行sql操作
		User user = mapper.get(1L);
		System.out.println(user);
		// 5、關閉資源
		session.close();
	}

(1)創建SqlSessoinFactory會話工廠對象

  • 查看源碼得知,表名上是創建了一個SqlSessoinFactory會話工廠對象, 實際上在創建SqlSessoinFactory會話工廠對象的時候還創建了一個全局配置對象。咱還順帶看了一下全局配置的創建過程啦
    image

(2)創建SqlSessoin會話對象

  • 查看源碼得知,表名上是創建了一個SqlSessoin會話對象, 實際上在創建SqlSessoin會話對象的時候還創建了一個全執行器對象。咱還順帶看了一下執行器的創建過程啦

  • 執行器對象ExecutorCachingExcutor(Simple)帶有緩存的執行器】,是mybatis的調度中心,負責sql的生成和查詢緩存維護。在創建SqlSessoin會話對象創建,會執行pluginAll方法
    image

(3)創建mapper對象

  • 查看源碼得知,創建mapper對象, 實際上通過jdk的代理機制創建了一個mapper的代理對象。
    image
    image

(4) 執行sql操作:mapper.get(1L);

  • 先判斷傳入的方法類型,不是Object類型,就使用映射方法進行執行
    image
  • 執行的時候會根據元素類型進行選擇
    image
  • 咱執行mapper.get(1L)實際上是會話對象調用selectOne方法
    image
  • selectOne 返回一個集合list,觀察selectList
    image
  • 映射語句mapperStatement封裝了元素的信息
    image
  • 在selectList方法看到執行器調用查詢方法
    image
  • 發現執行查詢的過程,先經過CachingExcutor(帶有二級緩存的執行器),先從二級緩存中尋找是否有數據
    image
  • 發現執行查詢的過程,經過BaseExcutor(底層的執行器),先從一級緩存localCache中尋找是否有數據,若是沒有在從數據庫中查詢
    image
  • 從數據庫查詢,是簡單的執行器,調用doQuery方法
    image
  • 構建語句處理器對象
    image
  • 構建RoutingStatementHandler語句處理器對象
    image
  • 構建PreparedStatementHandler預編譯語句處理器對象
    image
  • 構建ParameterHandler參數處理器對象、構建ParameterHandler參數處理器對象
    image

  • ★ Statement(PreparedStatement 預編譯語句對象)創建對象之前,先創建參數處理器和結果處理器
    □ ParamterHandler 參數處理器,先把用戶傳入的參數轉成JDBC需要的參數值,在創建對象之前,會執行pluginAll方法
    □ ResultSetHandler 結果集處理器,把結果集中的數據封裝到list集合,在創建對象之前,會執行pluginAll方法
    image
    image
    image

  • 實例化一個語句對象
    image
    。。。

✿ 總結閱讀mybatis執行sql的源碼中的核心對象:

  • InterceptorChaiin 攔截器鏈,多個攔截器合成

  • Configuration 全局配置對象,封裝了所有的配置信息

  • Executor 執行器,myBatis的調度中心,負責sql生成和查詢緩存維護,在創建sqlSession對象之前。創建ok之後,會執行pluginAll方法

    • BaseExecutor 底層的執行器,先從一級緩存中查詢,若沒有,則到數據庫中查詢
    • CachingExcutor(Simple) 帶有二級緩存的執行器,先去二級緩存中尋找是否有數據
  • MappedStatement 映射語句對象,封裝了一個元素節點(insert|delete|update|select)的信息

  • StatementHandler 語句處理器,封裝了JDBC的DML/DQL操作,參數設置,在創建對象時,執行pluginAll方法

    • RoutingStatement

■ 在創建StatementHandler 創建對象之前,先創建參數處理器和結果集處理器
□ ParameterHandler 參數處理器,把用戶傳入的參數轉化為JDBC需要的參數值,在創建對象時,執行 pluginAll方法
□ ResultSetrHandler 結果集處理器,在結果集中的數據封裝到List集合,在創建對象時,執行 pluginAll方法


✿ 讀的源碼需要掌握的單詞

  • map 映射       mapper 映射器
  • factory 工廠
  • build 構建
  • config 配置
  • parse 解析     parser 解析器      parsed 已解析的      parseConfiguration 解析配置
  • interceptor 攔截器
  • plugin 「安裝[增強]」、插件
  • proxy 代理
  • prepared 預編譯的 callable 存儲的
  • statment 語句對象      preparedStatement 預編譯語句對象     callableStatement 存儲的語句對象
  • cursor 光標
  • instantiate 實例化      instantiateStatement 實例化語句對象
  • handler 處理器      typeHandler 類型處理器
  • row 行