mybatis源码学习(三)

mybatis资源加载

上一篇文章介绍了搭建mybatis源码分析的工程,在测试工程里面看到,在进行数据库操作前,必须先加载mybatis的相关资源。
在这里插入图片描述
在start方法里面,首先通过Resources.getResourceAsStream(“myBatis-config.xml”)方法,读取mybatis的全局配置,接着通过SqlSessionFactoryBuilder().build(inputStream)方法生成一个SqlSessionFactory,最后SqlSessionFactory调用openSession()方法生成SqlSession。

public void start(){
   try{
    	//读取myBatis全局配置文件信息把数据源、mapper映射文件等配置信息读取出来
        InputStream inputStream = Resources.getResourceAsStream("myBatis-config.xml");
        //通过SqlSessionFactoryBuilder生成SqlSessionFactory
        SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(inputStream);
        //生成SqlSession
        session=factory.openSession();
    }catch(Exception exception){
        exception.printStackTrace();
    }
}
  1. SqlSessionFactoryBuilder
    在SqlSessionFactoryBuilder里面主要有3种方式构造SqlSessionFactory,第一种是通过InputStream构造,第二种是通过Reader构造,第三种是直接传入org.apache.ibatis.session.Configuration,三种构造方式没有本质上的区别,前面两种是通过类似配置文件的方式构造,第三种方式是先构造了配置类,然后通过配置类构造SqlSessionFactory,前面两种方法最后面在真正执行。
public class SqlSessionFactoryBuilder {
  public SqlSessionFactory build(Reader reader) {
    return build(reader, null, null);
  }
  public SqlSessionFactory build(Reader reader, String environment) {
    return build(reader, environment, null);
  }
  public SqlSessionFactory build(Reader reader, Properties properties) {
    return build(reader, null, properties);
  }
  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.
      }
    }
  }

  public SqlSessionFactory build(InputStream inputStream) {
    return build(inputStream, null, null);
  }

  public SqlSessionFactory build(InputStream inputStream, String environment) {
    return build(inputStream, environment, null);
  }

  public SqlSessionFactory build(InputStream inputStream, Properties properties) {
    return build(inputStream, null, properties);
  }

  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.
      }
    }
  }
    
  public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
  }
  1. XMLConfigBuilder,在SqlSessionFactoryBuilder中,首先创建XMLConfigBuilder对象,这个对象是专门解析MyBatis配置类用的,构造函数如下:
public XMLConfigBuilder(Reader reader, String environment, Properties props) {
	this(new XPathParser(reader, true, props, new XMLMapperEntityResolver()), environment, props);
}

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

从上面可以看出,其实不管是传入的是Reader还是传入的是InputStream,两者都是用来创建XPathParser对象的,因此正如上面说的,传入两者没什么区别。刚才的测试类的start方法中,创建SqlSessionFactoryBuilder的时候,在执行build方法的时候,只传进去了InputStream因此这里的environment和props两个参数都是空

SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(inputStream);

在创建XMLConfigBuilder的时候,先创建XPathParser对象

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

在创建XPathParser的时候,传入4个参数配置文件的流,true,props以及新创建的XMLMapperEntityResolver对象

  public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
    commonConstructor(validation, variables, entityResolver);
    this.document = createDocument(new InputSource(inputStream));
  }
  private void commonConstructor(boolean validation, Properties variables, EntityResolver entityResolver) {
    this.validation = validation;
    this.entityResolver = entityResolver;
    this.variables = variables;
    XPathFactory factory = XPathFactory.newInstance();
    this.xpath = factory.newXPath();
  }
  private Document createDocument(InputSource inputSource) {
    // important: this must only be called AFTER common constructor
    try {
      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
      factory.setValidating(validation);

      factory.setNamespaceAware(false);
      factory.setIgnoringComments(true);
      factory.setIgnoringElementContentWhitespace(false);
      factory.setCoalescing(false);
      factory.setExpandEntityReferences(true);

      DocumentBuilder builder = factory.newDocumentBuilder();
      builder.setEntityResolver(entityResolver);
      builder.setErrorHandler(new ErrorHandler() {
        @Override
        public void error(SAXParseException exception) throws SAXException {
          throw exception;
        }

        @Override
        public void fatalError(SAXParseException exception) throws SAXException {
          throw exception;
        }

        @Override
        public void warning(SAXParseException exception) throws SAXException {
        }
      });
      return builder.parse(inputSource);
    } catch (Exception e) {
      throw new BuilderException("Error creating document instance.  Cause: " + e, e);
    }
  }

从上面的代码可以看到,在SqlSessionFactoryBuilder创建XMLConfigBuilder的时候,只是把配置文件初始化到对象里面,此时还没对配置文件进行解析。接着,执行return build(parser.parse());代码对配置文件进行解析。
在parser.parse()方法中,即调用的是XMLConfigBuilder的parse()方法

 public Configuration parse() {
  if (parsed) {
     throw new BuilderException("Each XMLConfigBuilder can only be used once.");
   }
   parsed = true;
   parseConfiguration(parser.evalNode("/configuration"));
   return configuration;
 }

在parse方法里面通过调用parseConfiguration(parser.evalNode("/configuration"))方法初始化配置信息,这里传入的参数是配置文件里面configuration这个节点的信息。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值