MyBatis源碼解析——獲取SqlSessionFactory方式
MyBatis源碼解析_獲取SqlSessionFactory
我們都知道,在Mybatis中,對(duì)數(shù)據(jù)庫(kù)的增刪改查,實(shí)際上是由SqlSession來(lái)操作的,而SqlSession又是從SqlSessionFactory中得到的,那么問(wèn)題來(lái)了,SqlSessonFactory是如何獲得的呢?我們一起來(lái)解讀一下Mybatis是如何加載配置文件,從而獲取SqlSessionFactory的。
首先從Resources.getResourceAsReader(path)
傳入我們mybatis全局配置文件得到一個(gè)輸入流InputStream,這里用Reader來(lái)接收。然后new一個(gè)SqlSessionFactoryBuilder對(duì)象,這是干嘛呢,這個(gè)對(duì)象里有一個(gè)build(Reader)方法,可以將我們傳入的Reader,經(jīng)過(guò)一系列的解析過(guò)程,返回給我們一個(gè)SqlSessionFactory實(shí)例,這樣我們就得到了想要的SqlSessionFactory了,估計(jì)要是這么就結(jié)束了,讀者會(huì)不會(huì)打死我呀(哈哈)。
所以我們就詳細(xì)說(shuō)一下中間的解析過(guò)程。
進(jìn)入到SqlSessionFactoryBuilder.build(Reader)方法中
它會(huì)再次調(diào)用build(Reader,environment(默認(rèn)是null),Properties(默認(rèn)是null))方法,在這里,根據(jù)我們傳入的參數(shù)先new出一個(gè)XMLConfigBuilder對(duì)象,稱為parser(就是個(gè)解析器),然后parser調(diào)用它的parse()方法,parse()方法中有一個(gè)parseConfiguration(parser.evalNode("/configuration"))方法,我們知道m(xù)ybatis的全局配置文件是以configuration作為根節(jié)點(diǎn)的,而且各個(gè)子節(jié)點(diǎn)是有嚴(yán)格順序的,這里就是找到configuration根節(jié)點(diǎn),來(lái)分別解析根節(jié)點(diǎn)下的每個(gè)子節(jié)點(diǎn),然后將解析結(jié)果放在一個(gè)Configuration中。
解析節(jié)點(diǎn)是調(diào)用XpathParser.evalNode(root , expression),返回一個(gè)XNode,當(dāng)作參數(shù),放在一個(gè)**Element(XNode)方法中去處理節(jié)點(diǎn)里每一個(gè)信息。這里我們選一個(gè)mapperElement(root.evalNode("mappers"))來(lái)看看,它是如何解析mappers這個(gè)子節(jié)點(diǎn)的。
進(jìn)入到mapperElement(XNode)方法后
先去判斷傳入的節(jié)點(diǎn)是否為null,不為null則解析XNode下的每一個(gè)孩子節(jié)點(diǎn),(在mappers標(biāo)簽下,可以插入兩種子節(jié)點(diǎn),一種是package,這種做法,要求接口和xml文檔在同一個(gè)包下,另一種是mapper,mapper節(jié)點(diǎn)里有三種屬性,分別是resource,url,class,至多只能選一種)。
這里我我們來(lái)判斷子節(jié)點(diǎn)名字是否為"package",如果是,將package節(jié)點(diǎn)中的name取出,調(diào)用Configuration.addMappers(mapperPackage)方法,實(shí)際上調(diào)用MapperRegistry.addMappers(packeagename)方法,在這里,又new出了一個(gè)ResolverUtil<Class<?>>對(duì)象resolverUtil,它可以通過(guò)find()方法,找到該包下所有的所有的class或是別的文件,然后篩選出所有.class文件(不是class文件不要),如果是接口的話(不是接口不管),new出一個(gè)MapperAnnotationBuilder對(duì)象parser(實(shí)際上也是個(gè)解析器),調(diào)用parser.parse()方法,加載與接口名相同的XML文件,保存在configuration中。
如果子節(jié)點(diǎn)名字不是package
則取出"resource"、"url"、"class"等屬性,分別進(jìn)行判空,如果屬性resource中有值,先將resource所對(duì)應(yīng)的xml文件給轉(zhuǎn)成一個(gè)InputStream,再new出一個(gè)XMLMapperBuilder(inputStream,configuration,resource)對(duì)象mapperParser(這里也是個(gè)解析器),調(diào)用parse()方法,對(duì)接口里所對(duì)應(yīng)的XML文件去解析,具體解析過(guò)程和解析mybatis全局配置文件比較類似。
在解析每一個(gè)增刪改查標(biāo)簽,都會(huì)new一個(gè)mappedStatement對(duì)象statement(這里是通過(guò)它的靜態(tài)內(nèi)部類Builder來(lái)new的),相當(dāng)于一個(gè)MappedStatemet就代表了一個(gè)增刪改查的詳細(xì)信息 ,同樣MappedStatement也保存在Configuration中。
對(duì)于url中有值,過(guò)程和resource那個(gè)一樣,這里不作講述。對(duì)于mapperClass中有值,通過(guò)全類名反射,拿到對(duì)應(yīng)的接口,調(diào)用configuration.addMapper(mapperInterface)方法,具體過(guò)程和package那個(gè)一樣,也不再講述。
經(jīng)過(guò)一系列的解析,終于完成了
mappers節(jié)點(diǎn)的所有信息也都保存在Configuration中。這個(gè)時(shí)候回到SqlSessionFactoryBuilder中,將返回的Configuration對(duì)象作為參數(shù),調(diào)用它的build(configuration)方法,這里是關(guān)鍵的一步,此時(shí)根據(jù)configuration,new出了一個(gè)DefaultSqlSessionFactory對(duì)象返回給我們。
我們來(lái)看一下DefaultSqlSessionFactory這個(gè)類有啥特別的呢,它實(shí)現(xiàn)了SqlSessionFactory接口,這個(gè)接口里有很多openSession()的重載方法,原來(lái)如此,這里我們終于得到了SqlSessionFactory,也就是一個(gè)DefaultSqlSessionFactory對(duì)象,這個(gè)對(duì)象里保存著我們的Configuration,而Configuration里又保存著我們?nèi)峙渲梦募锏乃行畔?,以?*mapper.xml文件里所有信息。
如圖所示。
好啦,SqlSessionFactory獲取過(guò)程就講到這里啦,想要了解更多細(xì)節(jié)的童鞋,也可以自己去一步步debug,跟蹤源碼,了解整個(gè)過(guò)程
用MyBatis的配置文件獲取SqlSessionFactory
import java.io.IOException; import java.io.Reader; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; public class GetSqlSessionFactory { private static SqlSessionFactory sqlSessionFactory; static{ String rs="mybatis-config.xml"; try { Reader reader=Resources.getResourceAsReader(rs); SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder(); sqlSessionFactory=builder.build(reader); //sqlSessionFactory.getConfiguration().addMappers("com.hengtian.mapper"); } catch (IOException e) { e.printStackTrace(); } } public static SqlSessionFactory getInstance(){ return sqlSessionFactory; } }
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- 解析Mybatis SqlSessionFactory初始化原理
- mybatis初始化SqlSessionFactory失敗的幾個(gè)原因分析
- 使用Mybatis-Plus時(shí)的SqlSessionFactory問(wèn)題及處理
- Mybatis SqlSessionFactory與SqlSession詳細(xì)講解
- 詳解Mybatis核心類SqlSessionFactory的構(gòu)建
- Mybatis中自定義實(shí)例化SqlSessionFactoryBean問(wèn)題
- MyBatis-plus報(bào)錯(cuò)Property ‘sqlSessionFactory‘ or ‘sqlSessionTemplate‘ are required的解決方法
- 使用Mybatis時(shí)SqlSessionFactory對(duì)象總是報(bào)空指針
相關(guān)文章
Spring?Native打包本地鏡像的操作方法(無(wú)需通過(guò)Graal的maven插件buildtools)
這篇文章主要介紹了Spring?Native打包本地鏡像,無(wú)需通過(guò)Graal的maven插件buildtools,本文探索一下,如果不通過(guò)這個(gè)插件來(lái)生成鏡像,結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-02-02visual studio 2019安裝配置可編寫(xiě)c/c++語(yǔ)言的IDE環(huán)境
這篇文章主要介紹了visual studio 2019安裝配置可編寫(xiě)c/c++語(yǔ)言的IDE環(huán)境,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03Maven腳手架如何基于jeecg實(shí)現(xiàn)快速開(kāi)發(fā)
這篇文章主要介紹了Maven腳手架如何基于jeecg實(shí)現(xiàn)快速開(kāi)發(fā),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10springboot帶有進(jìn)度條的上傳功能完整實(shí)例
這篇文章主要介紹了springboot帶有進(jìn)度條的上傳功能,結(jié)合完整實(shí)例形式分析了springboot帶進(jìn)度條上傳的原理、實(shí)現(xiàn)步驟與相關(guān)操作技巧,需要的朋友可以參考下2019-11-11一篇文章了解Jackson注解@JsonFormat及失效解決辦法
這篇文章主要給大家介紹了關(guān)于如何通過(guò)一篇文章了解Jackson注解@JsonFormat及失效解決辦法的相關(guān)資料,@JsonFormat注解是一個(gè)時(shí)間格式化注解,用于格式化時(shí)間,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-11-11Java實(shí)現(xiàn)圖片上傳至服務(wù)器功能(FTP協(xié)議)
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)圖片上傳至服務(wù)器功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-06-06maven引入kabeja依賴的實(shí)現(xiàn)步驟
本文主要介紹了maven引入kabeja依賴的實(shí)現(xiàn)步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-09-09