mybatis底層源碼
一、運(yùn)行原理

二、配置文件的解析以及創(chuàng)建SqlSessionFactory
首先通過配置文件的文件流創(chuàng)建SqlSessionFactoryBuilder對象

調(diào)用build方法,傳入文件流

之后通過解析器解析xml配置文件

通過XPathParse解析configuration節(jié)點(diǎn),獲取根節(jié)點(diǎn),之后再parseConfiguration()方法中根據(jù)根節(jié)點(diǎn)解析根節(jié)點(diǎn)中的每一個(gè)節(jié)點(diǎn)


之后來到settingsElement()方法中

environmentsElement(root.evalNode("environments"))獲取數(shù)據(jù)源配置被放到了Configuration里面

解析mappers.xml配置文件

兩種方式
我們看看配置文件里面mappers標(biāo)簽是怎么配置的,官方給出了四種配置方式:
1、Mapper.xml文件的相對路徑引用(解析XML獲取SQL)
2、Mapper.xml文件的絕對路徑引用(解析XML獲取SQL)
3、Mapper.java類文件的完全限定類名(解析注解獲取SQL)
4、Mapper.java類文件所在的包路徑(解析注解獲取SQL)

既然配置有4種配置方法,那對應(yīng)的解析的時(shí)候也有4種解析方法:
XMLConfigBuilder.mapperElement

XMLMapperBuilder.parse()獲取mapper配置節(jié)點(diǎn)

解析mapper文件中的節(jié)點(diǎn)

之后調(diào)用XbuildStatementFromContext()方法,對所有的crud配置節(jié)點(diǎn),進(jìn)行解析

循環(huán)解析所有crud節(jié)點(diǎn)

解析并獲取所有crud節(jié)點(diǎn)的屬性

最后將所有的屬性值加入到一個(gè)MappedStatement中,封裝成MappedStatement,所以每一個(gè)MappedStatement表示一個(gè)crud的SQL語句詳細(xì)信息

然后將每一個(gè)MappedStatement添加到MappedStatements集合中,最后加入configuration,到此,configuration就填充完畢,其中保存了所有的配置信息(全局配置文件及sql映射文件)

通過configuration創(chuàng)建DefaultSqlSessionFactory

總結(jié):就是將所有的配置文件信息保存在configuration中,通過configuration對象創(chuàng)建SqlSessionFactory
三、SqlSession對象的創(chuàng)建
通過SqlSessionFactory的openSession獲取sqlSession

首先通過configuration.getDefaultExecutorType()獲取執(zhí)行器類型,默認(rèn)為SIMPLE

之后又來到openSessionFromDataSource()方法

創(chuàng)建了一個(gè)Executor對象,來到newExecutor()方法

Executor是一個(gè)接口,用來執(zhí)行crud的

是否配置了二級緩存,如果配置了使用CachingExecutor對Executor包裝,實(shí)際執(zhí)行crud還是Executor

包裝后的Executor在查詢之前會(huì)有緩存操作,Executor創(chuàng)建完畢后

會(huì)調(diào)用連接器鏈對executor進(jìn)行一個(gè)拼裝

循環(huán)所有的攔截器重新包裝Executor,并返回

將創(chuàng)建好的Executor對象傳入DefaultSqlSession中,DefaultSqlSession是SQLSession的實(shí)現(xiàn)類,
可以看出DefaultSqlSession中也包含了全局配置文件configuration的數(shù)據(jù),最終執(zhí)行crud還是Executor
總結(jié):創(chuàng)建Executor對象及DefaultSqlSession對象,注意如果有二級緩存會(huì)包裝Executor,其中還會(huì)使用攔截器鏈包裝Executor
四、獲取Mapper的代理對象
通過getMapper獲取mapper

最終調(diào)用configuration的getMapper方法

又調(diào)用mapperRegistry的getMapper方法

mapperRegistry中保存了每一個(gè)mapper對應(yīng)的MapperProxyFactory

根據(jù)接口類型獲取mapperProxyFactory,通過mapperProxyFactory創(chuàng)建代理對象

首先創(chuàng)建一個(gè)mapperProxy對象,在調(diào)用newInstance方法

MapperProxy實(shí)現(xiàn)InvocationHandler接口,這個(gè)是JDK做動(dòng)態(tài)代理需要傳入的對象

之后就是通過JDK代理創(chuàng)建代理對象并返回,代理對象中包含了sqlSession,可以用來執(zhí)行crud
總結(jié):mapperProxyFactory在configuration初始化完畢后,一個(gè)mapper就綁定一個(gè)mapperProxyFactory,
通過mapperProxyFactory創(chuàng)建mapperProxy代理對象,代理對象中保存sqlSession對象,sqlSession中包含類Executor對象,用來執(zhí)行crud
五、代理對象執(zhí)行增刪改查
調(diào)用代理的目標(biāo)方法時(shí),會(huì)先執(zhí)行invoke()方法

