Mybatis 源碼跟蹤

本篇就是記流水賬的,一般孩兒可忍不了

在前面一篇博客中,我從官方文檔上抄了這么一段內(nèi)容,它是一段完整的mybatis執(zhí)行步驟的代碼啊犬。首先創(chuàng)建sqlSessionFactory ,在利用它獲取一個(gè)SqlSession對(duì)象壁查,這個(gè)SqlSession對(duì)象通過getMapper方法獲取一個(gè)MapperProxy的代理對(duì)象椒惨,并利用代理對(duì)象執(zhí)行增刪改查的邏輯。

String resource = "mapper/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
try{
  BlogMapper mapper = sqlSession.getMapper(XXXX.class)
  mapper.....
}finally{
  sqlSession.close();
}

SqlSessionFactory

SqlSessionFactoryBuilder.build(resource) 的方法

創(chuàng)建SqlSessionFactory階段最重要的就是解析所有內(nèi)容潮罪。第一個(gè)Parser類解析全局配置文件康谆,存入Configuration對(duì)象中领斥。在解析所有的mapper.xml內(nèi)容,將每一個(gè)表示SQL的語句包裝成一個(gè)MappedStatement對(duì)象沃暗,這個(gè)對(duì)象包含了SQL語句的所有信息月洛。并將所有的MappedStatement存放到Configuration中,用一個(gè)全類名Mapper.id的形式(如com.zengg.test.dao.EmployeeMapper.getEmpById)的形式一一對(duì)應(yīng)孽锥,并生成一個(gè)DefaultSqlSessionFactory對(duì)象嚼黔,構(gòu)造器存入Configuration。
此外呢惜辑,Configuration還有一個(gè)屬性MapperRegistry唬涧,這個(gè)里面一個(gè)namespace的接口類對(duì)應(yīng)一個(gè)MapperProxyFactory,相當(dāng)于以后的MapperProxy是用這個(gè)工廠生產(chǎn)的盛撑。

1碎节、首先會(huì)創(chuàng)建一個(gè)XMLConfigBuilder的類對(duì)象,顧名思義抵卫,它的作用是解析全局配置文件的類狮荔,并執(zhí)行解析方法。


2介粘、XMLConfigBuilder.parse()方法中的parseConfiguration(XNode root)方法同根節(jié)點(diǎn)開始殖氏,將所有可能涉及到的配置標(biāo)簽如properties、typeAliases等信息全部封裝到Configuration對(duì)象中姻采,包括Setting里面的值雅采,沒有配置的就使用默認(rèn)值填充

3、然后返回這個(gè)Configuration 對(duì)象并創(chuàng)建一個(gè)new DefaultSqlSessionFactory(config)
到這兒SqlSessionFactory就創(chuàng)建好了慨亲,它只是獲取了全局配置文件的內(nèi)容并新建默認(rèn)對(duì)象DefaultSqlSessionFactory总滩。

SqlSession

SqlSessionFactory.openSession()

這個(gè)階段主要是生成一個(gè)Executor的執(zhí)行器,根據(jù)configuration中的不同的executorType巡雨,生成不一樣的執(zhí)行器(REUSE/SIMPLE(默認(rèn))/BATCH)。如果有緩存席函,再包裝一次成CacheExecutor(實(shí)際還是用之前生成的執(zhí)行器操作铐望,包裝了一層緩存而已),然后將Executor和Configuration作為構(gòu)造器的一部分茂附,生成一個(gè)DefaultSqlSession 對(duì)象

1正蛙、在DefaultSqlSessionFactory類中執(zhí)行openSession()方法,這個(gè)方法首先從全局配置對(duì)象Configuration中獲取Environment標(biāo)簽的信息中的事務(wù)管理器和ExecutorType营曼,并創(chuàng)建一個(gè)重要對(duì)象Executor(執(zhí)行器)乒验,不同的ExecutorType執(zhí)行器類型,會(huì)創(chuàng)建不同的執(zhí)行器蒂阱。

2锻全、如果我們開啟了二級(jí)緩存狂塘,mybatis會(huì)將已經(jīng)創(chuàng)建的執(zhí)行器包裝成一個(gè)新的擴(kuò)展執(zhí)行器對(duì)象CachingExecutor。這個(gè)緩存執(zhí)行器里面的通用的邏輯依然是用的之前創(chuàng)建的執(zhí)行器鳄厌,不過是在外加載了一層緩存相關(guān)處理的方法荞胡。

3、將Configuration了嚎、Executor 封裝創(chuàng)建一個(gè)DefaultSqlSession對(duì)象并返回泪漂。

