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。

推薦閱讀: