Mybatis源码阅读之二——模板方法模式与Executor
[系列目錄]
Mybatis源碼閱讀之一——工廠模式與SqlSessionFactory
文章目錄
- 一. 模板方法模式
- 二. 同步回調與匿名函數
- 三. Executor
- BaseExecutor與其子類
- 一二級緩存與CacheExecutor
- 總結
Mybatis中的Executor應用了模板方法模式,我們有必要先來了解這一種行為型設計模式。
一. 模板方法模式
行為型模式是對在不同的對象之間劃分責任和算法的抽象化。
通過行為型模式,可以更加清晰地劃分類與對象的職責,并研究系統在運行時實例對象 之間的交互。
模板方法模式通過繼承關系在父類與子類之間分配行為,父類負責通用邏輯的實現,不同的邏輯則是提供統一的方法,交由子類分別繼承實現。
-
實現一
BaseService抽象類實現了doAction01方法,doAction02方法為abstract或者內部實現為直接拋異常。
-
實現二
使用java提供的default關鍵字,用接口替換抽象類來使用。
總結: 通過如上兩種實現方式,可以讓子類在不改變算法整體結構的情況下,重新定義算法中的某些
步驟。這種模式在我們有大量重復邏輯的,不同類型又有些區別差異的時候顯然是十分適合的。
比如前文【Mybatis源碼閱讀之一——工廠模式與SqlSessionFactory】有提到的采購單與銷售單各自的處理邏輯有大量相同代碼,這部分可以提取到模板類,而剩余有區別的邏輯提取出來,作為一個差異方法來各自實現。
二. 同步回調與匿名函數
同步回調能夠做到與模板方法模式類似的事情,前者更加靈活。
借鑒【設計模式之美】中的例子,spring中的JdbcTemplate雖然名字上帶了模板,但是其實內部實現使用的是同步回調。
如JdbcTemplate.query()方法,以及batchUpdate方法,最終都使用了execute()方法,而他們自身應有的邏輯則是作為回調傳遞給了execute(),實現了自身邏輯的抽離,使得execute()方法有了模板類的作用。
值得一提的是,JdbcTemplate使用的是回調類,如果我們自己做開發,能夠精簡成匿名函數的話,個人認為易讀性會更好一些。
關于JAVA中匿名函數的使用可以參考這篇https://blog.csdn.net/qq_35946969/article/details/108492198
三. Executor
回到Mybatis源碼部分,從類圖看,CachingExecutor除外,Executor->BaseExecutor->各個實現類,這個結構是一個經典的模板方法模式,比我們上述部分中,抽象類的上方多了一層接口。
先看一下Executor的接口的各方法以及大致功能描述:
這些方法我們分開說,先來看CRUD。
BaseExecutor與其子類
- BaseExecutor.update()
當我們想要繼續找doUpdate時,卻發現這是一個抽象接口,這就是模板方法的具體應用,doUpdate的實現交給了子類,看一下他們各自的實現。 - SimpleExecutor
由這里面的方法可得知,BaseExecutor留給子類實現的方法并不多,主要是CRUD和doFlushStatements。對于SimpleExecutor的doUpdate來說做了簡單兩件事情。- 第一步,通過configuration生成StatementHandler,簡單說一下,configuration是mybatis的全局配置類,幾乎所有的配置項都放在這個類。
- 第二步,使用JDBC(對應的數據庫驅動)的Statement進行sql執行。這里不再深入,關于JDBC和Mybatis中的相關Handler內容過多,我們下一章再來詳細分析
- BatchExecutor
顧名思義,是SimpleExecutor的批量版。
- 第一步,如果是復用statement,只需要存儲參數。
- 第二步,如果是新的statement,存儲下來。
- 第三步,通過JDBC的Statement.addBatch()方法將statement存儲,等待之后的批量提交。
- ReuseExecutor
是SimpleExecutor的可復用版,此類的關鍵就在statementMap這個全局變量,他會緩存sql->Statement的對應關系,邏輯簡單不再展開。
一二級緩存與CacheExecutor
回到Executor的接口,我們繼續往下看緩存相關的接口:
上面我們介紹了BaseExecutor的子類只有CRUD等幾個少數方法,緩存相關的接口只在BaseExecutor/CacheExecutor實現。
-
CachingExecutor.createCacheKey()
可以看到CachingExecutor什么都沒做,直接轉給了自己內部的Executor代理類,那么具體的實現只會在BaseExecutor中了。
值得一提,這里的代理Executor體現了CacheExecutor的作用,他其實只是一個BaseExecutor的裝飾器,在BaseExecutor的基礎上,增加了二級緩存功能 -
BaseExecutor.createCacheKey()
這里的實現其實就是將sql等一些信息組裝起來,作為一個CacheKey對象返回,用于之后做一級緩存/二級緩存的key。
-
BaseExecutor.clearLocalCache()
CachingExecutor中該方法仍然是直接調用代理Executor,我們直接看BaseExecutor。
這里的localCache其實就是我們所說的一級緩存,PerpetualCache可以直接看作一個Map結構(Cache相關的具體涉及我們放到后面與裝飾器一起解讀) -
一級緩存
讓我們再找找這個一級緩存被使用到的地方。- 查詢時:
- 從數據庫查出時更新:
-
二級緩存
之前我們提到了二級緩存的實現就是CacheExecutor。
查詢時,會先經過二級緩存,找不到才會進入代理(原始)Executor。
總結
Executor與BaseExecutor采用了模板方法模式,擴展了批量操作,單個操作,復用操作等子類,同時又使用CacheExecutor裝飾器模式做了二級緩存的實現。
歡迎關注微信公眾號 【JAVA技術分享官】,公眾號首發,持續輸出原創高質量JAVA開發者知識點
總結
以上是生活随笔為你收集整理的Mybatis源码阅读之二——模板方法模式与Executor的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vue3学习(引入轮播图插件)
- 下一篇: 显卡显存测试u盘 mats_与RX570