背景
最近,聽到很多吐槽:看到源碼,心中就感到十分糾結、特別煩惱。
為什麼糾結?
因為面試的時候,面試官很喜歡問:你看過什麼框架源碼?JDK源碼也行。
這時候,如果回答沒有看過,雖然沒讓你立馬回去等通知。但也許,你在面試官心中的印象就大打折扣了。
如果回答看過,並且還能較為流利地說上一番,那面試官或許會在心裡讚嘆:小夥子可以呀!(PS:很多面試官自己也沒看過,或者看過很多也忘了)。
總之,你要是能說上個123,那給面試官的印象就會槓槓滴好。何愁工作?何愁加薪?
為什麼煩?
大部分人的情況是:源碼不是沒有看過,而是每次只看得下一部分。為什麼只看得下一部分呢?通常有下面三種原因:
缺乏技術支撐。看源碼是需要技術支撐的,不是隨便一個小白也能看懂的。沒有一些技術支撐,你頂多看看一小段,然後就看不下去,於是就放棄了。缺乏正確心態。看源碼確實挺無聊的,如果大家心態沒放好,把它當做一種任務去做,肯定覺得無聊,而且很容易放棄。缺乏足夠時間。確實很忙,經常看了一部分後,天天加班,沒時間看,忙完後又忘了之前正在看的某某源碼。個人建議
對於一般java程式設計師來說,閱讀源碼之前到底需要些什麼技能呢?
個人建議,以下基礎知識必須會一些:
會設計模式:包括單例模式、工廠模式、代理模式、裝飾器模式、責任鏈模式、模板方法模式等。
會猜測:大膽的猜測,在看源碼的時候,多站在高層次想想,如果你是Mybatis的設計者,你會怎麼設計?
會挑重點看:別被沒寫參數校驗、類型校驗等問題卡在那裡。
會畫圖:流程圖、類圖等,找一些在線畫圖工具,媒體畫完就保存下來,如果中途一段時間不看了,再回頭看看這些圖,也能快速繼續。
Mybatis源碼分析
今天,我們就來看看Mybatis源碼的閱讀,具體舉個例子來看看:
案例和疑問
從我們最初的demo中開始:
publicstaticvoidmain(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(); } }
關於獲取數據流inputStream,這個我們就不討論了,我們主要關注重點。
對於上面demo,我們可以分成五個步驟:
第一步,創建一個工廠類sqlSessionFactory。
配置文件的解析就是在這裡完成的。包括mybatis-config.xml和我們的Mapper.xml映射器文件。這一步我們關心的內容是:解析的時候做了什麼?產生了什麼對象,解析的結果放在哪裡的。因為這將意味著,我們後面使用的時候去哪裡獲取這項配置項內容。
第二步,通過SqlSessionFactory創建一個SqlSession。
那麼問題來了,SqlSession中定義了各種增刪改查的API,是給客戶端調用,返回的是什麼實現類?除了SqlSession以外,我們還創建了什麼對象,創建了什麼環境?
第三步,獲取到一個Mapper對象。
問題來了UserMapper.java是一個接口,並沒有為它創建實現類,那又是怎麼被實例化的呢?我們使用的這個Mapper對象到底是什麼對象呢?為什麼要從SqlSession裡去獲取呢?為什麼傳進去一個接口,然後還要用一個接口去接收呢?
第四步,調用接口方法。
問題是我們的接口沒有實現類,為什麼就可以直接調用它的方法呢?那它調用的是誰的方法呢?是如何把SQL給關聯起來的呢?是如何獲取到數據的呢?
第五步,關閉相關資源。
開始源碼分析過程
由於涉及到內容較多,下面就用幾張圖來展示整個流程。我們可以通過這幾張圖來快速翻閱Mybatis的源碼。
第一步
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
這一句代碼的整個流程如下:
根據inputStream,解析配置文件,創建出一個DefaultSqlSessionFactory默認的SqlSessionFactory 實現類。構建出一個工廠類,這個工廠類專門用來創建SqlSession對象的。
第二步
SqlSession sqlSession = sqlSessionFactory.openSession();
獲取SqlSession的整個流程如下:
第三步
User user = sqlSession.selectOne("com.tian.mybatis.mapper.UserMapper.selectById", 1);
第三步和第四步就是這行代碼畫的。
這一步是返回一個映射器代理類,映射器代理類專門用來給UserMapper接口和UserMapper.xml綁定的代理類。創建出來的代理類就可以實例化了,然後就可以調用UserMapper接口的方了。
第四步:調用代理對象執行SQL的整個過程。
第五步,關閉資源。
希望大家按照這個流程,找點源碼看看。聽別人的看別人永遠是別人的。
動起來吧!
總結
其實,沒什麼好總結的。好好領悟一下為什麼糾結吧!同時希望能看看我的建議,作為一個過來人,希望能幫助大家少走彎路。
最後,對於Mybatis源碼閱讀的整個流程,最好是本地環境搭起來,然後搞個demo,debug模式一步一步走起。