mybatis源码学习(三)

本文详细解析了MyBatis框架中资源加载的过程,包括如何读取全局配置文件myBatis-config.xml,通过SqlSessionFactoryBuilder生成SqlSessionFactory,以及创建SqlSession进行数据库操作。深入探讨了XMLConfigBuilder和XPathParser在配置解析中的作用。
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这个节点的信息。

根据原作 https://pan.quark.cn/s/0ed355622f0f 的源码改编 野火IM解决方案 野火IM是专业级即时通讯和实时音视频整体解决方案,由北京野火无限网络科技有限公司维护和支持。 主要特性有:私有部署安全可靠,性能强大,功能齐全,全平台支持,开源率高,部署运维简单,二次开发友好,方便与第方系统对接或者嵌入现有系统中。 详细情况请参考在线文档。 主要包括一下项目: 野火IM Vue Electron Demo,演示如何将野火IM的能力集成到Vue Electron项目。 前置说明 本项目所使用的是需要付费的,价格请参考费用详情 支持试用,具体请看试用说明 本项目默认只能连接到官方服务,购买或申请试用之后,替换,即可连到自行部署的服务 分支说明 :基于开发,是未来的开发重心 :基于开发,进入维护模式,不再开发新功能,鉴于已经终止支持且不再维护,建议客户升级到版本 环境依赖 mac系统 最新版本的Xcode nodejs v18.19.0 npm v10.2.3 python 2.7.x git npm install -g node-gyp@8.3.0 windows系统 nodejs v18.19.0 python 2.7.x git npm 6.14.15 npm install --global --vs2019 --production windows-build-tools 本步安装windows开发环境的安装内容较多,如果网络情况不好可能需要等较长时间,选择早上网络较好时安装是个好的选择 或参考手动安装 windows-build-tools进行安装 npm install -g node-gyp@8.3.0 linux系统 nodej...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值