MapperProxy

sqlSession.getMapper(Class<T> type)

重要的就是使用MapperProxyFactory創(chuàng)建了MapperProxy對(duì)象,對(duì)象里包含了DefaultSqlSession(Executor和configuration)的內(nèi)容
1歪泳、getMapper()方法實(shí)際上是調(diào)用了Configuration的getMapper方法(傳入了sqlSession對(duì)象作為參數(shù))萝勤,再調(diào)用MapperRegistry類對(duì)象去創(chuàng)建。
2呐伞、在MapperReistry類中敌卓,顯示根據(jù)參數(shù)MapperDao的全類名為key,獲取到對(duì)應(yīng)的MapperProxyFactory荸哟,然后在利用這個(gè)MapperProxyFactory新建實(shí)例MapperProxy假哎,這個(gè)MapperProxy就是我們用的代理對(duì)象了。它底層是利用了JDK下的java.lang.reflect包去實(shí)現(xiàn)的鞍历。

執(zhí)行查詢

匹配MappedStatement舵抹,拿到語句的內(nèi)容,為查詢做準(zhǔn)備劣砍。執(zhí)行查詢的邏輯由SqlSession執(zhí)行(包含了Executor和Configuration對(duì)象)
1钟哥、MapperProxy實(shí)現(xiàn)了接口InvocationHandler,它執(zhí)行方法的時(shí)候新進(jìn)入它的invoke()方法给涕。這個(gè)方法中傳入三個(gè)參數(shù)垛叨,分別是proxy對(duì)象、方法接口以及參數(shù)装畅。
?????然后創(chuàng)建一個(gè)MapperMethod對(duì)象并調(diào)用execute方法靠娱。
2、根據(jù)當(dāng)前方法的類型(增刪改查)分別執(zhí)行不同的邏輯


3掠兄、當(dāng)前跟蹤查詢方法像云,不同的返回參數(shù)有不同的MappedStatement執(zhí)行邏輯(分頁、查詢條件)蚂夕,比如說返回值為map迅诬,那么執(zhí)行結(jié)果就是 (SqlSession執(zhí)行查詢)
result = sqlSession.selectList(this.command.getName(), param);
如果返回值就是一個(gè)數(shù),也會(huì)返回一個(gè)集合婿牍,只不過會(huì)再去集合的第一個(gè)值侈贷,因此它們執(zhí)行查詢的邏輯基本相似。

以最下面的selectOne為例(返回值為單個(gè)對(duì)象)等脂,繼續(xù)跟蹤俏蛮。繼續(xù)執(zhí)行DefaultSqlSession的查詢類撑蚌,返回值為List并只取第一個(gè)作為結(jié)果返回。"參數(shù)中statement實(shí)際上就是sql的唯一標(biāo)識(shí)全類名加配置語句的唯一id")

4嫁蛇、利用封裝在DefaultSqlSession中的執(zhí)行器Executor 進(jìn)行查詢邏輯锨并。Executor有兩個(gè)實(shí)現(xiàn)類,一個(gè)是基礎(chǔ)實(shí)現(xiàn)類BaseExecutor睬棚,另外一個(gè)是CachingExecutor緩存執(zhí)行器第煮。這里我進(jìn)入緩存執(zhí)行器查看邏輯。

先回從configuration中對(duì)比傳入的statement參數(shù)抑党,拿到唯一的MappedStatement對(duì)象(這個(gè)對(duì)象封裝了該執(zhí)行語句的所有配置信息)



Executor

1包警、接續(xù)上面的邏輯,SqlSession調(diào)用Executor去執(zhí)行的query的方法底靠,這個(gè)方法第一步就會(huì)生成一個(gè)BoundSql的對(duì)象害晦,這個(gè)對(duì)象的作用應(yīng)該是先對(duì)我們的傳參作一些封裝處理(包含sql語句、傳參暑中、傳參類型等等)壹瘟。然后在創(chuàng)建了一個(gè)為查詢或者保存緩存用的CacheKey對(duì)象,這玩意兒有點(diǎn)長(方法id,sql語句鳄逾,參數(shù)信息等等)稻轨,感覺啥都包含了,就是為了確認(rèn)查詢的唯一性的雕凹。

2殴俱、之后先執(zhí)行檢查緩存中有沒有,沒有的話使用再調(diào)用被CacheExecutor包裝的真正的Executor執(zhí)行查詢
query方法

3枚抵、從本地緩存中拿數(shù)據(jù)(一級(jí)緩存)线欲,沒有的話再重新執(zhí)行查詢

