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;
    }    
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持云海天教程。