美文网首页Java 杂谈MyBatis+SpringMVC+SpringBoot程序员
SqlSessionFactory构建过程:源码简要分析

SqlSessionFactory构建过程:源码简要分析

作者: BestbpF | 来源:发表于2018-09-20 22:34 被阅读1次

简述

在我们刚学习Mybatis,没有集成Spring时,通常会以下面这种形式来进行SqlSessionFactory的创建

        SqlSessionFactory sqlSessionFactory = null;
        String resource = "mybatis-config.xml";
        InputStream inputStream;
        try {
            inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }

通俗的讲就是使用SqlSessionFactoryBuilder()的build()方法,并传入配置文件来生产SqlSessionFactory,下面我们通过阅读源码简要的了解以下整个流程

流程分析

【SqlSessionFactoryBuilder】

首先直接进入SqlSessionFactoryBuilder的build方法
在SqlSessionFactoryBuilder中,实现了多种不同的build方法,但大致可分为三类

  • 以字符流(Reader)的形式读取配置文件
//核心,其他参数为Reader的方法都会最终指向本方法
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.
      }
    }
  }
  • 以字节流(InputStream)的形式读取配置文件
  //核心,其他参数为InputStream的方法都会最终指向本方法
  public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    try {
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        inputStream.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }
  • 直接以Configuration类实例作为入参
    本方法是最核心的build方法,以上两个方法最终都会指向本方法
  public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
  }

通过上面三段代码我们可以了解到SqlSessionFactory构建的基本流程


流程
  • 可以发现,在构建SqlSessionFactory时,最为重要的还是Configuration的创建
  • 其实我们完全可以通过代码的方式去创建Configuration类的实例对象,然后直接调用public SqlSessionFactory build(Configuration config)方法去创建,但是这样不管是可读性还是修改代码的简易程度都不如XML配置,因此我们选择使用流的方式去读取XML配置文件然后解析为Configuration类
  • 在从流到Configuration的过程中XMLConfigBuilder起到了至关重要的作用
【XMLConfigBuilder】

在SqlSessionFactory的build方法中,通过如下手段产生Configuration类

XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
parser.parse();//parse方法生产Configuration实例对象

我们进入源码查看流程

  public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
    this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
  }

  private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
    super(new Configuration());
    ErrorContext.instance().resource("SQL Mapper Configuration");
    this.configuration.setVariables(props);
    this.parsed = false;
    this.environment = environment;
    this.parser = parser;
  }

  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 {
      Properties settings = settingsAsPropertiess(root.evalNode("settings"));
      //issue #117 read properties first
      propertiesElement(root.evalNode("properties"));
      loadCustomVfs(settings);
      typeAliasesElement(root.evalNode("typeAliases"));
      pluginElement(root.evalNode("plugins"));
      objectFactoryElement(root.evalNode("objectFactory"));
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      reflectionFactoryElement(root.evalNode("reflectionFactory"));
      settingsElement(settings);
      // read it after objectFactory and objectWrapperFactory issue #631
      environmentsElement(root.evalNode("environments"));
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      typeHandlerElement(root.evalNode("typeHandlers"));
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }
  • 大致流程就是XMLConfigBuilder读取配置文件流后,将其转为XPathParser,XPathParser调用parse方法(调用parseConfiguration方法)
  • parseConfiguration中完成了将配置文件中的内容装载到Configuration中,其中调用的各个方法内部最终都会使用configuration.setXXX的形式,将对应属性进行装载

建造者(Builder)模式

在整个SqlSessionFactory构建过程中,我们不难发现,其实就是如下思路

  1. 构建SqlSessionFactory需要构建大量的对象属性,如environments、typeHandlers等等,构建这些内容也异常复杂,因此Mybatis提供了一个配置类Configuration对这些对象来进行统筹规划,分步构建
  2. Configuration中所有内容构建完毕后,调用构造器XMLConfigBuilder和SqlSessionFactoryBuilder进行构造生产SqlSessionFactory
以上的设计模式被称为建造者(Builder)模式,可以将一个产品的内部表象(属性)与产品的生产过程分割开来,从而使一个建造过程生成具有不同的内部表象的产品对象

【如有错误,请指出!O(∩_∩)O谢谢】

相关文章

网友评论

    本文标题:SqlSessionFactory构建过程:源码简要分析

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