MyBatis源碼解析——獲取SqlSessionFactory方式
MyBatis源碼解析_獲取SqlSessionFactory
我們都知道,在Mybatis中,對數據庫的增刪改查,實際上是由SqlSession來操作的,而SqlSession又是從SqlSessionFactory中得到的,那麼問題來瞭,SqlSessonFactory是如何獲得的呢?我們一起來解讀一下Mybatis是如何加載配置文件,從而獲取SqlSessionFactory的。
首先從Resources.getResourceAsReader(path)
傳入我們mybatis全局配置文件得到一個輸入流InputStream,這裡用Reader來接收。然後new一個SqlSessionFactoryBuilder對象,這是幹嘛呢,這個對象裡有一個build(Reader)方法,可以將我們傳入的Reader,經過一系列的解析過程,返回給我們一個SqlSessionFactory實例,這樣我們就得到瞭想要的SqlSessionFactory瞭,估計要是這麼就結束瞭,讀者會不會打死我呀(哈哈)。
所以我們就詳細說一下中間的解析過程。
進入到SqlSessionFactoryBuilder.build(Reader)方法中
它會再次調用build(Reader,environment(默認是null),Properties(默認是null))方法,在這裡,根據我們傳入的參數先new出一個XMLConfigBuilder對象,稱為parser(就是個解析器),然後parser調用它的parse()方法,parse()方法中有一個parseConfiguration(parser.evalNode(“/configuration”))方法,我們知道mybatis的全局配置文件是以configuration作為根節點的,而且各個子節點是有嚴格順序的,這裡就是找到configuration根節點,來分別解析根節點下的每個子節點,然後將解析結果放在一個Configuration中。
解析節點是調用XpathParser.evalNode(root , expression),返回一個XNode,當作參數,放在一個**Element(XNode)方法中去處理節點裡每一個信息。這裡我們選一個mapperElement(root.evalNode(“mappers”))來看看,它是如何解析mappers這個子節點的。
進入到mapperElement(XNode)方法後
先去判斷傳入的節點是否為null,不為null則解析XNode下的每一個孩子節點,(在mappers標簽下,可以插入兩種子節點,一種是package,這種做法,要求接口和xml文檔在同一個包下,另一種是mapper,mapper節點裡有三種屬性,分別是resource,url,class,至多隻能選一種)。
這裡我我們來判斷子節點名字是否為”package”,如果是,將package節點中的name取出,調用Configuration.addMappers(mapperPackage)方法,實際上調用MapperRegistry.addMappers(packeagename)方法,在這裡,又new出瞭一個ResolverUtil<Class<?>>對象resolverUtil,它可以通過find()方法,找到該包下所有的所有的class或是別的文件,然後篩選出所有.class文件(不是class文件不要),如果是接口的話(不是接口不管),new出一個MapperAnnotationBuilder對象parser(實際上也是個解析器),調用parser.parse()方法,加載與接口名相同的XML文件,保存在configuration中。
如果子節點名字不是package
則取出”resource”、”url”、”class”等屬性,分別進行判空,如果屬性resource中有值,先將resource所對應的xml文件給轉成一個InputStream,再new出一個XMLMapperBuilder(inputStream,configuration,resource)對象mapperParser(這裡也是個解析器),調用parse()方法,對接口裡所對應的XML文件去解析,具體解析過程和解析mybatis全局配置文件比較類似。
在解析每一個增刪改查標簽,都會new一個mappedStatement對象statement(這裡是通過它的靜態內部類Builder來new的),相當於一個MappedStatemet就代表瞭一個增刪改查的詳細信息 ,同樣MappedStatement也保存在Configuration中。
對於url中有值,過程和resource那個一樣,這裡不作講述。對於mapperClass中有值,通過全類名反射,拿到對應的接口,調用configuration.addMapper(mapperInterface)方法,具體過程和package那個一樣,也不再講述。
經過一系列的解析,終於完成瞭
mappers節點的所有信息也都保存在Configuration中。這個時候回到SqlSessionFactoryBuilder中,將返回的Configuration對象作為參數,調用它的build(configuration)方法,這裡是關鍵的一步,此時根據configuration,new出瞭一個DefaultSqlSessionFactory對象返回給我們。
我們來看一下DefaultSqlSessionFactory這個類有啥特別的呢,它實現瞭SqlSessionFactory接口,這個接口裡有很多openSession()的重載方法,原來如此,這裡我們終於得到瞭SqlSessionFactory,也就是一個DefaultSqlSessionFactory對象,這個對象裡保存著我們的Configuration,而Configuration裡又保存著我們全局配置文件裡的所有信息,以及**mapper.xml文件裡所有信息。
如圖所示。
好啦,SqlSessionFactory獲取過程就講到這裡啦,想要瞭解更多細節的童鞋,也可以自己去一步步debug,跟蹤源碼,瞭解整個過程
用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; } }
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- 解析Mybatis SqlSessionFactory初始化原理
- MyBatis3源碼解析之如何獲取數據源詳解
- Java MyBatis是如何執行一條SQL語句的
- 基於Mybatis的配置文件入門必看篇
- Mybatis配置之<properties>屬性配置元素解析