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中ApplicationEventPublisher發(fā)布訂閱模式的實(shí)現(xiàn)
本文主要介紹了Spring中ApplicationEventPublisher發(fā)布訂閱模式的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07
mybatis高級(jí)映射一對(duì)多查詢實(shí)現(xiàn)代碼
本篇文章主要介紹了mybatis高級(jí)映射一對(duì)多查詢實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-04-04
SpringCloudAlibaba微服務(wù)調(diào)用組件OpenFeign的方法
Feign是Netflix開發(fā)的聲明式、模板化的HTTP客戶端,其靈感來(lái)自Retrofit、JAXRS-2.0以及WebSocket,Feign可幫助我們更加便捷、優(yōu)雅地調(diào)用HTTP API,這篇文章主要介紹了SpringCloudAlibaba微服務(wù)調(diào)用組件OpenFeign,需要的朋友可以參考下2024-07-07
Spring 整合 MyBatis的實(shí)現(xiàn)步驟
SpringMVC 本來(lái)就是 Spring 框架的一部分,這兩者無(wú)須再做整合,所以 SSM 整合的關(guān)鍵就是Spring對(duì)MyBatis的整合,三大框架整合完成后,將以 Spring 為核心,調(diào)用有關(guān)資源,高效運(yùn)作,這篇文章主要介紹了 Spring 整合 MyBatis的實(shí)現(xiàn)步驟,需要的朋友可以參考下2023-02-02
JDK?version和class?file?version(Class編譯版本號(hào))對(duì)應(yīng)關(guān)系解讀
這篇文章主要介紹了JDK?version和class?file?version(Class編譯版本號(hào))對(duì)應(yīng)關(guān)系,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07
SpringBoot關(guān)于List集合的校驗(yàn)方式
這篇文章主要介紹了SpringBoot關(guān)于List集合的校驗(yàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07

