阿里的御用框架,MyBatis與設(shè)計(jì)模式的激情碰撞

前言

Java程序員以前連接數(shù)據(jù)庫(kù)是這樣的

image

現(xiàn)在連接數(shù)據(jù)庫(kù)是這樣的

image

在傳統(tǒng)的JDBC 實(shí)現(xiàn)中,我們需要把查詢過(guò)程寫在Java 類中,這樣非常不便于后期維護(hù)。而使用Mybatis 則可以將查詢語(yǔ)句配置在配置文件中,只需要維護(hù)好映射關(guān)系即可。

image

Mybatis是一個(gè)開(kāi)源的輕量級(jí)半自動(dòng)化ORM框架,使得面向?qū)ο髴?yīng)用程序與關(guān)系數(shù)據(jù)庫(kù)的映射變得更加容易。熟悉Mybatis的都知道,其源碼里涉及到非常多的設(shè)計(jì)模式,比如

設(shè)計(jì)模式

Builder模式****:例如SqlSessionFactoryBuilder、XMLConfigBuilder、XMLMapperBuilder、XMLStatementBuilder、CacheBuilder;

工廠模式:例如SqlSessionFactory、ObjectFactory、MapperProxyFactory;

單例模式:例如ErrorContext和LogFactory;

代理模式:Mybatis實(shí)現(xiàn)的核心,比如MapperProxy、ConnectionLogger,用的jdk的動(dòng)態(tài)代理;還有executor.loader 包 使用了cglib或者javassist達(dá)到延遲加載的效果;

組合模式:例如SqlNode和各個(gè)子類ChooseSqlNode等;

模板方法模式:例如BaseExecutor和SimpleExecutor,還有BaseTypeHandler和所有的子類例如IntegerTypeHandler;

適配器模式:例如Log的Mybatis接口和它對(duì)jdbc、log4j等各種日志框架的適配實(shí)現(xiàn);

裝飾者模式:例如Cache包中的cache.decorators子包中等各個(gè)裝飾者的實(shí)現(xiàn);

迭代器模式:例如迭代器模式PropertyTokenizer;

關(guān)注公眾號(hào)“程序員白楠楠”獲取一份562頁(yè)的設(shè)計(jì)模式資料

如果之前只會(huì)使用或者沒(méi)有看過(guò)Mybatis源碼,那看到上面這些設(shè)計(jì)模式可能會(huì)有點(diǎn)懵逼。Mybatis用了這么多年了,只會(huì)用它來(lái)CRUD數(shù)據(jù)庫(kù)嗎?其底層的架構(gòu)設(shè)計(jì)與源碼分析,如何連接數(shù)據(jù)庫(kù)的?如何執(zhí)行的?一二級(jí)緩存的作用?sql如何解析的?源碼中設(shè)計(jì)到的設(shè)計(jì)模式......這些技術(shù)點(diǎn)都會(huì)嗎?

Mybatis源碼分析

今天,我們就來(lái)看看Mybatis源碼的閱讀,具體舉個(gè)例子來(lái)看看:

案例和疑問(wèn)

從我們最初的demo中開(kāi)始:

public static void main(String[] args) {
        String resource = "mybatis-config.xml";
        InputStream inputStream = null;
        SqlSession sqlSession = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            sqlSession = sqlSessionFactory.openSession(); 
            User user = sqlSession.selectOne("com.tian.mybatis.mapper.UserMapper.selectById", 1);
            System.out.println(user); 
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            sqlSession.close();
        }
    }

關(guān)于獲取數(shù)據(jù)流inputStream,這個(gè)我們就不討論了,我們主要關(guān)注重點(diǎn)。

對(duì)于上面demo,我們可以分成五個(gè)步驟:

第一步,創(chuàng)建一個(gè)工廠類sqlSessionFactory。

配置文件的解析就是在這里完成的。包括mybatis-config.xml和我們的Mapper.xml映射器文件。這一步我們關(guān)心的內(nèi)容是:解析的時(shí)候做了什么?產(chǎn)生了什么對(duì)象,解析的結(jié)果放在哪里的。因?yàn)檫@將意味著,我們后面使用的時(shí)候去哪里獲取這項(xiàng)配置項(xiàng)內(nèi)容。