先判斷執(zhí)行的方法是否是Object中的方法,否則就將方法包裝為一個(gè)MapperMethod,最后執(zhí)行其execute方法,傳入sqlSession及方法參數(shù)

判斷sql語句的類型,我這里是查詢

我這里返回對象進(jìn)入else流程,convertArgsToSqlCommandParam在解析參數(shù),單個(gè)參數(shù)直接返回,多個(gè)參數(shù)返回一個(gè)map,之后調(diào)用SqlSession的selectOne方法

調(diào)用selectList查詢多個(gè)方法

從configuration中通過方法id獲取MappedStatement(就是configuration初始化時(shí)用來執(zhí)行crud的),之后調(diào)用executor的query方法,
wrapCollection(parameter)是根據(jù)參數(shù)將其包裝為一個(gè)map,map中存放數(shù)據(jù)

現(xiàn)獲取綁定的sql

BoundSql中封裝了所有的sql信息,包括sql語句,參數(shù),參數(shù)映射關(guān)系,之后就是創(chuàng)建二級緩存中保存的key,之后就調(diào)用query方法

如果配置二級緩存先獲取緩存,之后調(diào)用query方法,就是SimpleExecutor的query方法

先從一級緩存中查詢獲取,這就印證了mybatis先查詢二級緩存,在查詢一級緩存,如果一級緩存中也沒有就執(zhí)行queryFromDatabase方法

調(diào)用doQuery()查詢數(shù)據(jù),查詢出數(shù)據(jù)后又加入到本地緩存中

首先聲明一個(gè)Statement對象,原生JDBC對象,在獲取configuration,在通過newStatementHandler創(chuàng)建StatementHandler對象,StatementHandler可以創(chuàng)建出Statement對象

首先創(chuàng)建一個(gè) RoutingStatementHandler

根據(jù)配置創(chuàng)建不同的Statement,默認(rèn)PREPARED,所以創(chuàng)建出一個(gè)PreparedStatementHandler,保存在RoutingStatementHandler中,
之后又將statementHandler包裝在攔截器鏈中,之后調(diào)用prepareStatement(handler, ms.getStatementLog())方法創(chuàng)建Statement

在prepareStatement中有對參數(shù)進(jìn)行預(yù)編譯

調(diào)用parameterHandler進(jìn)行參數(shù)預(yù)編譯設(shè)置參數(shù),創(chuàng)建PreparedStatementHandler對象時(shí)創(chuàng)建parameterHandler及resultSetHandler,在創(chuàng)建這兩個(gè)對象時(shí),
又將其包裝到攔截器鏈中,至此mybatis的四大對象(Executor,StatementHandler,parameterHandler,resultSetHandler)就全部創(chuàng)建完畢,調(diào)用setParameters設(shè)置參數(shù)

調(diào)用TypeHandler給sql語句預(yù)編譯設(shè)置參數(shù),參數(shù)設(shè)置完畢就調(diào)用handler.

通過resultSetHandler處理結(jié)果

最后通過typeHandler.getResult(rs, column)返回結(jié)果
總結(jié):先通過代理mapper對象,實(shí)際執(zhí)行crud是使用sqlSession,sqlSession又是使用executor執(zhí)行的,executor在執(zhí)行crud時(shí),
會(huì)創(chuàng)建StatementHandler,StatementHandler就是用來處理(預(yù)編譯,設(shè)置參數(shù)等)sql語句,
StatementHandler創(chuàng)建時(shí)創(chuàng)建了parameterHandler及resultSetHandler,
parameterHandler設(shè)置參數(shù)等等工作,并且執(zhí)行sql語句,
resultSetHandler是用來處理查詢后的結(jié)果,
parameterHandler及resultSetHandler執(zhí)行時(shí)都會(huì)有一個(gè)TypeHandler做設(shè)置參數(shù)及獲取結(jié)果映射為javaBean,TypeHandler底層是使用JDBC操作的
六、運(yùn)行流程總結(jié)
-
根據(jù)配置文件(全局文件及sql映射文件)初始化出Configuration
-
創(chuàng)建DefaultSqlSession對象,其中包括Configuration及Executor(根據(jù)全局配置文件中的defaultExecutorType進(jìn)行初始化)
-
DefaultSqlSession或Mapper接口對應(yīng)的MapperProxy,MapperProxy包含DefaultSqlSession
-
執(zhí)行增刪改查方法,代理對象調(diào)用DefaultSqlSession(Executor)的CRUD,創(chuàng)建一個(gè)Statement對象,同時(shí)創(chuàng)建StatementHandler,創(chuàng)建StatementHandler同時(shí)也會(huì)創(chuàng)建出parameterHandler及resultSetHandler,調(diào)用StatementHandler(parameterHandler)的預(yù)編譯參數(shù)及設(shè)置參數(shù)值,在調(diào)用StatementHandler的CRUD方法,使用resultSetHandler封裝結(jié)果
-
四大對象每個(gè)創(chuàng)建時(shí)都有一個(gè)攔截器鏈的步驟,這一步在mybatis的插件中有用。

浙公網(wǎng)安備 33010602011771號