美文网首页
MyBatis源码阅读(二)创建SqlSessionFactor

MyBatis源码阅读(二)创建SqlSessionFactor

作者: 竹本辰 | 来源:发表于2018-10-28 16:01 被阅读0次

接上一篇文章
https://www.jianshu.com/p/0f0408e3c02f

把测试类贴过来,方便阅读

import com.xingchen.mybatis.entity.Country;
import com.xingchen.mybatis.mapper.CountryMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.Reader;
import java.util.List;

/**
 * @author chen
 * @Date 2018/10/24
 * mybatis 源码阅读
 * */
public class MyTest {
    private static SqlSessionFactory sqlSessionFactory=null;

    static {
        try{
            Reader reader= Resources.getResourceAsReader("mybatis/mybatis-config.xml");
            sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader);
            reader.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        SqlSession sqlSession=sqlSessionFactory.openSession();
        try {
            CountryMapper countryMapper=sqlSession.getMapper(CountryMapper.class);
            List<Country> countries=countryMapper.selectAll();
            for(Country country:countries){
                System.out.println(country);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            sqlSession.close();
        }
    }
}

首先是SqlSessionFactory的创建

SqlSessionFactoryMyBatis的核心类之一,其最重要对的功能就是提供创建MyBatis的核心接口SqlSession,所以需要首先创建SqlSessionFactory,为此我们需要提供配置文件和相关参数。而MyBatis是一个复杂的系统,采用建造者模式去创建SqlSessionFactory,可以通过SqlSessionFactoryBuilder去创建。主要分为两步:

  • 第一步,通过XMLConfigBuilder解析XML配置文件,读取配置参数,并将读取的数据存入Configuration类中。

    MyBatis几乎所有的配置都是存在这里。

  • 第二步,使用Configuration对象去构建SqlSessionFactoryMyBatisSqlSessionFactory是一个接口,而不是一个实现类,不能实例化。因此MyBatis提供了一个默认的SqlSessionFactory实现类DefaultSqlSessionFactory。大部分情况下,我们都没有必要去创建新的SqlSessionFactory

SqlSessionFactory是通过SqlSessionFactoryBuilderbuild()方法来创建的,从名字中很明显看的出这里用到了建造者模式。

下面就看看build()是如何创建SqlSessionFactory

public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
    try {
        XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
        return build(parser.parse());
    } catch (Exception e) {
        throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
        ErrorContext.instance().reset();
        try {
            reader.close();
        } catch (IOException e) {
            // Intentionally ignore. Prefer previous error.
        }
    }
}

build()方法先创建了一个XMLConfigBuilder,从名字不难看出来这是个解析XML配置文件的类。我们来看看parser的创建过程。

public class XMLConfigBuilder extends BaseBuilder {
    ...
    public XMLConfigBuilder(Reader reader, String environment, Properties props) {
    // 这个this是真正执行创建XMLConfigBuilder的方法
    this(new XPathParser(reader, true, props, new XMLMapperEntityResolver()), environment, props);
    }
    ...
}

对的就是下面这个方法。先初始化初始化Configuration对象,然后设置一些属性,最终创建了XMLConfigBuilder对象。

private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
    // 执行父类的构造方法,初始化Configuration 对象
    super(new Configuration());
    ErrorContext.instance().resource("SQL Mapper Configuration");
    this.configuration.setVariables(props);
    this.parsed = false;
    this.environment = environment;
    this.parser = parser;
}

SqlSessionFactory构建中,Configuration是重要的,MyBatis的配置信息都会来源于次。作用如下:

  • 读入配置文件,包括基础配置的XML文件和映射器的XML文件。
  • 初始化基础配置,比如MyBatis的别名等,一些重要的类对象,例如,插件、映射器、ObjectFactory和typeHandle对象。
  • 提供单例,为后续创建SessionFactory服务并提供配置的参数。
  • 执行一些重要的对象方法,初始化配置信息。

初始化Configuration对象的时候,将一些别名注册到typeAliasRegistry容器中。如下:

// Configuration类 无参构造方法
public Configuration() {
    typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
    typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);

    typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
    typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
    typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);

    ···
}

获取到了 XMLConfigBuilder对象之后,则进入了下一步的处理parser.parse()解析配置文件。

// XMLConfigBuilder 类
// 我们来看看这个这个parser.parse()到底干了什么
// 注意这个方法的返回对象 是Configuration 类对象
public Configuration parse() {
    if (parsed) {
        throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    parsed = true;
    // 调用这个方法,解析配置文件
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
}

/**
 * 解析配置文件
 * 这里面可以看到配置文件中的一些标签,都是在这里进行解析的。
 * 解析过程不算复杂,而且解析的方法都很类似。
 */
private void parseConfiguration(XNode root) {
    try {
        //issue #117 read properties first
        propertiesElement(root.evalNode("properties"));
        Properties settings = settingsAsProperties(root.evalNode("settings"));
        loadCustomVfs(settings);
        typeAliasesElement(root.evalNode("typeAliases"));
        pluginElement(root.evalNode("plugins"));
        objectFactoryElement(root.evalNode("objectFactory"));
        objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
        reflectorFactoryElement(root.evalNode("reflectorFactory"));
        settingsElement(settings);
        // read it after objectFactory and objectWrapperFactory issue #631
        environmentsElement(root.evalNode("environments"));
        databaseIdProviderElement(root.evalNode("databaseIdProvider"));
        typeHandlerElement(root.evalNode("typeHandlers"));
        // 解析mapper配置文件
        // 将mapper配置存储到Configuration的MapperRegistry容器中  
        mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
        throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
}

执行完parser.parse()之后,则得到了一个Configuration对象接着执行

return build(parser.parse());

来看看这个SqlSessionFactoryBuilderbuild() 方法。

public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
}

前面有提到由于SqlSessionFactory是一个接口,而这里需要返回一个SqlSessionFactory的实例对象,所以这个方法最终创建了一个DefaultSqlSessionFactory对象作为返回结果。到此为止,SqlSessionFactory创建完成。

接下一篇《SqlSession的创建和运行》
https://www.jianshu.com/p/04af4b3cc459

相关文章

网友评论

      本文标题:MyBatis源码阅读(二)创建SqlSessionFactor

      本文链接:https://www.haomeiwen.com/subject/qkzptqtx.html