第二步,通過(guò)SqlSessionFactory創(chuàng)建一個(gè)SqlSession。

那么問(wèn)題來(lái)了,SqlSession中定義了各種增刪改查的API,是給客戶端調(diào)用,返回的是什么實(shí)現(xiàn)類?除了SqlSession以外,我們還創(chuàng)建了什么對(duì)象,創(chuàng)建了什么環(huán)境?

第三步,獲取到一個(gè)Mapper對(duì)象。

問(wèn)題來(lái)了UserMapper.java是一個(gè)接口,并沒(méi)有為它創(chuàng)建實(shí)現(xiàn)類,那又是怎么被實(shí)例化的呢?我們使用的這個(gè)Mapper對(duì)象到底是什么對(duì)象呢?為什么要從SqlSession里去獲取呢?為什么傳進(jìn)去一個(gè)接口,然后還要用一個(gè)接口去接收呢?

第四步,調(diào)用接口方法。

問(wèn)題是我們的接口沒(méi)有實(shí)現(xiàn)類,為什么就可以直接調(diào)用它的方法呢?那它調(diào)用的是誰(shuí)的方法呢?是如何把SQL給關(guān)聯(lián)起來(lái)的呢?是如何獲取到數(shù)據(jù)的呢?

第五步,關(guān)閉相關(guān)資源。

開(kāi)始源碼分析過(guò)程

由于涉及到內(nèi)容較多,下面就用幾張圖來(lái)展示整個(gè)流程。我們可以通過(guò)這幾張圖來(lái)快速翻閱Mybatis的源碼。

第一步

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

這一句代碼的整個(gè)流程如下:

image

根據(jù)inputStream,解析配置文件,創(chuàng)建出一個(gè)DefaultSqlSessionFactory默認(rèn)的SqlSessionFactory 實(shí)現(xiàn)類。構(gòu)建出一個(gè)工廠類,這個(gè)工廠類專門用來(lái)創(chuàng)建SqlSession對(duì)象的。

第二步

SqlSession  sqlSession = sqlSessionFactory.openSession();

獲取SqlSession的整個(gè)流程如下:

image

第三步

User user = sqlSession.selectOne("com.tian.mybatis.mapper.UserMapper.selectById", 1);

第三步和第四步就是這行代碼畫的。

這一步是返回一個(gè)映射器代理類,映射器代理類專門用來(lái)給UserMapper接口和UserMapper.xml綁定的代理類。創(chuàng)建出來(lái)的代理類就可以實(shí)例化了,然后就可以調(diào)用UserMapper接口的方了。

image

第四步:調(diào)用代理對(duì)象執(zhí)行SQL的整個(gè)過(guò)程。

image

第五步,關(guān)閉資源。

希望大家按照這個(gè)流程,找點(diǎn)源碼看看。聽(tīng)別人的看別人永遠(yuǎn)是別人的。

動(dòng)起來(lái)吧!

個(gè)人建議

對(duì)于一般java程序員來(lái)說(shuō),閱讀源碼之前到底需要些什么技能呢?

個(gè)人建議,以下基礎(chǔ)知識(shí)必須會(huì)一些:

會(huì)設(shè)計(jì)模式:包括單例模式、工廠模式、代理模式、裝飾器模式、責(zé)任鏈模式、模板方法模式等。

會(huì)猜測(cè):大膽的猜測(cè),在看源碼的時(shí)候,多站在高層次想想,如果你是Mybatis的設(shè)計(jì)者,你會(huì)怎么設(shè)計(jì)?

總結(jié)

Mybatis應(yīng)該是國(guó)內(nèi)用得最多的「數(shù)據(jù)訪問(wèn)層」框架了,看了我司的好幾個(gè)系統(tǒng),基本都是用Mybatis。所以深入了解Mybatis的重要性不言而喻。

小編總結(jié)一份562頁(yè)的設(shè)計(jì)模式資料, 這份資料非常全面且詳細(xì),覆蓋了 設(shè)計(jì)模式 基礎(chǔ)學(xué)習(xí)的方方面面,非常適合初學(xué)者入門!

資料獲取方式:關(guān)注公眾號(hào)“程序員白楠楠”獲取上述資料!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容