4、后面一直跟蹤到SimpleExecutor的執(zhí)行器的doQuery方法(查詢完了之后的結(jié)果又會(huì)存放在localCache本地緩存中)汽摹。首先定義了一個(gè)JDBC原生的Statemten對(duì)象李丰,也說明了底層就是根據(jù)JDBC完成的。此外逼泣,這個(gè)方法出現(xiàn)了非常重要的第二個(gè)接口對(duì)象StatementHandler(可使用攔截器攔截)趴泌。(注:在創(chuàng)建StatementHandler的時(shí)候,構(gòu)造器中會(huì)默認(rèn)創(chuàng)建另外兩個(gè)重要對(duì)象PrepareHandler和ResultSethandler (BaseStatementHandler 抽象類中實(shí)現(xiàn)的))

StatementHandler ---> RoutingStatementHandler --> 默認(rèn)PreparedStatementHandler

5圾旨、在上圖中,使用prepareStatement()創(chuàng)建Statement對(duì)象中魏蔗,需要先創(chuàng)建鏈接砍的,然后使用RoutingStatementHandler進(jìn)行參數(shù)預(yù)編譯。這個(gè)預(yù)編譯又依賴第三個(gè)特殊對(duì)象PrepareHandler對(duì)象進(jìn)行輔助莺治。 而PrepareHandler 又使用TypeHandler 進(jìn)行參數(shù)的設(shè)置廓鞠。

6帚稠、第四點(diǎn)中的圖片,執(zhí)行最后一步query后床佳,返回的結(jié)果滋早,又需要第四個(gè)非常重要的對(duì)象去處理返回的結(jié)果(方法在PreparedStatementHandler中),同樣也用了TypeHandler輔助執(zhí)行砌们。

文中的四大對(duì)象Executor杆麸、StatementHandler、PrepareHandler和ResultSetHandler 都有一句interceptorChain.pluginAll(target)的方法用于包裝它們浪感,這也是實(shí)現(xiàn)Mybatis的Plugin插件的切入點(diǎn)昔头。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市影兽,隨后出現(xiàn)的幾起案子揭斧,更是在濱河造成了極大的恐慌,老刑警劉巖峻堰,帶你破解...
    沈念sama閱讀 211,948評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件讹开,死亡現(xiàn)場離奇詭異,居然都是意外死亡捐名,警方通過查閱死者的電腦和手機(jī)旦万,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來桐筏,“玉大人纸型,你說我怎么就攤上這事∶芳桑” “怎么了狰腌?”我有些...
    開封第一講書人閱讀 157,490評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長牧氮。 經(jīng)常有香客問我琼腔,道長,這世上最難降的妖魔是什么踱葛? 我笑而不...
    開封第一講書人閱讀 56,521評(píng)論 1 284
  • 正文 為了忘掉前任丹莲,我火速辦了婚禮,結(jié)果婚禮上尸诽,老公的妹妹穿的比我還像新娘甥材。我一直安慰自己,他們只是感情好性含,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,627評(píng)論 6 386
  • 文/花漫 我一把揭開白布洲赵。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪叠萍。 梳的紋絲不亂的頭發(fā)上芝发,一...
    開封第一講書人閱讀 49,842評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音苛谷,去河邊找鬼辅鲸。 笑死,一個(gè)胖子當(dāng)著我的面吹牛腹殿,可吹牛的內(nèi)容都是我干的独悴。 我是一名探鬼主播,決...
    沈念sama閱讀 38,997評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼赫蛇,長吁一口氣:“原來是場噩夢啊……” “哼绵患!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起悟耘,我...
    開封第一講書人閱讀 37,741評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤落蝙,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后暂幼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體筏勒,經(jīng)...
    沈念sama閱讀 44,203評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,534評(píng)論 2 327
  • 正文 我和宋清朗相戀三年旺嬉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了管行。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,673評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡邪媳,死狀恐怖捐顷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情雨效,我是刑警寧澤迅涮,帶...
    沈念sama閱讀 34,339評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站徽龟,受9級(jí)特大地震影響叮姑,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜据悔,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,955評(píng)論 3 313
  • 文/蒙蒙 一传透、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧极颓,春花似錦朱盐、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽骚烧。三九已至,卻和暖如春闰围,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背既峡。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評(píng)論 1 266
  • 我被黑心中介騙來泰國打工羡榴, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人运敢。 一個(gè)月前我還...
    沈念sama閱讀 46,394評(píng)論 2 360
  • 正文 我出身青樓校仑,卻偏偏與公主長得像,于是被迫代替她去往敵國和親传惠。 傳聞我的和親對(duì)象是個(gè)殘疾皇子迄沫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,562評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容